基于js的rsa签名
引入node-forge
const forge = require("node-forge");
新建RSA加密类
将对象转换成签名字符串,并且按要求去除sign参数
然后进行排列 小写字母在前
// RSA加密类
class RSACrypt {
constructor(key) {
this.key = forge.pki.publicKeyToPem(key);
}
// 将对象转换为签名字符串,对参数进行排序
static signData(dataDict) {
let tmp = [];
for (let key in dataDict) {
if (dataDict.hasOwnProperty(key) && key !== "sign") {
// 排除sign参数
let value = dataDict[key];
if (typeof value === "object" && value !== null) {
tmp.push(`${key}=${JSON.stringify(value)}`);
} else {
tmp.push(`${key}=${value}`);
}
}
}
// 按照参数名称排序,小写字母在前
tmp.sort((a, b) => {
return a.split("=")[0].localeCompare(b.split("=")[0], undefined, { numeric: true, sensitivity: "base" });
});
return tmp.join("&");
}
}
RSA私钥并且继承RSA加密类
根据外部传入的RSA密钥生成签名
// RSA私钥
class RSAPrvCrypt extends RSACrypt {
// RSA私钥生成签名
sign(data) {
if (typeof data === "object") {
data = RSACrypt.signData(data);
}
data = new Uint8Array(forge.util.encodeUtf8(data));
const md = forge.md.sha256.create();
md.update(data);
const privateKey = forge.pki.privateKeyFromPem(this.key);
const signature = privateKey.sign(md);
return signature.toBase64(); // 将签名结果进行Base64编码
}
}
RSA公钥加密 并且验证签名
// RSA公钥
class RSAPubCrypt extends RSACrypt {
// RSA公钥加密
encrypt(data) {
const encrypted = [];
const maxLength = 117; // 根据密钥长度调整,117是2048位密钥的推荐块大小
data = data.utf8Encode();
const publicKey = forge.pki.publicKeyFromPem(this.key);
for (let i = 0; i < data.length; i += maxLength) {
const block = data.subarray(i, i + maxLength);
encrypted.push(publicKey.encrypt(block, "RSAES-PKCS1-V1_5"));
}
return encrypted.map((b) => b.toBase64()).join("");
}
// RSA公钥验证签名
verifySign(data, signature) {
if (typeof data === "object") {
data = RSACrypt.signData(data);
}
data = new Uint8Array(forge.util.encodeUtf8(data));
const signatureBytes = forge.util.decode64(signature);
const publicKey = forge.pki.publicKeyFromPem(this.key);
return publicKey.verify(data, signatureBytes, "SHA256");
}
}
导出模块供外部使用
module.exports = {
RSAPubCrypt,
RSAPrvCrypt,
};
外部
const forge = require("node-forge");
const { RSAPrvCrypt } = require("文件名"); //
// 私钥
const privateKeyPem = `-----BEGIN RSA PRIVATE KEY-----
...
-----END RSA PRIVATE KEY-----`;
// 创建RSA私钥实例
const rsaPrvCrypt = new RSAPrvCrypt(privateKeyPem);
// API请求参数
const params = {
foo: 1,
bar: 2,
'foo_bar': 3,
foobar: 4
};
// 1. 对参数进行排序
const sortedParams = RSACrypt.signData(params);
// 2. 使用私钥对排序后的参数进行签名
const signature = rsaPrvCrypt.sign(sortedParams);
// 3. 将签名结果进行Base64编码(在sign方法中已经完成)
// 4. 将签名值赋给Sign参数,并发起API请求
const apiParamsWithSign = {
...params,
Sign: signature
};