AES前端加密解密传输的坑
- AES加密解密
- 1.首先是密钥的正确性,以及密钥决定了数据块的位数
- 2.对于这个库的AES有两种输出形式编码,Hex和Base64。相应的输入内容进行解密时也有两种编码形式。
- 3.AES的算法可以设置模式mode和填充padding,与其他平台对接时需要确保是一致的填充和模式。如果设置了偏移iv也要一致。
AES加密解密
使用的是crypto-js进行加密解密。引入方式github上有讲解:
https://github.com/brix/crypto-js 文档地址见: https://cryptojs.gitbook.io/docs/ 在前后台对接中或不同语言对接中需要弄明白的几点有:
1.首先是密钥的正确性,以及密钥决定了数据块的位数
库中默认的数据块是256
CryptoJS supports AES-128, AES-192, and AES-256. It will pick the variant by the size of the key you pass in. If you use a passphrase, then it will generate a 256-bit key.
库内支持128位 192位 256位的加解密,这取决于你传入的key(密钥)的种类,如果你用的是一个密钥,那么它将生成256位的key
如果是与java通信,可能需要前台将密钥转为128位的key
// 可以让数据块为128位
key = CryptoJS.enc.Utf8.parse(key);
2.对于这个库的AES有两种输出形式编码,Hex和Base64。相应的输入内容进行解密时也有两种编码形式。
当输入Hex的密文进行解密时,如果之前加密的明文数据长度不是8的整数倍就会报错Malformed UTF-8 data,此时可以将Hex编码的密文转为base64再进行解密,或者使用官方提供的解码器
如使用官方的解码工具:
// secret是等待进行解密的Hex编码密文
// Json返回的内容未做长度为8的整数倍限制,Hex直接解密报错,CryptoJS.lib.CipherParams
secretText = CryptoJS.lib.CipherParams.create({'ciphertext': CryptoJS.enc.Hex.parse(secret)});
// 转为base64来进行解密, 如果需要得到明文,还需要对现有return结果进行toString()
secretText = CryptoJS.enc.Hex.parse(secret),
secretText = CryptoJS.enc.Base64.stringify(secretText);
如果输出Base64密文传输给后台,要对特殊的符号进行处理,比如+ 换为%2b 不然传输后后台拿到的可能是空,后台拿到密文后再对转义后的符号换回原符号再进行解密。
3.AES的算法可以设置模式mode和填充padding,与其他平台对接时需要确保是一致的填充和模式。如果设置了偏移iv也要一致。
官网文档给出的支持的模式和填充有:
CryptoJS supports the following modes:
- 密码分组链模式(CBC)(the default):对于每个待加密的密码块在加密前会先与前一个密码块的密文异或然后再用加密器加密。第一个明文块与一个叫初始化向量的数据块异或。
- 密文反馈模式 (CFB): CFB能够将块密文(Block Cipher)转换为流密文(Stream Cipher)
- 计数器模式(CTR):完全的流模式。将瞬时值与计数器连接起来,然后对此进行加密产生密钥流的一个密钥块,再进行XOR操作
- 输出反馈模式(OFB):密码算法的输出(指密码key而不是密文)会反馈到密码算法的输入中,通过将明文分组和密码算法的输出进行XOR来产生密文分组。
- 电码本模式(ECB) : 将整个明文分成若干段相同的小段,然后对每一小段进行加密。
And CryptoJS supports the following padding schemes:
- Pkcs7 (the default)
- Iso97971
- AnsiX923
- Iso10126
- ZeroPadding
- NoPadding
而填充:拿ECB模式举例:加密时,如果明文不足16的倍数, 会填充为16的倍数。
// padding填充采用默认的Pkcs7 (the default) crypto 的mode默认:CBC (the default)
var decrypted = CryptoJS.AES.decrypt(secretText, key, {
iv: '', // 设置偏移量
mode: CryptoJS.mode.ECB, // 设置模式
padding: CryptoJS.pad.AnsiX923 // 设置填充
});