RSA
RSA加密算法是一種非對稱加密算法。
假設 A 與 B 通信。A 和 B 都提供一個公開的公鑰。A 把需要傳遞的信息,先用自己的私鑰簽名,再用 B 的公鑰加密。B 接收到這串密文后,用自己的私鑰解密,用 A 提供的公鑰驗簽。
為什么要先簽名后加密?如果你先加密后簽名,非法用戶通過獲取的公鑰就可以破解簽名,破解之后就可以替換簽名。
詳細的原理可以參考以下文檔:
RSA算法原理(一)
RSA算法原理(二)
node-rsa
在 node.js 中使用 rsa 算法,我們使用的是 node-rsa 這個包。
const NodeRSA = require('node-rsa');
const a_public_key_data = '-----BEGIN PUBLIC KEY----- ... -----END PUBLIC KEY-----';
const a_private_key_data = '-----BEGIN PRIVATE KEY----- ... -----END PRIVATE KEY-----';
const b_public_key_data = '-----BEGIN PUBLIC KEY----- ... -----END PUBLIC KEY-----';
const b_private_key_data = '-----BEGIN PRIVATE KEY----- ... -----END PRIVATE KEY-----';
// 生成 A 的公私鑰對象
const a_public_key = new NodeRSA(a_public_key_data);
const a_private_key = new NodeRSA(a_private_key_data);
// 生成 B 的公私鑰對象
const a_public_key = new NodeRSA(a_public_key_data);
const a_private_key = new NodeRSA(a_private_key_data);
const text = 'Hello RSA!';
// 加簽並加密
const sign = a_private_key.sign(text, 'base64', 'utf8');
console.log('A 私鑰加簽:', sign);
const encrypted = a_public_key.encrypt(sign, 'base64');
console.log('B 公鑰加密:', encrypted);
// 解密並驗簽
const decrypted = a_public_key.decrypt(encrypted, 'utf8');
console.log('B 私鑰解密:', decrypted);
const verify = a_public_key.verify(text, decrypted, 'utf8', 'base64');
console.log('A 公鑰驗簽:', verify);
serialize
接口傳遞的一般是復雜的對象,所以我們需要把對象按一定的順序排列並序列化成字符串再進行簽名加密的操作
const serialize = (obj) => {
const str = [];
Object.keys(obj).sort().forEach((key) => {
if (obj.hasOwnProperty(key)) {
str.push(encodeURIComponent(key) + '=' + encodeURIComponent(obj[key]));
}
});
return str.join('&');
};
注意
RSA 算法有一定的計算量,加上 Node 不適合做計算密集型的操作。當接口被頻繁調用可能會占用主線程,阻塞其他接口,使用了 RSA 的接口並發量會下降十倍左右。如非必要,謹慎在 Node 里使用 RSA。