diff --git "a/docs/03.\350\276\205\345\212\251\346\237\245\350\257\242/04.\345\212\240\345\257\206\347\256\227\346\263\225/07.rsa.md" "b/docs/03.\350\276\205\345\212\251\346\237\245\350\257\242/04.\345\212\240\345\257\206\347\256\227\346\263\225/07.rsa.md" index d1bab39d..531aeeec 100644 --- "a/docs/03.\350\276\205\345\212\251\346\237\245\350\257\242/04.\345\212\240\345\257\206\347\256\227\346\263\225/07.rsa.md" +++ "b/docs/03.\350\276\205\345\212\251\346\237\245\350\257\242/04.\345\212\240\345\257\206\347\256\227\346\263\225/07.rsa.md" @@ -8,13 +8,6 @@ article: false ::: details 关于 RSA 非对称加密算法 RSA 加密算法是一种非对称加密算法,是由罗纳德·李维斯特(Ron Rivest)、阿迪·萨莫尔(Adi Shamir)和伦纳德·阿德曼(Leonard Adleman)在 1977 年一起提出的,RSA 就是他们三人姓氏开头字母拼在一起组成的。RSA 公开密钥密码体制的原理是:根据数论,寻求两个大素数比较简单,而将它们的乘积进行因式分解却极其困难,因此可以将乘积公开作为加密密钥。 - - ::: right RSA [维基百科](https://en.wikipedia.org/wiki/RSA_(cryptosystem)) ::: @@ -1602,6 +1595,27 @@ nHPppz1nsV+COkxXQV4= ``` ## 加密解密 + +::: details 关于加密解密 +在 RSA 加密解密操作中,我们需要注意的是填充方式(padding),最常见的分为以下四种: + +- `RSA_NO_PADDING`: 不使用填充方案; +- `RSA_PKCS1_PADDING`: 最常见,使用 PKCS#1 v1.5 填充方案; +- `RSA_PKCS1_OAEP_PADDING`: OAEP (Optimal asymmetric encryption padding),最优非对称加密填充,在 PKCS#1 v2 中标准化; +- `RSA_PKCS1_PSS_PADDING`: PSS (Probabilistic signature scheme),概率签名方案,在 PKCS#1 v2.1 中标准化。 + +--- + +::: right +【实用参考资料】 + +Padding 维基百科:[https://en.wikipedia.org/wiki/Padding_(cryptography)](https://en.wikipedia.org/wiki/Padding_(cryptography))
+RSA Padding 维基百科:[https://en.wikipedia.org/wiki/RSA_(cryptosystem)#Padding](https://en.wikipedia.org/wiki/RSA_(cryptosystem)#Padding)
+聊聊密码学中的Padding:[https://cloud.tencent.com/developer/article/1499219](https://cloud.tencent.com/developer/article/1499219)
+PSS (Probabilistic signature scheme):[https://en.wikipedia.org/wiki/Probabilistic_signature_scheme](https://en.wikipedia.org/wiki/Probabilistic_signature_scheme)
+OAEP (Optimal asymmetric encryption padding):[https://en.wikipedia.org/wiki/Optimal_asymmetric_encryption_padding](https://en.wikipedia.org/wiki/Optimal_asymmetric_encryption_padding) +::: + ### Python
@@ -1618,9 +1632,181 @@ nHPppz1nsV+COkxXQV4= + ```javascript + // ✅ Node.js 内置 crypto 模块,无需单独安装,官方文档:https://nodejs.org/docs/latest/api/crypto.html + + var crypto = require("crypto"); + + + function rsaEncrypt(data) { + var bufferData = Buffer.from(data); + var encrypted = crypto.publicEncrypt({ + key: publicKey, + // 支持 RSA_NO_PADDING、RSA_PKCS1_PADDING、RSA_PKCS1_OAEP_PADDING、RSA_PKCS1_PSS_PADDING + padding: crypto.constants.RSA_PKCS1_PADDING + }, bufferData); + return encrypted.toString("base64"); + } + + function rsaDecrypt(cipherText) { + var bufferData = Buffer.from(cipherText, "base64"); + var decrypted = crypto.privateDecrypt({ + key: privateKey, + // 支持 RSA_NO_PADDING、RSA_PKCS1_PADDING、RSA_PKCS1_OAEP_PADDING、RSA_PKCS1_PSS_PADDING + padding: crypto.constants.RSA_PKCS1_PADDING + }, bufferData); + return decrypted.toString(); + } + + // pkcs1 标准 pem 格式的公钥 + var publicKeyPkcs1Pem = ` + -----BEGIN RSA PUBLIC KEY----- + MIGJAoGBALLA/aUElSxqvPUnlC4A8UaNh6txyrjlLshW4/wUgWZIBBbvp7yVj4Oi + C5mbbbyvOqElQNhkaeV8EF2rZqy9m5whs+jIx1tUdyJPJXLyZCNr3Q8t4sQyek6q + 1+imN6KUEIHrLveuYq1Lvmw3lt52vRzvWwucYV0EHSbx3G0b6hErAgMBAAE= + -----END RSA PUBLIC KEY----- + ` + + // pkcs1 标准 pem 格式的私钥 + var privateKeyPkcs1Pem = ` + -----BEGIN RSA PRIVATE KEY----- + MIICYAIBAAKBgQCywP2lBJUsarz1J5QuAPFGjYerccq45S7IVuP8FIFmSAQW76e8 + lY+DoguZm228rzqhJUDYZGnlfBBdq2asvZucIbPoyMdbVHciTyVy8mQja90PLeLE + MnpOqtfopjeilBCB6y73rmKtS75sN5bedr0c71sLnGFdBB0m8dxtG+oRKwIDAQAB + AoGADOrlaYdrQEp2XUD+9FQdG3we0cTnYXUubEvbLdxNfZa2tPGcrYQhWuHa9L7G + r1v6YKrQhNK81Fii1iIMvBnzkVIakhSYvC294yyEZG+fYJcXuZWzoF0+YUrlFP0b + vG5JOpDcUN4YG+tG924AbhyPL0AJkX0BEElSWaFhVtnTxAECRQC4fMLIzE2hCq9F + UmR59YDSHasPUVDWuq0eXG+P/0Kp9x5ZUDjZcojcBhpsJBQbx9P4ygyiYj4uUw3O + SA8X/fZHxqmg/QI9APgLR5Uz5Veaj1PguhkoKB3384PnrrKoFD+wgc6H7Qib9aKG + KT0x5dKswZefyE/PF+Qi7hMWiO18FK2HRwJEb/eQREvyhV21uE3kGzzL3ToSWq6Q + cHJFpVqWfv9+Fyea7LvKdPaVZ2vw11ciOSYTWThPaLJVaMoRY/PJ7Va+BRvmUYUC + PQCO06fnYReZRxVq3gcqvzXCc+kTtg+hLilitxc3vosdnvhlGk2awCWvFuzuiwID + +qKuKfLeqOY1oXIirbcCRGtG4PspKLAQMO6jI7bFUc5if9UKo6TGeu39E3qtv4jW + NW6qObPBJ9R1gurMqPUT9g630xjZdZxz6ac9Z7FfgjpMV0Fe + -----END RSA PRIVATE KEY----- + ` + + // 将 pem 格式的密钥转换为 crypto 可以使用的对象 + var publicKey = crypto.createPublicKey(publicKeyPkcs1Pem); + var privateKey = crypto.createPrivateKey(privateKeyPkcs1Pem); + + // RSA 加解密,填充方式使用 RSA_PKCS1_PADDING,其他可选 RSA_NO_PADDING、RSA_PKCS1_OAEP_PADDING、RSA_PKCS1_PSS_PADDING + var data = "spiderapi.cn - 虫术"; + var resultEncrypted = rsaEncrypt(data); + var resultDecrypted = rsaDecrypt(resultEncrypted); + + console.log("RSA PKCS1Padding 加密结果: ", resultEncrypted) + console.log("RSA PKCS1Padding 解密结果: ", resultDecrypted) + + ``` + ```javascript + // ✅ 安装依赖:npm install node-rsa,官方文档:https://github.com/rzcoder/node-rsa + + // ❓ 注意:截止 2024.03,该库中公钥语法标准支持 pkcs8,但实际上不存在这种说法,具有争议,正确应该是 spki,参见:https://github.com/rzcoder/node-rsa/issues/208 + // ❌ padding 填充方式只支持 PKCS1、PKCS1_OAEP,不支持 NO_PADDING、PKCS1_PSS + + var NodeRSA = require("node-rsa"); + + + // pkcs1 标准 pem 格式的公钥 + var publicKeyPkcs1Pem = ` + -----BEGIN RSA PUBLIC KEY----- + MIGJAoGBALLA/aUElSxqvPUnlC4A8UaNh6txyrjlLshW4/wUgWZIBBbvp7yVj4Oi + C5mbbbyvOqElQNhkaeV8EF2rZqy9m5whs+jIx1tUdyJPJXLyZCNr3Q8t4sQyek6q + 1+imN6KUEIHrLveuYq1Lvmw3lt52vRzvWwucYV0EHSbx3G0b6hErAgMBAAE= + -----END RSA PUBLIC KEY----- + ` + + // pkcs1 标准 pem 格式的私钥 + var privateKeyPkcs1Pem = ` + -----BEGIN RSA PRIVATE KEY----- + MIICYAIBAAKBgQCywP2lBJUsarz1J5QuAPFGjYerccq45S7IVuP8FIFmSAQW76e8 + lY+DoguZm228rzqhJUDYZGnlfBBdq2asvZucIbPoyMdbVHciTyVy8mQja90PLeLE + MnpOqtfopjeilBCB6y73rmKtS75sN5bedr0c71sLnGFdBB0m8dxtG+oRKwIDAQAB + AoGADOrlaYdrQEp2XUD+9FQdG3we0cTnYXUubEvbLdxNfZa2tPGcrYQhWuHa9L7G + r1v6YKrQhNK81Fii1iIMvBnzkVIakhSYvC294yyEZG+fYJcXuZWzoF0+YUrlFP0b + vG5JOpDcUN4YG+tG924AbhyPL0AJkX0BEElSWaFhVtnTxAECRQC4fMLIzE2hCq9F + UmR59YDSHasPUVDWuq0eXG+P/0Kp9x5ZUDjZcojcBhpsJBQbx9P4ygyiYj4uUw3O + SA8X/fZHxqmg/QI9APgLR5Uz5Veaj1PguhkoKB3384PnrrKoFD+wgc6H7Qib9aKG + KT0x5dKswZefyE/PF+Qi7hMWiO18FK2HRwJEb/eQREvyhV21uE3kGzzL3ToSWq6Q + cHJFpVqWfv9+Fyea7LvKdPaVZ2vw11ciOSYTWThPaLJVaMoRY/PJ7Va+BRvmUYUC + PQCO06fnYReZRxVq3gcqvzXCc+kTtg+hLilitxc3vosdnvhlGk2awCWvFuzuiwID + +qKuKfLeqOY1oXIirbcCRGtG4PspKLAQMO6jI7bFUc5if9UKo6TGeu39E3qtv4jW + NW6qObPBJ9R1gurMqPUT9g630xjZdZxz6ac9Z7FfgjpMV0Fe + -----END RSA PRIVATE KEY----- + ` + + var key = new NodeRSA(); + key.setOptions({ encryptionScheme: "pkcs1" }); // 设置填充模式,默认 pkcs1_oaep + + // 导入密钥,传入参数格式:语法标准-密钥类型-输出格式,即 scheme-[key_type]-[output_type] + key.importKey(publicKeyPkcs1Pem, "pkcs1-public-pem"); // 公钥语法标准支持 pkcs1、pkcs8,输出格式支持 pem、der + key.importKey(privateKeyPkcs1Pem, "pkcs1-private-pem"); // 私钥语法标准支持 pkcs1、pkcs8,输出格式支持 pem、der + + // RSA 加解密 + var data = "spiderapi.cn - 虫术"; + var resultEncrypted = key.encrypt(data, "base64"); + var resultDecrypted = key.decrypt(resultEncrypted, "utf8"); + + console.log("RSA PKCS1Padding 加密结果: ", resultEncrypted) + console.log("RSA PKCS1Padding 解密结果: ", resultDecrypted) + ``` + + + + ```javascript + // ✅ 安装依赖:npm install jsencrypt,官方文档:https://github.com/travist/jsencrypt + + // ❗ 如果在 Node 环境中使用,会遇到报错 window is not defined,需要在 \node_modules\jsencrypt\bin\jsencrypt.js 添加代码:window = global; + // ❌ padding 填充方式默认为 RSA_PKCS1_PADDING,不支持其他填充方式 + + + var JSEncrypt = require("jsencrypt"); + + + // pkcs1 标准 pem 格式的公钥 + var publicKeyPkcs1Pem = ` + -----BEGIN RSA PUBLIC KEY----- + MIGJAoGBALLA/aUElSxqvPUnlC4A8UaNh6txyrjlLshW4/wUgWZIBBbvp7yVj4Oi + C5mbbbyvOqElQNhkaeV8EF2rZqy9m5whs+jIx1tUdyJPJXLyZCNr3Q8t4sQyek6q + 1+imN6KUEIHrLveuYq1Lvmw3lt52vRzvWwucYV0EHSbx3G0b6hErAgMBAAE= + -----END RSA PUBLIC KEY----- + ` + + // pkcs1 标准 pem 格式的私钥 + var privateKeyPkcs1Pem = ` + -----BEGIN RSA PRIVATE KEY----- + MIICYAIBAAKBgQCywP2lBJUsarz1J5QuAPFGjYerccq45S7IVuP8FIFmSAQW76e8 + lY+DoguZm228rzqhJUDYZGnlfBBdq2asvZucIbPoyMdbVHciTyVy8mQja90PLeLE + MnpOqtfopjeilBCB6y73rmKtS75sN5bedr0c71sLnGFdBB0m8dxtG+oRKwIDAQAB + AoGADOrlaYdrQEp2XUD+9FQdG3we0cTnYXUubEvbLdxNfZa2tPGcrYQhWuHa9L7G + r1v6YKrQhNK81Fii1iIMvBnzkVIakhSYvC294yyEZG+fYJcXuZWzoF0+YUrlFP0b + vG5JOpDcUN4YG+tG924AbhyPL0AJkX0BEElSWaFhVtnTxAECRQC4fMLIzE2hCq9F + UmR59YDSHasPUVDWuq0eXG+P/0Kp9x5ZUDjZcojcBhpsJBQbx9P4ygyiYj4uUw3O + SA8X/fZHxqmg/QI9APgLR5Uz5Veaj1PguhkoKB3384PnrrKoFD+wgc6H7Qib9aKG + KT0x5dKswZefyE/PF+Qi7hMWiO18FK2HRwJEb/eQREvyhV21uE3kGzzL3ToSWq6Q + cHJFpVqWfv9+Fyea7LvKdPaVZ2vw11ciOSYTWThPaLJVaMoRY/PJ7Va+BRvmUYUC + PQCO06fnYReZRxVq3gcqvzXCc+kTtg+hLilitxc3vosdnvhlGk2awCWvFuzuiwID + +qKuKfLeqOY1oXIirbcCRGtG4PspKLAQMO6jI7bFUc5if9UKo6TGeu39E3qtv4jW + NW6qObPBJ9R1gurMqPUT9g630xjZdZxz6ac9Z7FfgjpMV0Fe + -----END RSA PRIVATE KEY----- + ` + + var encryptor = new JSEncrypt(); + encryptor.setPublicKey(publicKeyPkcs1Pem); + encryptor.setPrivateKey(privateKeyPkcs1Pem); + + // RSA 加解密,填充方式只支持 RSA_PKCS1_PADDING + var data = "spiderapi.cn - 虫术"; + var resultEncrypted = encryptor.encrypt(data); + var resultDecrypted = encryptor.decrypt(resultEncrypted); + + console.log("RSA PKCS1Padding 加密结果: ", resultEncrypted) + console.log("RSA PKCS1Padding 解密结果: ", resultDecrypted) + ```