前端RSA+AES混合加密
前言
最近在工作中使用到了RSA和AES加密,网上也有很多教程,但是没有什么时效性了,所以想把内容记录下来和同学们一起学习交流
一、为什么要使用RSA和AES?
-
RSA和AES是什么?
-
RSA:非对称加密,使用
公钥
和私钥
加密和解密,加密速度慢 -
AES:对称加密,加密和解密使用
同一个密钥
,加密速度快
-
-
为什么要混淆?只用一个不行吗?
因为AES加密速度快,自然是我们的第一选择,但是缺点也明显。因为使用
同一个密钥
,如果有一方密钥泄露,那么数据也就不安全了。所以我们可以结合RSA互补二者的缺点,使用RSA来加密传递AES密钥,用AES来加密数据。
二、思路
- 服务端生成RSA密钥对(
privateKey-1
、publicKey-1
),把公钥 publicKey-1
发送给客户端 - 客户端生成RSA密钥对(
privateKey-2
、publicKey-2
),使用服务端的公钥
加密自己的公钥publicKey-2
,将加密后的数据发送给服务端 - 服务端使用自己的
私钥
解密获取到客户端的公钥,将AESKey
使用客户端公钥 publicKey-2
加密发送给客户端 - 客户端使用自己的
私钥
解密获取AESkey
- 双方使用
AESkey
来进行数据传输
流程图
如果流程从客户端开始,原理也是一样的,只需要把双方角色互换即可
三、代码
前端需要用到两个npm包
- crypto-js 用于操作AES密钥
- JSEncrypt 用于操作RSA密钥,如果加密密文过长可以替换为encryptlong
生成RSA密钥
import CryptoJS from 'crypto-js/crypto-js'
import JSEncrypt from 'jsencrypt'
// 初始化
const keyPair = new JSEncrypt()
const genKeyPair = () => {
const genKeyPair = {}
genKeyPair.privateKey = rsaUtil.keyPair.getPrivateKey() // 生成RSA密钥
genKeyPair.publicKey = rsaUtil.keyPair.getPublicKey() // 生成RSA公钥
return genKeyPair
}
RSA公钥加密 - 收到服务端公钥后加密公钥
/**
* rsa公钥加密
* @param {*} cipherContent 需要加密内容
* @param {*} publicKey 服务端的公钥
* @returns
*/
const encryptByRsa = (cipherContent, publicKey) => {
const newValue = typeof cipherContent === 'string' ? cipherContent : cipherContent.toString()
keyPair.setPublicKey(publicKey)
return keyPair.encryptLong(newValue) // 注意:加密类型为string
},
RSA解密 - 解密后取到AES key
/**
* rsa私钥解密
* @param {*} plainContent 解密的内容
* @param {*} privateKey 解密私钥
* @returns
*/
const decryptByRsa = (plainContent, privateKey) => {
keyPair.setPrivateKey(privateKey)
return keyPair.decryptLong(plainContent)
},
AES 加密
/**
* AES 加密
* @param {*} cipherContent 加密的内容
* @param {*} key AES key
* @returns
*/
const encrypt = (cipherContent, key) => {
const aesKey = CryptoJS.enc.Utf8.parse(key)
const newValue = typeof cipherContent === 'string' ? cipherContent : cipherContent.toString()
const encrypted = CryptoJS.AES.encrypt(CryptoJS.enc.Utf8.parse(newValue), aesKey, { mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.Pkcs7 })
return encrypted.toString()
}
AES 解密
/**
* AES解密
* @param {*} plainContent 解密的内容
* @param {*} key AES key
* @returns
*/
decrypt: (plainContent, key) => {
const aesKey = CryptoJS.enc.Utf8.parse(key)
const decrypt = CryptoJS.AES.decrypt(plainContent, aesKey, { mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.Pkcs7 })
const decString = CryptoJS.enc.Utf8.stringify(decrypt).toString()
return decString instanceof Object ? decString : JSON.parse(decString)
},
四、Q&A
剩下几个问题想和大家一起探讨下
-
前端加密有意义吗?
我的回答是防君子不防小人,真正的"安全"还是得靠后端的同学
-
前端怎么安全的存储密钥?
我现在的操作还是二次加密后存储session,不知道同学们是否有更好的方案
转载自:https://juejin.cn/post/7078952957739286542