<!doctype html> <html lang="zh"> <head> <meta charset="utf-8"> <title>使用jsencrypt.js实现RSA加密和解密</title> </head> <body> <script type="text/javascript" src="./jsencrypt.min.js"></script> <script type="text/javascript"> JSEncrypt.prototype.hexToB64 = function (h) { var b64map = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; var i; var c; var ret = ''; for (i = 0; i + 3 <= h.length; i += 3) { c = parseInt(h.substring(i, i + 3), 16); ret += b64map.charAt(c >> 6) + b64map.charAt(c & 63); } if (i + 1 == h.length) { c = parseInt(h.substring(i, i + 1), 16); ret += b64map.charAt(c << 2); } else if (i + 2 == h.length) { c = parseInt(h.substring(i, i + 2), 16); ret += b64map.charAt(c >> 2) + b64map.charAt((c & 3) << 4); } while ((ret.length & 3) > 0) { ret += '='; } return ret; }; JSEncrypt.prototype.b64ToHex = function (s) { var b64map = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; var ret = ''; var i; var k = 0; var slop = 0; let intToChar = function (n) { return '0123456789abcdefghijklmnopqrstuvwxyz'.charAt(n); } for (i = 0; i < s.length; ++i) { if (s.charAt(i) == '=') { break; } var v = b64map.indexOf(s.charAt(i)); if (v < 0) { continue; } if (k == 0) { ret += intToChar(v >> 2); slop = v & 3; k = 1; } else if (k == 1) { ret += intToChar((slop << 2) | (v >> 4)); slop = v & 0xf; k = 2; } else if (k == 2) { ret += intToChar(slop); ret += intToChar(v >> 2); slop = v & 3; k = 3; } else { ret += intToChar((slop << 2) | (v >> 4)); ret += intToChar(v & 0xf); k = 0; } } if (k == 1) { ret += intToChar(slop << 2); } return ret; } JSEncrypt.prototype.encryptUnicodeLong = function (string) { var k = this.getKey(); var maxLength = ((k.n.bitLength() + 7) >> 3) - 11; // 明文允许的最大长度 try { var subStr = ''; var encryptedString = ''; var subStart = 0; var subEnd = 0; var bitLen = 0; var tmpPoint = 0; for (var i = 0, len = string.length; i < len; i++) { var charCode = string.charCodeAt(i); if (charCode <= 0x007f) { // 单字节 bitLen += 1; } else if (charCode <= 0x07ff) { // 双字节 bitLen += 2; } else if (charCode <= 0xffff) { // 三字节 bitLen += 3; } else { bitLen += 4; } if (bitLen > maxLength) { subStr = string.substring(subStart, subEnd) encryptedString += k.encrypt(subStr); subStart = subEnd; bitLen = bitLen - tmpPoint; } else { subEnd = i; tmpPoint = bitLen; } } subStr = string.substring(subStart, len) encryptedString += k.encrypt(subStr); return this.hexToB64(encryptedString); } catch (ex) { return false; } }; JSEncrypt.prototype.decryptUnicodeLong = function (string) { var k = this.getKey(); var maxLength = ((k.n.bitLength() + 7) >> 3) * 2; try { var hexString = this.b64ToHex(string); var decryptedString = ''; var rexStr = '.{1,' + maxLength + '}'; var rex = new RegExp(rexStr, 'g'); var subStrArray = hexString.match(rex); if (subStrArray) { subStrArray.forEach(function (entry) { decryptedString += k.decrypt(entry); }); return decryptedString; } } catch (ex) { return false; } }; //========== 公钥(用于加密) ==========// let publicKey = `-----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzjGQT86U567mS2j3dzuf Q6sDJJDGfnO9J8ESaiwvMChZ30zD/USypRlKSnX1d+bqTLFMoNEOK/bQmqZiiSk5 Fzek2IA78n4NsvorKfsc5Gje2RQGqG5kKMt1TfLg2cF8dOZ+8Q6FoJ6EB3Dd1KPU f0duLcEXs+Am70CVeBs7aGYVUY2dtVlAVSK1mlUmYWNxRlk5V5oSdUaHN9vAzgiJ Y844bbpP3XOCgT/Fc0sN+AVoGIrgAyGt1qWHTiXIbJQ0ocyFoaT/CCdP7ueqesJp LCxupSqoS0SdNh3JpbLz4ZnHGug7uP1mqwkGQACAJfYE6X7fNRO+BIaVJRGCMBcm jwIDAQAB -----END PUBLIC KEY-----`; //========== 私钥(用于解密) ==========// let privateKey = `-----BEGIN PRIVATE KEY----- MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDOMZBPzpTnruZL aPd3O59DqwMkkMZ+c70nwRJqLC8wKFnfTMP9RLKlGUpKdfV35upMsUyg0Q4r9tCa pmKJKTkXN6TYgDvyfg2y+isp+xzkaN7ZFAaobmQoy3VN8uDZwXx05n7xDoWgnoQH cN3Uo9R/R24twRez4CbvQJV4GztoZhVRjZ21WUBVIrWaVSZhY3FGWTlXmhJ1Roc3 28DOCIljzjhtuk/dc4KBP8VzSw34BWgYiuADIa3WpYdOJchslDShzIWhpP8IJ0/u 56p6wmksLG6lKqhLRJ02HcmlsvPhmcca6Du4/WarCQZAAIAl9gTpft81E74EhpUl EYIwFyaPAgMBAAECggEAR5X7lUmSdvFI8QtrRxEDFTotKCe/Ui2akU+9tfDLHTwV H6qGLMsJ/rnOChXz+AHKfH/dq8OI2Qiimd6EPTx7nqzp5WR365OJ7AZgr/2HpWEn ZVRHj3hr+6HPgxV8rP042Vkg3038ZKxECFVOHsIWR24kOWxdb0y2F8BjZESIFpEi IRN9Xb77C2yCOUX/yoyMgjkKM/Z+cThM5wQ0nR1wZHDl4CE91UxhdDYBQz5uzoDV qZerHT2Kmy5fUBRGxJdSujN7qyGgf9FarNkfBYAII97StIS512ZuLCwzmEddXp4i gNlsla0eqCxQvAqOoGm8Fp/N0PCyfR7fJexck3L1kQKBgQD+SvKklvp055BpVB2n IsJHpPd43zXxxX+k8eQSKhGIy+6eO53xapQDZiB/4OVfGnY+xPF4z8nLxCWd9C3S K6X/OzQTC7c4Y4a9L/P2NKissuqsxzMf2jGPCUBIGKcBZ9eizOGNbdhJ/HvXQY7r CxyRaeOqU6om1DKPHBkFsXPfGQKBgQDPk/Kxugnzgv+4b2TWwxY7Ot2LcWszPkEp RsbBLdCS08h9GYOlC1kGMXZFv8QGO3R+e4mZMOIVhwSadrhfGwvlqDumDaORF+MH ZZAe6ARRX71KKTjGZqcX0nImLI5o1s/YMK8BkCE6ArYVPFspk68Voun4wbNcO/U9 aoNsK9Vv5wKBgQDDW3jFkWegYDXFdWXCfSWcPNQR/AlJUF0brul0OvV1jpYm4c4Z JbPIWLEnDPOp+H5XAp4wHhH9hRcRHgIFsJq6VhVPfHSp0Ww1850MzK+43UsEqZRR KCNiq8zClo3Wupwi6httt7GuRVYurKLLV6H+5MaOl+/kHKkq4H8orIdEIQKBgGng uOXWUsUWiID2sKSqlWhYujAqBdf5ZRs8spxOVhjOVXEZ1oAUra/vArjI+5+CLAVn 1eOBf5AjckGnVJuOHB9kFCi6xDd5y582OrDI/4rSHqb5J7BrI8eO3BKEn47yIsnO 6zUM4yXHxEBIrOckISYUFut/QZFGM+zDq409Pnz5AoGAXqkbybLPznaumBngpY25 BOnBxF02hWxiWlREsXbqfpa6WU50BLXFxknP+91QYwOHafZpdjm7LL8GJ7H5vmyK CLhxY5fZejlze0eMa8A07JWBH9F4cBamI9NbmatfmhlvLjPaRcNaoyuk1W8LuL9Z im+u/8E9Zm1atbpr7lP33YQ= -----END PRIVATE KEY-----`; // 要加密的消息 let message = '北国风光,千里冰封,万里雪飘。望长城内外,惟余莽莽;大河上下,顿失滔滔。山舞银蛇,原驰蜡象,欲与天公试比高。须晴日,看红装素裹,分外妖娆。江山如此多娇,引无数英雄竞折腰。惜秦皇汉武,略输文采;唐宗宋祖,稍逊风骚。一代天骄,成吉思汗,只识弯弓射大雕。俱往矣,数风流人物,还看今朝。'; let jse = new JSEncrypt(); let startTime = 0; let endTime = 0; //========== 使用公钥加密 ==========// jse.setKey(publicKey); startTime = new Date().getTime(); let ciphertext = jse.encryptUnicodeLong(message); // 注:相同消息每次加密的结果都是不同的 endTime = new Date().getTime(); console.log('消息密文:%s', ciphertext); // 消息密文:mZ/Y7DBPR5p+oNW+aYs0nj0eX+KwDJquCDOOoBjQABqAA89BrEtbCXpSOeFf2vtcEmnxsZAYa…… console.log('加密用时:%d毫秒', endTime - startTime); // 加密用时:8毫秒 //========== 使用私钥解密 ==========// jse.setKey(privateKey); startTime = new Date().getTime(); let plaintext = jse.decryptUnicodeLong(ciphertext); endTime = new Date().getTime(); console.log('消息明文:%s', plaintext); // 消息明文:北国风光,千里冰封,万里雪飘。望长城内外,惟余莽莽;大河上下,顿失滔滔。山…… console.log('解密用时:%d毫秒', endTime - startTime); // 解密用时:66毫秒 //========== 总结 ==========// // 1、超长消息的加解密会非常耗时(尤其是解密),所以强烈建议使用Worker创建子线程来执行加解密运算,避免页面发生阻塞。 </script> </body> </html>
//========== 由主线程执行的代码 ==========// if (typeof window !== 'undefined') { // 获取当前JavaScript脚本URL,并创建子线程执行当前JavaScript脚本里的子线程代码 let worker = new Worker(document.scripts[document.scripts.length - 1].src); worker.onerror = function (event) { console.log('子线程出错辣~~~', event); }; let task = 2; // 任务数量(只有加密和解密两个任务,完成一个就自减一) // 接收子线程消息 worker.onmessage = function (event) { let data = event.data; // 收到子线程消息:加密成功 if (data.action === 'encrypt') { console.log('消息密文:%s', data.ciphertext); task--; } // 收到子线程消息:解密成功 if (data.action === 'decrypt') { console.log('消息明文:%s', data.plaintext); task--; } // 任务已全部完成,可以销毁子线程 if (task === 0) { worker.terminate(); } }; // 向子线程发送消息(加密) let plaintext = '北国风光,千里冰封,万里雪飘。望长城内外,惟余莽莽;大河上下,顿失滔滔。山舞银蛇,原驰蜡象,欲与天公试比高。须晴日,看红装素裹,分外妖娆。江山如此多娇,引无数英雄竞折腰。惜秦皇汉武,略输文采;唐宗宋祖,稍逊风骚。一代天骄,成吉思汗,只识弯弓射大雕。俱往矣,数风流人物,还看今朝。'; worker.postMessage({action: 'encrypt', plaintext: plaintext}); // 向子线程发送消息(解密) let ciphertext = 'M01IMhuL/GRZpAlf9sUaiJm8oWIpJNc4pbzKLShuw3HSm43dRZ4/bkKuES2mgARCuEMktinUqcCJv6seGNrehiwV+CwXDnL0+PjKvnFT3Y2/wc64D6Nq5Xi9e9HfPmQUMBFMWhXBnUjycwmkR92Bnr55+qCHIgJPi++xQtLponX6Z0QD9PlOPNxtKSzo+tW7tr1Nn3ADmp6QHzbiSL1alNjwzUfn/DwhjivaAVBNXg6IYUPa/HCsNwWfRzJCULND8pa7J2XFLGyfMTL6UJCAL1p5kCIG2v3ml9RJI8LfzupvyalNGNOp9ZNo7kRk2zKAqa17lk7GKRrccb/FAxUaKgeo8QquOBw7972lsHLLdmRlPzRPU3O0LdJoY05TOL1ytBD5s5Og7UsIpkBORqAGZICcs3BqvLEFOB7uSSESPvi8lpnHXLPzJw4JZ57/ye/w2V6qWuFtZU6+xspOjEVtCXTXc4WPI3n8ExAUy7+DmzDyFPRzbM6oj59p4I6kSmg8QbBjy03XTEG393crO6ghZZaZPDfm2wgPkZTyCyz5Fjc033nrssLZ6Jir0paj9RTCB3AM2kNW+rEQ2bbJ7YwRianl9+9qipMKTncoSNEjs+HYMivcLSDTcYrZQFBz0V/GJ1A5lopZCen2OMR9EQHzQXEjvNazqdkUpBREWTIfiBo='; worker.postMessage({action: 'decrypt', ciphertext: ciphertext}); } //========== 由子线程执行的代码 ==========// if (typeof window === 'undefined') { var window = {}; // JSEncrypt库会用到window对象,故这里创建一个,需要说明的是这个window对象只是一个普通的对象, // 并不是浏览器内置的window对象,所以它没有浏览器内置window对象的属性和方法。 importScripts('jsencrypt.min.js'); // 引入JSEncrypt库,在页面通过<script>引入是无效的,因为那是主线程的,而这里是子线程 window.JSEncrypt.prototype.hexToB64 = function (h) { var b64map = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; var i; var c; var ret = ''; for (i = 0; i + 3 <= h.length; i += 3) { c = parseInt(h.substring(i, i + 3), 16); ret += b64map.charAt(c >> 6) + b64map.charAt(c & 63); } if (i + 1 == h.length) { c = parseInt(h.substring(i, i + 1), 16); ret += b64map.charAt(c << 2); } else if (i + 2 == h.length) { c = parseInt(h.substring(i, i + 2), 16); ret += b64map.charAt(c >> 2) + b64map.charAt((c & 3) << 4); } while ((ret.length & 3) > 0) { ret += '='; } return ret; }; window.JSEncrypt.prototype.b64ToHex = function (s) { var b64map = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; var ret = ''; var i; var k = 0; var slop = 0; let intToChar = function (n) { return '0123456789abcdefghijklmnopqrstuvwxyz'.charAt(n); } for (i = 0; i < s.length; ++i) { if (s.charAt(i) == '=') { break; } var v = b64map.indexOf(s.charAt(i)); if (v < 0) { continue; } if (k == 0) { ret += intToChar(v >> 2); slop = v & 3; k = 1; } else if (k == 1) { ret += intToChar((slop << 2) | (v >> 4)); slop = v & 0xf; k = 2; } else if (k == 2) { ret += intToChar(slop); ret += intToChar(v >> 2); slop = v & 3; k = 3; } else { ret += intToChar((slop << 2) | (v >> 4)); ret += intToChar(v & 0xf); k = 0; } } if (k == 1) { ret += intToChar(slop << 2); } return ret; } window.JSEncrypt.prototype.encryptUnicodeLong = function (string) { var k = this.getKey(); var maxLength = ((k.n.bitLength() + 7) >> 3) - 11; // 明文允许的最大长度 try { var subStr = ''; var encryptedString = ''; var subStart = 0; var subEnd = 0; var bitLen = 0; var tmpPoint = 0; for (var i = 0, len = string.length; i < len; i++) { var charCode = string.charCodeAt(i); if (charCode <= 0x007f) { // 单字节 bitLen += 1; } else if (charCode <= 0x07ff) { // 双字节 bitLen += 2; } else if (charCode <= 0xffff) { // 三字节 bitLen += 3; } else { bitLen += 4; } if (bitLen > maxLength) { subStr = string.substring(subStart, subEnd) encryptedString += k.encrypt(subStr); subStart = subEnd; bitLen = bitLen - tmpPoint; } else { subEnd = i; tmpPoint = bitLen; } } subStr = string.substring(subStart, len) encryptedString += k.encrypt(subStr); return this.hexToB64(encryptedString); } catch (ex) { return false; } }; window.JSEncrypt.prototype.decryptUnicodeLong = function (string) { var k = this.getKey(); var maxLength = ((k.n.bitLength() + 7) >> 3) * 2; try { var hexString = this.b64ToHex(string); var decryptedString = ''; var rexStr = '.{1,' + maxLength + '}'; var rex = new RegExp(rexStr, 'g'); var subStrArray = hexString.match(rex); if (subStrArray) { subStrArray.forEach(function (entry) { decryptedString += k.decrypt(entry); }); return decryptedString; } } catch (ex) { return false; } }; //========== 公钥(用于加密) ==========// let publicKey = `-----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzjGQT86U567mS2j3dzuf Q6sDJJDGfnO9J8ESaiwvMChZ30zD/USypRlKSnX1d+bqTLFMoNEOK/bQmqZiiSk5 Fzek2IA78n4NsvorKfsc5Gje2RQGqG5kKMt1TfLg2cF8dOZ+8Q6FoJ6EB3Dd1KPU f0duLcEXs+Am70CVeBs7aGYVUY2dtVlAVSK1mlUmYWNxRlk5V5oSdUaHN9vAzgiJ Y844bbpP3XOCgT/Fc0sN+AVoGIrgAyGt1qWHTiXIbJQ0ocyFoaT/CCdP7ueqesJp LCxupSqoS0SdNh3JpbLz4ZnHGug7uP1mqwkGQACAJfYE6X7fNRO+BIaVJRGCMBcm jwIDAQAB -----END PUBLIC KEY-----`; //========== 私钥(用于解密) ==========// let privateKey = `-----BEGIN PRIVATE KEY----- MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDOMZBPzpTnruZL aPd3O59DqwMkkMZ+c70nwRJqLC8wKFnfTMP9RLKlGUpKdfV35upMsUyg0Q4r9tCa pmKJKTkXN6TYgDvyfg2y+isp+xzkaN7ZFAaobmQoy3VN8uDZwXx05n7xDoWgnoQH cN3Uo9R/R24twRez4CbvQJV4GztoZhVRjZ21WUBVIrWaVSZhY3FGWTlXmhJ1Roc3 28DOCIljzjhtuk/dc4KBP8VzSw34BWgYiuADIa3WpYdOJchslDShzIWhpP8IJ0/u 56p6wmksLG6lKqhLRJ02HcmlsvPhmcca6Du4/WarCQZAAIAl9gTpft81E74EhpUl EYIwFyaPAgMBAAECggEAR5X7lUmSdvFI8QtrRxEDFTotKCe/Ui2akU+9tfDLHTwV H6qGLMsJ/rnOChXz+AHKfH/dq8OI2Qiimd6EPTx7nqzp5WR365OJ7AZgr/2HpWEn ZVRHj3hr+6HPgxV8rP042Vkg3038ZKxECFVOHsIWR24kOWxdb0y2F8BjZESIFpEi IRN9Xb77C2yCOUX/yoyMgjkKM/Z+cThM5wQ0nR1wZHDl4CE91UxhdDYBQz5uzoDV qZerHT2Kmy5fUBRGxJdSujN7qyGgf9FarNkfBYAII97StIS512ZuLCwzmEddXp4i gNlsla0eqCxQvAqOoGm8Fp/N0PCyfR7fJexck3L1kQKBgQD+SvKklvp055BpVB2n IsJHpPd43zXxxX+k8eQSKhGIy+6eO53xapQDZiB/4OVfGnY+xPF4z8nLxCWd9C3S K6X/OzQTC7c4Y4a9L/P2NKissuqsxzMf2jGPCUBIGKcBZ9eizOGNbdhJ/HvXQY7r CxyRaeOqU6om1DKPHBkFsXPfGQKBgQDPk/Kxugnzgv+4b2TWwxY7Ot2LcWszPkEp RsbBLdCS08h9GYOlC1kGMXZFv8QGO3R+e4mZMOIVhwSadrhfGwvlqDumDaORF+MH ZZAe6ARRX71KKTjGZqcX0nImLI5o1s/YMK8BkCE6ArYVPFspk68Voun4wbNcO/U9 aoNsK9Vv5wKBgQDDW3jFkWegYDXFdWXCfSWcPNQR/AlJUF0brul0OvV1jpYm4c4Z JbPIWLEnDPOp+H5XAp4wHhH9hRcRHgIFsJq6VhVPfHSp0Ww1850MzK+43UsEqZRR KCNiq8zClo3Wupwi6httt7GuRVYurKLLV6H+5MaOl+/kHKkq4H8orIdEIQKBgGng uOXWUsUWiID2sKSqlWhYujAqBdf5ZRs8spxOVhjOVXEZ1oAUra/vArjI+5+CLAVn 1eOBf5AjckGnVJuOHB9kFCi6xDd5y582OrDI/4rSHqb5J7BrI8eO3BKEn47yIsnO 6zUM4yXHxEBIrOckISYUFut/QZFGM+zDq409Pnz5AoGAXqkbybLPznaumBngpY25 BOnBxF02hWxiWlREsXbqfpa6WU50BLXFxknP+91QYwOHafZpdjm7LL8GJ7H5vmyK CLhxY5fZejlze0eMa8A07JWBH9F4cBamI9NbmatfmhlvLjPaRcNaoyuk1W8LuL9Z im+u/8E9Zm1atbpr7lP33YQ= -----END PRIVATE KEY-----`; let jse = new window.JSEncrypt(); // 创建JSEncrypt对象 // 接收主线程消息 self.onmessage = function (event) { let data = event.data; //========== 使用公钥加密 ==========// if (data.action === 'encrypt') { jse.setKey(publicKey); let ciphertext = jse.encryptUnicodeLong(data.plaintext); // 注:相同消息每次加密的结果都是不同的 self.postMessage({action: 'encrypt', ciphertext: ciphertext}); // 向主线程发送消息(返回密文) return; } //========== 使用私钥解密 ==========// if (data.action === 'decrypt') { jse.setKey(privateKey); let plaintext = jse.decryptUnicodeLong(data.ciphertext); self.postMessage({action: 'decrypt', plaintext: plaintext}); // 向主线程发送消息(返回明文) return; } }; }
Copyright © 2024 码农人生. All Rights Reserved