一: 常见加密算法
1.对称加密
使用的密钥只有一个,发送和接收双方都使用这个密钥对数据进行加密和解密。这就要求加密和解密方事先都必须知道加密的密钥。其优点是算法公开、计算量小、加密速度快、加密效率高;缺点是密钥泄露之后,数据就会被破解。一般不推荐单独使用。根据实现机制的不同,常见的算法主要有AES、ChaCha20、3DES等。
2.非对称加密
它需要两个密钥,一个称为公开密钥 (public key),即公钥;另一个称为私有密钥 (private key),即私钥。
他俩是配对生成的,就像钥匙和锁的关系。因为加密和解密使用的是两个不同的密钥,所以这种算法称为非对称加密算法。其优点是算法强度复杂、安全性高;缺点是加解密速度没有对称加密算法快。常见的算法主要有RSA、Elgamal等。
3.散列算法
散列算法又称散列函数、哈希函数,是把消息或数据压缩成摘要,使得数据量变小,将数据的格式固定成特定长度的值。一般用于校验数据的完整性,平时我们下载文件就可以校验 MD5 来判断下载的数据是否完整。常见的算法主要有 MD4、MD5、SHA 等。
二:方案
单单使用对称加密
使用两套非对称加密,
上传数据-客户端用公钥加密,下载数据-客户端用私钥解密秘钥更新比较麻烦
对称加密与非对称结合:
上传数据时:
- 客户端用随机生成秘钥对敏感数据进行对称加密,
- 从服务端获取非对称加密的 公钥,
- 对对称加密的秘钥进行非对称加密
下载数据:
- 服务端用对称加密对数据进行加密
总结:
方案二比较简单,但是需要维护两套公钥和私钥,当公钥变化的时候,必须通知对方,灵活性比较差。方案三相对方案二来说,密钥 1 随时可以变化,并且不需要通知服务端,相对来说灵活性、安全性好点并且方案三对内容是对称加密,当数据量大时,对称加密的速度会比非对称加密快。所以本文采用方案三给予代码实现。
三: 代码实现
前端:
// npm 引入
npm install crypto-js
//utils包下的index文件中增加解密与加密方法
const CryptoJS = require('crypto-js')
/**
* aes加密方法
* @param {string} text 待加密的字符串
* @param {array} key 加密key
*/
export function aesEncrypt(text, key) {
// var message = JSON.stringify(data);//加密后的字符窜
key = CryptoJS.enc.Utf8.parse(key)
var encryptedData = CryptoJS.AES.encrypt(text, key, {
mode: CryptoJS.mode.ECB, // ECB加密模式 根据后端采用的模式更改
padding: CryptoJS.pad.Pkcs7
})
return encryptedData.toString()
}
/**
* aes解密方法
* @param {string} encryptedHex 加密的字符串
* @param {array} key 加密key
*/
export function aesDecrypt(encryptedHex, key) {
key = CryptoJS.enc.Utf8.parse(key)
var decrypt = CryptoJS.AES.decrypt(encryptedHex, key, {
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.Pkcs7
})
return CryptoJS.enc.Utf8.stringify(decrypt).toString()
}
/**
* 随机生成秘钥
*/
export function getRandomKey(n) {
var chars = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z']
if (n == null) {
n = 16
}
var res = ''
for (var i = 0; i < n; i++) {
var id = Math.ceil(Math.random() * 35)
res += chars[id]
}
return res
}
常见错误:
Key length not 128/192/256 bits,key的长度必须要是128,192或者256 位
128 位 对应的是 16 个字节
192 位 对应的是 24 个字节
256 位 对应的是 32 个字节
npm install jsencrypt
//vue页面引入
import { JSEncrypt } from 'jsencrypt'
//页面方法内:
const encrypt = new JSEncrypt()
encrypt.setPublicKey(this.publicKey) //设置公钥
data.secretKey = encrypt.encrypt(secretKey) //非对称加密
java:
java部分是引用的Hutool工具包中的方法
//@Configuration配置类中,配置公私钥 将rsa对象放入容器中
@Bean
public RSA RSAGenfactory(){
return new RSA(privateKey,publicKey);
}
//接口方法中对上传数据进行解析
引入容器中的RSA对象
@Autowired
RSA rsa;
//非对称解密
String data = rsa.decryptStr(要解密的数据, KeyType.PrivateKey);
//对称解密
SymmetricCrypto aes = new SymmetricCrypto(SymmetricAlgorithm.AES, data.getBytes());
String repCode = aes.decryptStr(要解密的数据,CharsetUtil.CHARSET_UTF_8);