为什么AES在线加密每次结果不一样(CryptoJS库)
编辑
2
2023-08-23
某次在使用AES在线加密网站的时候遇到了两个问题:
相同明文和密钥的情况下,每次加密结果不一致,但都可以正常解密出相同的明文。
密钥长度无需指定,甚至用空密钥也可以。
示例网站:在线AES加密 | AES解密 - 在线工具 (sojson.com)
密文内容会变,base64 编码,开头一段总是固定的字符。
虽然每次加密结果不一致,但开头的一段数据总是U2FsdGVkX1
,于是先解base64
查看有没有可读的内容。
密文总是以Salted__
开头,看来是加了盐,密文中应该包含了盐的信息。
查看网站代码,看样子是使用了一个叫做CryptoJS
的第三方库。
在npm
上能找到crypto-js
,可阅读代码。
cryptojs-npm
查看源码,文件cipher-core.js
第646行左右,parse函数的作用是解析出实际密文和salt值。以word(一个word是8个16进制,就是32个bit,4个字节)为单位将原密文分割为数组,ciphertextWords[0]
是0x53616c74
(Salt),ciphertextWords[1]
是0x65645f5f
(ed__),ciphertextWords[2]
和ciphertextWords[3]
就是盐值,剩下的就是实际的密文。
parse: function (openSSLStr) {
var salt;
// 先解 base64 编码
var ciphertext = Base64.parse(openSSLStr);
// 以 word 为单位分割成数组
var ciphertextWords = ciphertext.words;
// 判断开始是否是 Salted__
if (ciphertextWords[0] == 0x53616c74 && ciphertextWords[1] == 0x65645f5f) {
// 解析出盐值
salt = WordArray.create(ciphertextWords.slice(2, 4));
// 去掉开头和盐值,剩下的就是实际密文
ciphertextWords.splice(0, 4); //删除"salted__"+salt
ciphertext.sigBytes -= 16;
}
return CipherParams.create({ ciphertext: ciphertext, salt: salt });
}
十六进制转字符串
进一步阅读源码可知,盐值是随机生成,不需要指定盐值。同时有一个密钥派生函数,根据输入的字符串派生出符合长度要求的密钥,所以即使用户输入的密钥长度不满足条件,也是可以正常加密的。
- 0
- 0
-
分享