项目里来来回回一直在用aes,有些时候总会出现和别人加解密不一致的情况,也没看到具体说明很详细的文章,自己花时间研究搜集整理了一下。
一、编码格式
要弄懂aes加解密,首先得先清除编码格式。简单列举说明几种编码格式。
1.base64编码
Base64 编码是通过使用一组 64 个不同的字符表示二进制数据来实现的,包括小写字母a-z、大写字母A-Z、数字0-9、符号"+"、"/"一共64个字符的字符集。
2.Hex编码(十六进制编码)
Hex编码(也称为十六进制编码)是一种将数据转换为十六进制表示形式的编码方法。与base64编码不同,Hex编码使用16个字符来表示数据,这16个字符分别是0-9的数字和A-F的字母(不区分大小写,即a-f和A-F是等价的)。
3.Unicode编码
Unicode编码是一个用于表示字符的编码标准,它允许使用16位或32位的整数序列来表示字符,具体取决于使用的Unicode编码格式。Unicode编码包括但不限于、UTF-8和UTF-7等,每种编码方式都有其特定的应用场景和优缺点。
二、AES前端加密方法
首先要用到crypto-js库,里面包含很多加密方法,我们使用其中的aes加密方法。
1.安装前端加密库crypto-js
npm install crypto-js
2.引入crypto-js
import CryptoJS from 'crypto-js'
3.密钥
aes属于对称加密,加密解密都使用同一个密钥。这里不详细解释,对加密感兴趣的可以自己学习密码学相关知识。aes的密钥长度可以是16字节,24字节,32字节。(1字节=8位,可以使用16位base64编码,32位Hex编码)
4.crypto-js的加密方法
CryptoJS.AES.encrypt(data, key, {
iv:iv,
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.Pkcs7
});
该方法接受三个参数,第一个是加密的数据(data),第二个是加密的秘钥(key),第三个是加密方法对象,该对象能接受三个值:iv表示偏移量(CBC模式特有),mode表示加密模式,padding表示填充方式(加解密数据不满16位用于填充的方法)
这是crypto-js提供的加密方法,理论上如果传入字符串类型的参数,方法内部会自动转为WordArray格式。但是为保证规范,我们将上述传入参数都转换为WordArray格式。下面是官网提供各种编码转化方式:
CryptoJS.AES.encrypt方法加密后的结果是一个对象,其中包含了加密后的数据。这个对象通常包含以下属性:
-
ciphertext
: 加密后的数据,以WordArray
对象的形式存储。 -
key
: 加密使用的密钥,以WordArray
对象的形式存储。 -
iv
: 加密使用的初始化向量(IV),以WordArray
对象的形式存储。
所以根据需要加密的编码格式这边可以得到最简单的一个加密过程,下面方法中默认传入的为utf-8编码格式数据,结果输出的是bsae64格式密文。这边注意还有个比较常用的密文输出是Hex编码,通常可以用toString()方法代替CryptoJS.enc.Hex.stringify(),即encrypted.ciphertext.toString()就是将WordArray对象格式转化为Hex编码返回。
function aesEncryptCBC(key,data,iv) {
//将key,data,iv都转化为wordarry格式,根据传入的编码格式选择对应的方法
key = CryptoJS.enc.Utf8.parse(key);
iv = CryptoJS.enc.Utf8.parse(iv);
data= CryptoJS.enc.Utf8.parse(data)
var encrypted = CryptoJS.AES.encrypt(data, key, {
iv:iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
//这里返回的是Base64的密文
return CryptoJS.enc.Base64.stringify(encrypted.ciphertext);
}
5.crypto-js的解密方法
同加密方法提到的一些注意点,不再赘述,以下代码中的toString(CryptoJS.enc.Utf8)等同于CryptoJS.enc.Utf8.stringify(encrypted.ciphertext),都是将WardArray转化为utf8编码格式,可以自行选择。
function aesDecrypt(key,encrypted,iv) {
key = CryptoJS.enc.Utf8.parse(key);
encrypted = CryptoJS.enc.Base64.parse(encrypted);
iv = CryptoJS.enc.Utf8.parse(iv);
var decrypted = CryptoJS.AES.decrypt(encrypted, key, {
iv:iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
return decrypted.toString(CryptoJS.enc.Utf8);
}
三、总结
主要还是搞清楚各种编码的格式以及CryptoJS提供的WordArray格式转化的方法。其他都是一些基础的传参及取值问题。最后提一个注意点,AES是对称加密,前端加密秘钥总还是没有那么安全,建议采用非对称加密。