nodejs之RSA加密/签名

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
原文地址:https://www.cnblogs.com/wzs5800/p/13169306.html