首先需要了解以下内容:
Vue中使用crypto-js进行AES对称加密:https://blog.csdn.net/qq_40323256/article/details/123688626
Vue中使用jsencrypt进行RSA非对称加密:https://blog.csdn.net/qq_40323256/article/details/124006449
生成RSA密钥对在线工具:http://web.chacuo.net/netrsakeypair
混合加密流程:
- 接收方创建RSA秘钥对,
- 发送RSA公钥给发送方,自己保留RSA私钥
- 发送方创建AES密钥,加密待传送的明文,之后用RSA公钥加密该密钥,
- RSA公钥加密AES的密钥+AES密钥加密明文的密文----通过Internet发给---->接收方
- 接收方用RSA私钥解密加密的密钥,之后再用解密后的AES密钥解密数据密文,得到明文。
客户端:
<!--main-->
<template>
<div>
<el-button @click="test()">test</el-button>
</div>
</template>
<script>
import { JSEncrypt } from "jsencrypt";
import CryptoJS from "crypto-js";
import axios from "axios";
export default {
methods: {
async test() {
//待加密传输的data数据
const data = {
username: "李疆",
password: 123,
};
console.log("aes加密前的data数据:", data);
//aes密钥
let key_aes = "385f33cb91484b04a177828829081ab7";
console.log("aes密钥:", key_aes);
//aes加密data数据
const data_encrypted_by_aes = CryptoJS.AES.encrypt(
JSON.stringify(data),
CryptoJS.enc.Utf8.parse(key_aes),
{
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.Pkcs7,
}
).ciphertext.toString();
console.log("aes加密后的data数据:", data_encrypted_by_aes);
//从服务端获取公钥
let { data: publicKey } = await axios.get("/api/test/publicKey");
console.log("从服务端获取的rsa公钥:", publicKey);
//rsa公钥加密aes密钥
let encryptor = new JSEncrypt();
encryptor.setPublicKey(publicKey);
let aeskey_encrypted_by_rsa = encryptor.encrypt(key_aes);
console.log("被rsa公钥加密后的aes密钥:", aeskey_encrypted_by_rsa);
//发送aes加密后的data数据和被rsa公钥加密的aes密钥到服务端
let result = await axios.post("/api/test/decryption", {
data_encrypted_by_aes,
aeskey_encrypted_by_rsa,
});
console.log("result:", result);
},
},
};
</script>
服务端:
const router = require('koa-router')()
const CryptoJS = require("crypto-js");
const NodeRSA = require('node-rsa');
router.prefix('/test')
router.get('/', (ctx, next) => {
ctx.body = 'this is a users response!'
})
const key_rsa = new NodeRSA({ b: 1024 });//密钥长度1024位
key_rsa.setOptions({ encryptionScheme: 'pkcs1' });//指定加密格式.不改格式得话可能会报错
router.get('/publicKey', async (ctx, next) => {
let publicKey = key_rsa.exportKey('public');//生成公钥
// let privateKey = key_rsa.exportKey('private');//生成私钥
ctx.body = publicKey;
});
router.post('/decryption', async (ctx, next) => {
let { data_encrypted_by_aes, aeskey_encrypted_by_rsa, } = ctx.request.body;
console.log("aes加密后的data数据:", data_encrypted_by_aes)
console.log("被rsa公钥加密的aes密钥:", aeskey_encrypted_by_rsa)
//rsa私钥解密出aes密钥
const aeskey_decrypted_by_rsa = key_rsa.decrypt(aeskey_encrypted_by_rsa, 'utf8');
console.log('被rsa私钥解密出的aes密钥: ', aeskey_decrypted_by_rsa);
// aes密钥解密出data数据
let data_decrypted_by_aes = JSON.parse(CryptoJS.enc.Utf8.stringify(CryptoJS.AES.decrypt(
CryptoJS.format.Hex.parse(data_encrypted_by_aes),
CryptoJS.enc.Utf8.parse(aeskey_decrypted_by_rsa),
{
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.Pkcs7
}
)))
console.log('被aes密钥解密出的data数据:', data_decrypted_by_aes);
ctx.body = { message: "success" };
});
module.exports = router
结果:
上面的公钥和私钥是通过node-rsa生成的,如果想自己手动指定公钥和私钥,可通过如下方式:(客户端代码不变,只需要改服务端代码)
const router = require('koa-router')()
const CryptoJS = require("crypto-js");
const NodeRSA = require('node-rsa');
router.prefix('/test')
router.get('/', (ctx, next) => {
ctx.body = 'this is a users response!'
})
router.get('/publicKey', async (ctx, next) => {
let publicKey = `-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDARcNxlvPXZQSup9yPV6iVzqMI
eBr2Rztd4zxYUCwL2pqaig3ZP17eFpzfiI+aBf2F4qp/QHPMVnEQmx33/fGlssvc
cqplP7gvk7BKporUWtnyqYKqy/fAE07c/Yxpe5WZoMo2pRyaBDMLMZ49MpfAzHXS
pTzUY9W4F49C0Y8SPQIDAQAB
-----END PUBLIC KEY-----`
ctx.body = publicKey;
});
router.post('/decryption', async (ctx, next) => {
let { data_encrypted_by_aes, aeskey_encrypted_by_rsa, } = ctx.request.body;
console.log("aes加密后的data数据:", data_encrypted_by_aes)
console.log("被rsa公钥加密的aes密钥:", aeskey_encrypted_by_rsa)
let privateKey = `-----BEGIN PRIVATE KEY-----
MIICeQIBADANBgkqhkiG9w0BAQEFAASCAmMwggJfAgEAAoGBAMBFw3GW89dlBK6n
3I9XqJXOowh4GvZHO13jPFhQLAvampqKDdk/Xt4WnN+Ij5oF/YXiqn9Ac8xWcRCb
Hff98aWyy9xyqmU/uC+TsEqmitRa2fKpgqrL98ATTtz9jGl7lZmgyjalHJoEMwsx
nj0yl8DMddKlPNRj1bgXj0LRjxI9AgMBAAECgYEAsjd34y+yMTKXVnSNQehUgRcZ
kt4Qz7pS0sGvy4P0b8BekWPpVjcg7eYz3hYsVO28gn8I3g6Vxw9Qmb3N13HwqrPt
1z6pGkr54FtgsxPDaS0Cu86gt9G+MfAHMbYHtCd3VEhfXmj17/NeV/nFUG0mlgGZ
bZY0wLlDNYX6t+clYQECQQDphC6/5xhdWr1yelNO5fybt/1p9Cp5q3nRR1NjEwCY
77WE1VMwbdSYkj9whSL9EcnEGFL6/PgcWjkXuY4Jpg9hAkEA0sj79IVYt7L0xnTO
tNg6RBoF9vnt9T0HUAqU0Q9YHbV+SzEMUOKepMW5XwSlPomeOpOQEYot7SmXuUL5
aBj8XQJBAKNj+dIMwN+RPj17mg76nWXXt1kLnyzC7tmgLpiEE0bvcvMe0LZyIu8e
ZYU1ouWwLJ0o5+b2WiR8fLY8/0WBDAECQQCa7mXbfiQOqjgmovbIkGKLagFWXrBc
YKY+W/i0ja278IpK5FtkHJ51CGxPfg+jnu2xqoLrkYBeYQMHhkXiEPN1AkEAmjlL
3AWqcl6I0vsvt1cK4XiQmez8L6JomMddjF9vi96mNy8Be8+7OCxWv+aZ2P8AhZKD
WrHvhaHSs389XzS3HQ==
-----END PRIVATE KEY-----
`
const key_rsa = new NodeRSA(privateKey);
key_rsa.setOptions({ encryptionScheme: 'pkcs1' }); // 因为jsencrypt自身使用的是pkcs1加密方案, nodejs需要修改成pkcs1。
const aeskey_decrypted_by_rsa = key_rsa.decrypt(aeskey_encrypted_by_rsa, 'utf8');
console.log('被rsa私钥解密出的aes密钥: ', aeskey_decrypted_by_rsa);
let data_decrypted_by_aes = JSON.parse(CryptoJS.enc.Utf8.stringify(CryptoJS.AES.decrypt(
CryptoJS.format.Hex.parse(data_encrypted_by_aes),
CryptoJS.enc.Utf8.parse(aeskey_decrypted_by_rsa),
{
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.Pkcs7
}
)))
console.log('被aes密钥解密出的data数据:', data_decrypted_by_aes);
ctx.body = { message: "success" };
});
module.exports = router
注意:我尝试过代码中不直接展示公钥和私钥,而是通过fs.readFile()的方式读取本地的公钥和私钥文件,虽然可以读取,但是最后加密解密失败。
把公钥私钥文件放到public/files文件夹中,这样读取路径是可以的:fs.readFile('public/files/xxx.txt',(err,data)=>{})