JavaScript的RSA加密库
- 一、Rsa利用openssl生成公钥私钥
- 二、Cryptico
-
- 1.优点:
- 2.缺点:
- 3.安装:
- 4.Demo
- 5.参考链接:
- 三、Node-rsa
-
- 1.优点:
- 2.缺点:
- 3.安装:
- 4.Demo
- 5.参考
- 四、Crypto
- 1.优点:
- 2.缺点:
- 3.安装:免安装
- 4.Demo
-
- 4.1、nodejs支持的加密算法和哈希算法有哪些?
- 4.2、生产rsa公钥私钥(pkcs1的公钥publicKey长度为188)
- 4.3公钥加密,私钥解密;私钥加密,公钥解密;
- 4.4、当然,这里的公钥可以使用OpenSSL产生的,也可以用上一步产生的公钥私钥
- 5.参考
- 五、Jsrsasign
-
- 1.优点:
- 2.缺点:
- 3.安装:
- 4.Demo
-
- 4.1支持openssl及nodersa生产的标准格式的rsa密钥
- 4.2支持jsrsasign生产的密钥
- 4.3 支持crypto生产的密钥,并且加密方式和crypto的解密方式通用
- 5.参考
- 六、JSencrypt
-
- 1.优点:
- 2.缺点:
- 3.安装:
- 4.Demo
-
- 4.1nodejs端node-jsencrypt
- 4.2web端jsencrypt
- 5.参考
一、Rsa利用openssl生成公钥私钥
生成公钥:
1 | openssl genrsa -out rsa_private_key.pem 1024 |
生成私钥:
1 | openssl rsa -in rsa_private_key.pem -pubout -out rsa_public_key.pem |
二、Cryptico
1.优点:
rsa密钥生产、rsa加密、rsa解密,使用方式简单,前端和nodejs服务端都可以使用
2.缺点:
生产的密钥不是标准位数的rsa密钥;不支持标准位数的rsa密钥pem格式;七年前已经停止更新;
3.安装:
1.nodejs端:
npm i cryptico .
2web端
直接require加密代码
4.Demo
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | const cryptico = require('cryptico') // The passphrase used to repeatably generate this RSA key. var PassPhrase = "The Moon is a Harsh Mistress."; // The length of the RSA key, in bits. var Bits = 1024; var date1 = new Date().getTime() var MattsRSAkey = cryptico.generateRSAKey(PassPhrase, Bits); console.log(new Date().getTime()-date1) // // Matt's public key string can then be generated like this: var MattsPublicKeyString = cryptico.publicKeyString(MattsRSAkey); // var publicKey =keys.exportKey('pkcs8-public-pem') // var privateKey =keys.exportKey('pkcs1-private-pem') console.log(MattsPublicKeyString.length) //172,1024Bits对应的密钥长度为172 // 需要加密的信息PlainText var PlainText = "Matt, I need you to help me with my Starcraft strategy."; // Encrypting a message 加密 var EncryptionResult = cryptico.encrypt(PlainText, MattsPublicKeyString); // Decrypting a message 解密 var DecryptionResult = cryptico.decrypt(EncryptionResult.cipher, MattsRSAkey); console.log(DecryptionResult.plaintext) |
5.参考链接:
- https://www.npmjs.com/package/cryptico
三、Node-rsa
1.优点:
可以生产不同填充方式的rsa公钥和私钥,并且生产密钥可以在nodejs中的crypto加密解密使用;
2.缺点:
crypto加密可以使用node-rsa解密,但是node-rsa加密的不可以使用crypto模块解密(更换解密私钥的填充方式应该可以);生产密钥时间较长;
3.安装:
npm i node-rsa。
4.Demo
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | const NodeRSA = require("node-rsa"); var key = new NodeRSA(); //生成2048位的密钥 key.generateKeyPair(1024) var publicDer = key.exportKey("pkcs8-public-pem"); //公钥pkcs1对应公钥长度为188,pkcs8对应公钥长度为216 console.log(new Date().getTime()-date1) var privateDer = key.exportKey("pkcs1-private-pem");//私钥 console.log("公钥:", publicDer); console.log("私钥:", privateDer); const text = "Hello RSA!"; //导入私钥 //key.importKey(privateDer, "pkcs1-private-pem"); // 加签并加密 //var key = new NodeRSA() const sign = key.sign(text, "base64", "utf8"); console.log("A 私钥加签:", sign); const encrypted = key.encrypt(sign, "base64"); console.log("B 公钥加密:", encrypted); // 解密并验签 //var key = new NodeRSA() //key.setOptions({ encryptionScheme: 'pkcs1' }) const decrypted = key.decrypt(encrypted, "utf8"); console.log("C 私钥解密:", decrypted); const verify = key.verify(text, decrypted, "utf8", "base64"); console.log("D 公钥验签:", verify); const crypto = require("crypto"); // 加密 const crypto_encrypted = crypto.publicEncrypt(publicDer, Buffer.from(text)).toString("base64"); console.log("E 公钥加密:", crypto_encrypted); // 解密 var crypto_decrypted = crypto.privateDecrypt({<!-- --> key: privateDer, padding: crypto.constants.RSA_PKCS1_OAEP_PADDING }, Buffer.from(crypto_encrypted, "base64") ).toString("utf8"); console.log("F 私钥解密:", crypto_decrypted); const decrypted2 = key.decrypt(crypto_encrypted, "utf8"); console.log("G 私钥解密:", decrypted2); |
5.参考
- 5.1Node-RSA 生成公私钥对、私钥签名、公钥验签https://blog.csdn.net/tony_328427685/article/details/90403374
- 5.2https://www.npmjs.com/package/node-rsa
四、Crypto
crypto模块的目的是为了提供通用的加密和哈希算法。用纯JavaScript代码实现这些功能不是不可能,但速度会非常慢。Nodejs用C/C++实现这些算法后,通过cypto这个模块暴露为JavaScript接口,这样用起来方便,运行速度也快。
NodeJS的模块crypto,有以下4个与公钥加密相关的类。
- ① Cipher: 用于加密数据;
- ② Decipher: 用于解密数据;
- ③ Sign: 用于生成签名;
- ④ Verify: 用于验证签名;
1.优点:
生产密钥速度快,耗时是cryptcio和node-rsa的十分之一;nodejs内置模块;
2.缺点:
公钥不支持pcks8,前端和其对应的库较少;只可以在nodejs端使用(从后面的例子可以看到,更改密钥的填充方式,可以和前端部分rsa加密方式通用,估计这也就是为何node加密模块crypto用的少的原因)
3.安装:免安装
4.Demo
4.1、nodejs支持的加密算法和哈希算法有哪些?
1 2 3 4 5 6 7 8 9 10 | const crypto = require('crypto') // 查看含有哪些加密算法 var Ciphers=crypto.getCiphers() console.log(Ciphers) // (171) ['aes-128-cbc', 'aes-128-ccm', 'aes-128-cfb',...]可以看到共有171种加密算法(没有rsa) // 查看含有哪些哈希算法 var Hashes = crypto.getHashes() console.log(Hashes); // (59) ['RSA-MD4', 'RSA-MD5', 'RSA-MDC2', 'RSA-RIPEMD160', 'RSA-SHA1',...]可以看到共有59种哈希算法 |
4.2、生产rsa公钥私钥(pkcs1的公钥publicKey长度为188)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | const {<!-- --> generateKeyPairSync } = require('crypto'); const {<!-- --> publicKey, privateKey } = generateKeyPairSync('rsa', {<!-- --> modulusLength: 1024, publicKeyEncoding: {<!-- --> type: 'pkcs1', format: 'pem' }, privateKeyEncoding: {<!-- --> type: 'pkcs8', format: 'pem', cipher: 'aes-256-cbc', passphrase: 'top secret' } }); |
4.3公钥加密,私钥解密;私钥加密,公钥解密;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | const crypto = require('crypto'); const fs = require('fs'); const path = require('path'); const root = __dirname; const publicKey = fs.readFileSync(path.join(root, '../rsa_public_key.pem')).toString('ascii'); const privateKey = fs.readFileSync(path.join(root, '../rsa_private_key.pem')).toString('ascii'); const data = 'data to crypt'; // 公钥加密 const encryptData = crypto.publicEncrypt(publicKey, Buffer.from(data)).toString('base64'); console.log('encode', encryptData); // 私钥解密 const decryptData = crypto.privateDecrypt(privateKey, Buffer.from(encryptData.toString('base64'), 'base64')); console.log('decode', decryptData.toString()); // 私钥加密 const encryptData2 = crypto.privateEncrypt(privateKey, Buffer.from(data)).toString('base64'); console.log('encode', encryptData2); // 公钥解密 const decryptData2 = crypto.publicDecrypt(publicKey, Buffer.from(encryptData2.toString('base64'), 'base64')); console.log('decode', decryptData2.toString()); |
4.4、当然,这里的公钥可以使用OpenSSL产生的,也可以用上一步产生的公钥私钥
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | const crypto = require('crypto'); const {<!-- --> publicKey, privateKey } = crypto.generateKeyPairSync('rsa', {<!-- --> modulusLength: 1024, publicKeyEncoding: {<!-- --> type: 'pkcs1', format: 'pem' }, privateKeyEncoding: {<!-- --> type: 'pkcs1', format: 'pem', // cipher: 'aes-256-cbc', // passphrase: 'top secret' } }); const data = 'data to crypt'; // 公钥加密 const encryptData = crypto.publicEncrypt(publicKey, Buffer.from(data)).toString('base64'); console.log('encode', encryptData); // 私钥解密 const decryptData = crypto.privateDecrypt(privateKey, Buffer.from(encryptData.toString('base64'), 'base64')); console.log('decode', decryptData.toString()); |
5.参考
- 5.1【node.js_crypto 模块】https://www.jianshu.com/p/c5c8c19bc80a
- 5.2【Node.js v14.14.0 文档】http://nodejs.cn/api/crypto.html#crypto_crypto_constants_1
- 5.3【crypto】https://www.liaoxuefeng.com/wiki/1022910821149312/1023025778520640
五、Jsrsasign
1.优点:
加密解密方法比较全,nodejs和web端均可使用,支持nodejs的crypto模块生产的pkcs1格式的公钥;
2.缺点:
生成rsa密钥耗时较长,加密解密过程耗时较长;
3.安装:
- nodejs:
npm i jsrsasign ,npm i jsrsasign-util
- web端:
引入jsrsasign-all-min.js(https://github.com/kjur/jsrsasign)
4.Demo
4.1支持openssl及nodersa生产的标准格式的rsa密钥
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | const fs = require('fs') var rs = require('jsrsasign'); const path = require('path'); const root = __dirname; const publicKey = fs.readFileSync(path.join(root, './rsa_public_key.pem')).toString('ascii'); const privateKey = fs.readFileSync(path.join(root, './rsa_private_key.pem')).toString('ascii'); // 加密 // 读取解析pem格式的秘钥, 生成秘钥实例 (RSAKey) var date1 = new Date().getTime() var pub = rs.KEYUTIL.getKey(publicKey); var enc = rs.KJUR.crypto.Cipher.encrypt('src', pub); console.log(enc); //38b5835801da14a7efb1d15ee7c92d87e12b5535de29335401a7df4fc190ca251beeff6fa5f8bd3be47cefea6533dcd7bdc1120dcad91504b5b428d5c5ac20446c6849511081b96dbb67668dd81f42b3c46e5a68b52c85a26feee49d4f62b3f8f39e6feaaffc91a8d637a697d63b2e68806ce8919c1133c44fbf2d99c91c6650 console.log(rs.hextob64(enc)); //OLWDWAHaFKfvsdFe58kth+ErVTXeKTNUAaffT8GQyiUb7v9vpfi9O+R87+plM9zXvcESDcrZFQS1tCjVxawgRGxoSVEQgbltu2dmjdgfQrPEblpotSyFom/u5J1PYrP4855v6q/8kajWN6aX1jsuaIBs6JGcETPET78tmckcZlA= // 解密 var prv = rs.KEYUTIL.getKey(privateKey); var dec = rs.KJUR.crypto.Cipher.decrypt(enc, prv); console.log(new Date().getTime() - date1) console.log("jsrsasign decrypt: " + dec); //jsrsasign decrypt:src |
4.2支持jsrsasign生产的密钥
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | var rs = require('jsrsasign'); const path = require('path'); const root = __dirname; // 生产密钥对 var date1 = new Date().getTime() var rsaKeypair = rs.KEYUTIL.generateKeypair("RSA", 512); console.log(new Date().getTime() - date1) //314 // 密钥对象获取pem格式的密钥 var pub = rs.KEYUTIL.getPEM(rsaKeypair.pubKeyObj); var prv = rs.KEYUTIL.getPEM(rsaKeypair.prvKeyObj,'PKCS8PRV'); console.log(pub); // -----BEGIN PUBLIC KEY----- // MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAMBAvyyQ7ZvG+vKmAvb3zrA816O5i0tg // FWKaveQbuZ/xwFdHRFB/f27pEKo7jbUWBMDDIBGNu7QZ/uG6birsJ0UCAwEAAQ== // -----END PUBLIC KEY----- console.log(prv); // -----BEGIN PRIVATE KEY----- // MIIBVgIBADANBgkqhkiG9w0BAQEFAASCAUAwggE8AgEAAkEAt1huGEUWoa1z2Ruw // DRdJX+EWfZI64QNJ8UUVwSyEou7PB0fwTdczr5UbxjH2zRsNQo5wPHAOTKvr2GGh // DH1nFwIDAQABAkBBjwM+9mVTRnxoI3heFfeMqyWpnQIkt1JXTUasHkkHIRVaZMFx // b5rnSRSpj/QzWHUAT9CaffZqRoqM9EWig2wRAiEA8WRJZpvac7CK0OPvE8sD2THZ // D49fzyvNf9dRZUI9IAsCIQDCcN9XASIhFOkrrVC9ySr4+m+VTlJfVKO6P95/7V9A // pQIhALrPH7bW2mI5t9Qc8YJh1GKbnx3ZmQ3dGjXbTlSMxH0tAiEAlvMFkAfjNQeE // 1VGhwxSvdccGZUT+kd+lk+wNkgb30bkCIQDwS8xr2P4bm3vkVBCDvrttjTKPIjtG // apnvPZ2yh1OIqQ== // -----END PRIVATE KEY----- // 加密 // 读取解析pem格式的秘钥, 生成秘钥实例 (RSAKey) var date1 = new Date().getTime() // 公钥加密 var enc = rs.KJUR.crypto.Cipher.encrypt('src', rsaKeypair.pubKeyObj); console.log(enc); //5ee71af15aa5fcc652d8ccaab81a1883e49232b4726c31a538ed98347de972c3f86cb736fa4622f14c7bb872b33ebc0bb57657dcdddc22992c27d1c71600a8f4 console.log(rs.hextob64(enc)); // Xuca8Vql/MZS2MyquBoYg+SSMrRybDGlOO2YNH3pcsP4bLc2+kYi8Ux7uHKzPrwLtXZX3N3cIpksJ9HHFgCo9A== // 私钥解密 // var enc=rs.hextob64(enc) var dec = rs.KJUR.crypto.Cipher.decrypt(enc, rsaKeypair.prvKeyObj); console.log("jsrsasign decrypt: " + dec); // jsrsasign decrypt: src |
4.3 支持crypto生产的密钥,并且加密方式和crypto的解密方式通用
- (需要指定生成密钥对的填充方式,及解密时私钥的填充方式为pkcs1)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | var crypto = require('crypto'); var rs = require('jsrsasign'); date1 = new Date().getTime() const {<!-- --> publicKey, privateKey } = crypto.generateKeyPairSync('rsa', {<!-- --> modulusLength: 512, publicKeyEncoding: {<!-- --> type: 'spki', format: 'pem' }, privateKeyEncoding: {<!-- --> type: 'pkcs1', format: 'pem', // cipher: 'aes-256-cbc', // passphrase: 'top secret' } }); console.log(new Date().getTime() - date1) var date1 = new Date().getTime() var pub = rs.KEYUTIL.getKey(publicKey); var enc = rs.KJUR.crypto.Cipher.encrypt('src', pub); // console.log(enc); console.log(rs.hextob64(enc)); //DZzrNuD730u+5AsRcikeSMoU1yCscUutQlqXJ5WU/2iUSuCsJxyOJOJjVbI87r7EGL7EjeS278PziN9pZ7TWOg== // 使用jsrsasign解密 var prv = rs.KEYUTIL.getKey(privateKey); var dec = rs.KJUR.crypto.Cipher.decrypt(enc, prv); console.log(new Date().getTime() - date1) console.log("jsrsasign decrypt: " + dec); //jsrsasign decrypt:src // 使用crypto模块解密 var enc = rs.hextob64(enc) const dec2 = crypto.privateDecrypt({<!-- --> key: privateKey, padding: crypto.constants.RSA_PKCS1_PADDING }, Buffer.from(enc.toString('base64'), 'base64')).toString(); console.log("jsrsasign decrypt: " + dec2); //jsrsasign decrypt:src |
5.参考
- 5.1https://kjur.github.io/jsrsasign/api/index.html
- 5.2前端 rsa加密参数的实现(加密库:jsrsasign)
https://blog.csdn.net/qq_38652871/article/details/86234957 - 5.3https://www.npmjs.com/package/jsrsasign
- 5.4jsrsasign使用笔记(加密,解密,签名,验签)https://www.jianshu.com/p/b32fc387d8ad
六、JSencrypt
1.优点:
支持rsa加密解密,支持标准的rsa密钥;比jsrsasign加密速度稍微快几毫秒;加密内容可以用nodejs标准的加密模块crypto解密
2.缺点:
不能生产rsa密钥;
3.安装:
- Web端
html文件引入jsencrypt.min.js(https://github.com/travist/jsencrypt)
- Nodejs端:
npm i node-jsencrypto
4.Demo
4.1nodejs端node-jsencrypt
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | ar crypto = require('crypto'); date1 = new Date().getTime() var {<!-- --> publicKey, privateKey } = crypto.generateKeyPairSync('rsa', {<!-- --> modulusLength: 512, publicKeyEncoding: {<!-- --> type: 'spki', format: 'pem' }, privateKeyEncoding: {<!-- --> type: 'pkcs1', format: 'pem', // cipher: 'aes-256-cbc', // passphrase: 'top secret' } }); console.log(new Date().getTime() - date1) // 引入加密模块 JSEncrypt = require('node-jsencrypt') // 加密 date1 = new Date().getTime() const jsEncrypt = new JSEncrypt() jsEncrypt.setPublicKey(publicKey) enc = jsEncrypt.encrypt('src') console.log(new Date().getTime() - date1) //解密 date1 = new Date().getTime() var decrypt = new JSEncrypt(); decrypt.setPrivateKey(privateKey); var uncrypted = decrypt.decrypt(enc); console.log(new Date().getTime() - date1) // 使用crypto模块解密 const dec3 = crypto.privateDecrypt({<!-- --> key: privateKey, padding: crypto.constants.RSA_PKCS1_PADDING }, Buffer.from(enc.toString('base64'), 'base64')).toString(); console.log("jsrsasign decrypt: " + dec2); |
4.2web端jsencrypt
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 | <!doctype html> <html> <head> <title>JavaScript RSA Encryption</title> <script src="//i2.wp.com/cdn.staticfile.org/jquery/1.10.2/jquery.min.js"></script> <script src="//i2.wp.com/passport.cnblogs.com/scripts/jsencrypt.min.js"></script> <script src="./jsrsasign-all-min.js"></script> <script type="text/javascript"> // Call this code when the page is done loading. $(function () {<!-- --> // Run a quick encryption/decryption when they click. $('#testme').click(function () {<!-- --> // Encrypt with the public key... var date1 = new Date().getTime() var encrypt = new JSEncrypt(); encrypt.setPublicKey($('#pubkey').val()); var encrypted = encrypt.encrypt('123'); console.log(new Date().getTime() - date1) // jsrsasign加密 var date1 = new Date().getTime() var pub = new KEYUTIL.getKey($('#pubkey').val()); var enc = KJUR.crypto.Cipher.encrypt('src', pub); //console.log(rs.hextob64(enc)); console.log(new Date().getTime() - date1) // Decrypt with the private key... var decrypt = new JSEncrypt(); decrypt.setPrivateKey($('#privkey').val()); var uncrypted = decrypt.decrypt(encrypted); // Now a simple check to see if the round-trip worked. if (uncrypted == $('#input').val()) {<!-- --> alert('It works!!!'); } else {<!-- --> alert('Something went wrong....'); } }); }); </script> </head> <body> <label for="privkey">Private Key</label><br /> <textarea id="privkey" rows="15" cols="65">-----BEGIN RSA PRIVATE KEY----- MIIBOgIBAAJBAL1o9pLm8ErFu4rzJIizJY+4W3aTZlrEv0WhRKxVXkCt5Lwm2+aE /YpwtEkIdCpwr//PTLN7y554MhR7tFNu748CAwEAAQJABOkKs2Y/RoD3yrNg+BZE 3AP4gwtxNNsy5jg3EoyoA98yxQQAe3/093Qll19zQVCwHqM9Ijy7EmK6k8NcE5TF oQIhAOrEV8k3LiYCxnn2ogbRkgRQH1xUju01pvX5fpRBpy4RAiEAzopzsBEP9Bi/ 6yNh9n+aMqTI1ceqhj71jbK62gN9I58CIQCAYB9U43yzwl7AALK3IdBD1YBgn8iM RANpjCXAcmo10QIgHbczv9AkoHTzH8x+aq2fLMwijQdmFFx4jcN6OKWp2ncCIFZX fwHIo+ZpL/avDe1P5I8FY9KlKnTXDCM9GnI9Unwb -----END RSA PRIVATE KEY-----</textarea><br /> <label for="pubkey">Public Key</label><br /> <textarea id="pubkey" rows="15" cols="65">-----BEGIN PUBLIC KEY----- MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAL1o9pLm8ErFu4rzJIizJY+4W3aTZlrE v0WhRKxVXkCt5Lwm2+aE/YpwtEkIdCpwr//PTLN7y554MhR7tFNu748CAwEAAQ== -----END PUBLIC KEY-----</textarea><br /> <label for="input">Text to encrypt:</label><br /> <textarea id="input" name="input" type="text" rows=4 cols=70>This is a test!</textarea><br /> <input id="testme" type="button" value="Test Me!!!" /><br /> </body> </html> |
5.参考
- 5.1https://www.npmjs.com/package/jsencrypt?activeTab=versions
- 5.2在VUE中使用RSA加密解密加签解签https://juejin.cn/post/6844903749626888200