nodejs之RSA加密/簽名
密鑰對生成
使用內置模塊crypto
從 node.js 的 v10.12.0 開始,可以使用內部模塊 crypto.generateKeyPairSync 方法生成公私鑰。
const { generateKeyPairSync } = require('crypto');
const { publicKey, privateKey } = generateKeyPairSync('rsa', {
modulusLength: 4096,
publicKeyEncoding: {
type: 'spki',
format: 'pem'
},
privateKeyEncoding: {
type: 'pkcs8',
format: 'pem',
cipher: 'aes-256-cbc',
passphrase: 'top secret'
}
});
使用node-rsa庫
低版本(< v10.12.0)的話可以使用node-rsa來生成:
// 生成一個1024長度的密鑰對
const key = new nodeRSA({b: 1024});
// 導出公鑰
const publicKey = key.exportKey('public');
// 導出私鑰
const privateKey = key.exportKey('private');
console.log('publicKey>>>>>>',publicKey);
console.log('privateKey>>>>>>',privateKey);
輸出如下:
publicKey>>>>>> -----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDLANd0RbDjBb9R5o1ng5y1WRpf
VnX+xuVd0BY7ZyFzzlq8L05PGMbfElxLqWGqvtmEspOPZibd+6i05D+xePoF4k7h
GYLmdJW2JJdqLVCWCKbVBPAlI7PS9XoRKea1czL0syNd10l+TdXJ4r/ES4vMn33m
JzCGuueIhRjcqalGowIDAQAB
-----END PUBLIC KEY-----
privateKey>>>>>> -----BEGIN RSA PRIVATE KEY-----
MIICXwIBAAKBgQDLANd0RbDjBb9R5o1ng5y1WRpfVnX+xuVd0BY7ZyFzzlq8L05P
GMbfElxLqWGqvtmEspOPZibd+6i05D+xePoF4k7hGYLmdJW2JJdqLVCWCKbVBPAl
I7PS9XoRKea1czL0syNd10l+TdXJ4r/ES4vMn33mJzCGuueIhRjcqalGowIDAQAB
AoGBAMDxRtZDGrFbmBCusX1OMRaH3rH4imOiBQSaL1c8WSYpXkH4MFSrNvF0EPb0
wVg41qLx25/ytkRL2Xg8bHEwi2h030SsQAgQnb/8kXOztS3vE3ujOJmji6B+5/2e
cnZjrgOxkb8U5PwNdFalpUqpXGDxsxfem7ej537Xv23cBqHZAkEA55I4+w7cpOlT
X1bw5A5ODJE8+WHptmSzAso7YTxaGgOFv415hr4tnxH3Oj+BL4bqlhLyh0QXgUqo
PCtRBjgLpwJBAOBrHmDj/4zhZYj/0OyrA7069ktEEezEfYYHKeYbt1CA6gxPB+Qk
UVvndY2cQNR0ItIHYixgSnOR15ZegcoQnKUCQQDWpkeDD8eeZVkOqrwn6MqYA5iN
YSEOHFGCaIqaGyM5scIsSKs5JteK91A/AdZxg5G3AmEk2Q0gn19KRqyYIyNJAkEA
kaRzHqZZHvDYmESNLkr+Ljypwsb2axZJ8EWN54xtN42yVzKjCGiZdG+OVszlNfv4
7R1llS8YolAv/aJv0NdfEQJBALdZzBkUOwS8sfnjh8BOtEGhTwgHxF7IrXk875mJ
4JaKMWJYhki27TzqIskSlY7luemXFKRB3pxagB8kUeVFzdQ=
-----END RSA PRIVATE KEY-----
ps:如果不指定導出格式,公鑰默認是pkcs8,私鑰是pkcs1。關於這兩個格式簡單描述(具體可以參考README.md):
* `'pkcs1'` — public key starts from `'-----BEGIN RSA PUBLIC KEY-----'` header and private key starts from `'-----BEGIN RSA PRIVATE KEY-----'` header
* `'pkcs8'` — public key starts from `'-----BEGIN PUBLIC KEY-----'` header and private key starts from `'-----BEGIN PRIVATE KEY-----'` header
或者,使用已存在的私鑰來生成公鑰:
const fs = require('fs');
const nodeRSA = require('node-rsa');
// 讀取私鑰
const privateKey = fs.readFileSync('./certs/ca-key.pem', 'utf8');
const key = new nodeRSA(cakey);
// 導出對應公鑰
const publicKey = key.exportKey('pkcs1-public-pem');
console.log(privateKey);
console.log(publicKey)
RSA加密
使用crypto
最簡單的方法,使用自帶模塊crypto:
const crypto = require('crypto');
const nodeRSA = require('node-rsa');
// 生成一個1024長度的密鑰對
const key = new nodeRSA({b: 1024});
// 導出公鑰
const publicKey = key.exportKey('public');
// 導出私鑰
const privateKey = key.exportKey('private');
const secret = 'hello ashin!'
// 使用私鑰加密,公鑰解密
const encrypt = crypto.privateEncrypt(privateKey, Buffer.from(secret));
const decrypt = crypto.publicDecrypt(publicKey, encrypt);
// 也可反過來
// const encrypt = crypto.publicDecrypt(publicKey, Buffer.from(secret));
// const decrypt = crypto.privateEncrypt(privateKey, encrypt);
console.log('加密后:', encrypt.toString('base64'));
console.log('解密后:', decrypt.toString());
輸出:
加密后: m6HOwaF//jDW9PvXJwgx3gipV54Ia1pPsiR1+qRXkiy7ZNxrogMt+O6+6NwRL15qsNZM/suCeB6gn9uxFOtby58MzsYOMUiZGDWbfafRawypX5lEY6GEY/EdwuveLU97XkIHUpJ424CN2x6vxw6LdQjKBeyPbFI0Pw19Et5FSuc=
解密后: hello ashin!
使用node-rsa
const nodeRSA = require('node-rsa');
// 生成一個1024長度的密鑰對
const key = new nodeRSA({b: 1024});
const secret = 'hello ashin!'
const encryptd = key.encrypt(secret);
const decryptd = key.decrypt(encryptd)
console.log('加密后:', encryptd.toString('base64'));
console.log('解密后:', decryptd.toString());
輸出:
加密后: lypj+J4qvRaNIQpe6bAaMc8NV2kwlh9Uzn6zdkI1Cda4PKECP8AD/aANUhW2qNB6vxtSwD5xDBLak/9LYAmADavu2F4kxDDvepfd6L4F1+JShsrxWHF/OGY1LyoLtPkSfK6DtJcDqtSv/X/PZ7hAcTgyBRnpwPFKKgplikqt8OI=
解密后: hello ashin!
RSA簽名
rsa簽名一般用於web api的安全驗證,防止請求被篡改。
一般我們需要對請求參數(包括params、body、協議等)做一定規則處理(客戶端與服務端預定好規則),然后請求頭帶上簽名,服務端拿到簽名后進行驗簽。
node客戶端發起請求時可以使用urllib庫的請求鈎子快速生成簽名,然后加到請求頭headers里面:
beforeRequest Function - Before request hook, you can change every thing here.
使用crytpo
簽名/認證如下:
const crypto = require('crypto');
console.log('>>>>>>>>>>使用 crypto 簽名>>>>>>>>>>');
const sign = crypto.createSign('SHA256');
sign.update('hello ashin!');
sign.end();
const signature = sign.sign(privateKey);
console.log(signature.toString('base64'));
console.log('>>>>>>>>>>使用 crypto 簽名驗證>>>>>>>>>>');
const verify = crypto.createVerify('SHA256');
// 對具體數據驗證
verify.update('hello ashin!');
verify.end();
const data = verify.verify(publicKey, signature);
console.log(data);
輸出:
>>>>>>>>>>使用 crypto 簽名>>>>>>>>>>
PARviHlEefrUcroa2DsyvlRDInMvHzSWASL6Jb9IQ9zMf7mobVMrOP5pMnt/WhB5VMzt7AmlQkNRVm4+dmtmn3ow9BDZ+ZU8l8iRmoIDO89BgQHSCQJp8YRQ6cmo8JXjswBPMAurnlcVr0IxUkmewgv2E7INuOTYn9tgiOrjZ8k=
>>>>>>>>>>使用 crypto 簽名驗證>>>>>>>>>>
true
使用node-rsa
const nodeRSA = require('node-rsa');
const key = new nodeRSA({b: 1024});
console.log('>>>>>>>>>>使用 node-rsa簽名>>>>>>>>>>');
const signature = key.sign('hello ashin!');
console.log(signature.toString('base64'));
console.log('>>>>>>>>>>使用 node-rsa驗簽>>>>>>>>>>');
const verify = key.verify('hello ashin!', signature);
console.log(verify.toString('base64'));
輸出:
>>>>>>>>>>使用 node-rsa簽名>>>>>>>>>>
PgwpNyMeCnSuguTm3O2ftFzO6Hh1T966jHuMQf4pUTKcqSjRTkehET5JMMEQfMepjDVlrt1xPBR8ZO7Hej4RlnZ4sGP+hQW4qSuDGqcgeZIp6+8oMtgJ5V/QqcfY81K7NXojzTDep7oQ2UzRWOyRcl1JO6BmhqHMEkuemTyPuIM=
>>>>>>>>>>使用 node-rsa簽名驗證>>>>>>>>>>
true