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)
+ ```