前几天在研究
AES+RSA
混合加密的问题,AES用来加解密文本数据,RSA用来加解密AES key。一开始方向错了,百度最多的结果关于RSA用到的库是jsencrypt
,由于后台的RSA规则是RSA/ECB/OAEPWithSHA-256AndMGF1Padding
,后面换了另一个库node-forge
,它支持各种加密及解密的规则。
1、思路
加密
1、生成AES key
2、用AES key对数据进行加密(AES 加密)
3、用客户端私钥对AES key加签(RSA 加签)
4、用服务端的公钥对AES key加密(RSA 加密)
解密
1、用服务端的私钥对AES key解密(RSA 解密)
2、用客户端公钥验签(RSA 验签)
3、用AES key解密数据(AES 解密)
2、实施步骤代码
1)生成密钥,pem格式
此处需要是
pem
格式的,需要用openssl
命令去终端生成,我这边用到的密钥是2048、pkcs#8格式的,根据自己需要的格式去生成,默认是PKCS#1格式
的
//生成2048格式的密钥
openssl genrsa -out private.pem 2048
//查看私钥
cat private.pem
//转成pkcs8格式
openssl pkcs8 -topk8 -inform PEM -in private.pem -outform pem -nocrypt -out pkcs8.pem
//查看转成pkcs#8格式的私钥
cat pkcs8.pem
//生成对应的公钥
openssl rsa -in private.pem -pubout -out public.pem
PKCS#1格式
以-----BEGIN RSA PRIVATE KEY-----开头以-----END RSA PRIVATE KEY-----结束
PKCS#8格式
以-----BEGIN PRIVATE KEY-----开头以-----END PRIVATE KEY-----结束
-----生成私钥-----
-----私钥转pkcs#8格式-----
-----生成对应的公钥-----
2)加密数据
生成AES key
export const getKey = () => {
let random = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
let str = "";
for (let i = 0; i < 16; i++) {
str = str + random.charAt(Math.random() * random.length);
}
return str;
};
用AES key对数据进行加密
import CryptoJS from "crypto-js";
/**
* AES加密数据
* @param {String} data 要加密的数据
* @param {String} key AES加密密钥
*/
export const aesEncryteData = (data, key) => {
// 加密选项
let CBCOptions = {
iv: CryptoJS.enc.Utf8.parse(key.substr(0, 16)),
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7,
};
let encrypted = CryptoJS.AES.encrypt(
CryptoJS.enc.Utf8.parse(data),
CryptoJS.enc.Utf8.parse(key),
CBCOptions
);
return encrypted.toString();
};
用客户端私钥对AES key加签
import * as forge from "node-forge";
//加签
export const signPri = (signData) => {
const priAForrmat =
"-----BEGIN PRIVATE KEY-----\n" + priA + "\n-----END PRIVATE KEY-----";
var privateKey = forge.pki.privateKeyFromPem(priAForrmat);
const md = forge.md.sha256.create();
md.update(signData, "utf8");
let decrypttext = privateKey.sign(md);
let baseText = forge.util.encode64(decrypttext);
return baseText;
};
用服务端的公钥对AES key加密
import * as forge from "node-forge";
//加密
export const encryte = (str) => {
let pubKey = `-----BEGIN PUBLIC KEY-----\n${pubA}\n-----END PUBLIC KEY-----`;
const pub = forge.pki.publicKeyFromPem(pubKey);
let byteData = str;
var encrypted = pub.encrypt(byteData, "RSA-OAEP", {
md: forge.md.sha256.create(),
mgf1: {
md: forge.md.sha256.create(),
},
});
let encryptText = forge.util.encode64(encrypted);
return encryptText;
};
3)解密数据
用服务端的私钥对AES key解密
import * as forge from "node-forge";
//解密
export const decryte = (key) => {
//base64解密
let baseData = forge.util.decode64(key);
let priKey = `-----BEGIN PRIVATE KEY-----\n${priA}\n-----END PRIVATE KEY-----`;
const pri = forge.pki.privateKeyFromPem(priKey);
//decrypt 解密 AES key
var decrypted = pri.decrypt(baseData, "RSA-OAEP", {
md: forge.md.sha256.create(),
mgf1: {
md: forge.md.sha256.create(),
},
});
return decrypted;
};
用客户端公钥验签
import * as forge from "node-forge";
//验签
export const signPub = (signKey, signData) => {
const pubAForrmat =
"-----BEGIN PUBLIC KEY-----\n" + pubA + "\n-----END PUBLIC KEY-----";
var publiceKey = forge.pki.publicKeyFromPem(pubAForrmat);
const md = forge.md.sha256.create();
md.update(signKey, "utf8");
let erg = forge.util.decode64(signData);
var decrypttext = publiceKey.verify(md.digest().bytes(), erg);
return decrypttext;
};
用AES key解密数据
import CryptoJS from "crypto-js";
/**
* AES解密数据
* @param {String} key AES解密密钥
* @param {String} data 要解密的密文
*/
export const aesDecryptData = (key, data) => {
//加密选项
let CBCOptions = {
iv: CryptoJS.enc.Utf8.parse(key.substr(0, 16)),
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7,
};
let decrypt = CryptoJS.AES.decrypt(
data,
CryptoJS.enc.Utf8.parse(key),
CBCOptions
);
return CryptoJS.enc.Utf8.stringify(decrypt);
};
完毕!希望能给你们带来帮助~~~