目标:简单的CryptoJS示例使用AES-128, ECB, 0-padding进行加密,解密。
见下面我的可运行示例。
输入文本为" us0378331005 - us- us -en"这是加密(希望AES-128与上述所有),然后解密(这不起作用)
text: US0378331005-USD-US-en
key: 11A1764225B11AA1
key length: 16
encrypted 951422f8ac8354acf23fbc
decrypted a5126fa0fc3cb4c39a4f3e637be98a73
var text = 'US0378331005-USD-US-en';
var key = '11A1764225B11AA1'; // to ensure AES-128 this has to be 16 bit
console.log('text:', text);
console.log('key:', key);
console.log('key length:', key.length );
text = CryptoJS.enc.Hex.parse(text);
key = CryptoJS.enc.Hex.parse(key);
var iv = CryptoJS.enc.Hex.parse("00000000000000000000000000000000");
var encrypted = CryptoJS.AES.encrypt(text, key, { iv: iv, mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.NoPadding });
encrypted = encrypted.ciphertext.toString(CryptoJS.enc.Hex);
console.log('encrypted', encrypted);
var decrypted = CryptoJS.AES.decrypt(encrypted, key, {iv: iv, mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.NoPadding });
console.log('decrypted', decrypted.toString() );
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/aes.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/md5.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/enc-hex.min.js"></script>
你的代码中有几个bug:
- 像ECB这样的块密码模式总是需要填充,如果明文的大小不对应于块大小的整数倍,就像上面的例子一样。实际上,应该抛出一个异常。然而,CryptoJS隐式地填充0x00值,执行加密,并将密文截断为原始明文的长度。这种处理是偶然的,(在我看来)甚至是一个bug。
作为修复,必须应用填充。由于您正在谈论0填充,您可能指的是0填充,即CryptoJS.pad.ZeroPadding
。注意pkcs# 7填充(默认)更可靠。 - 您正在使用十六进制编码器进行密钥导入,因此密钥的16个十六进制数字被转换为8字节的密钥,这不是有效的AES密钥(有效的AES密钥长度为16,24和32字节)。然而,由于一个错误,CryptoJS处理这个密钥大小,但产生一个不符合aes的结果。
作为修正,例如,32十六进制数字密钥必须与十六进制编码器一起用于AES-128。另一种与发布密钥一起工作的选择是Utf8编码器。 - 明文显然不是十六进制编码的,所以没有十六进制编码器可以应用。
作为修复Utf8编码器被使用。 - ECB模式不使用IV,即IV被忽略,因此可以省略。请注意,ECB模式是不安全的,因为它不使用IV。因此,应该应用带有IV的模式。
- 在解密过程中,
CryptoJS.AES.decrypt()
期望一个CipherParams
对象,但在当前代码中,十六进制编码的密文被传递。
解决方法是从十六进制编码的密文中创建一个CipherParams
对象并传递它,或者传递Base64编码的密文,CryptoJS隐式地将其转换为CipherParams
对象。 - 解密数据的Utf8解码缺失。 固定代码:
var text = 'US0378331005-USD-US-en';
var key = '11A1764225B11AA1';
console.log('text:', text);
console.log('key:', key);
console.log('key length:', key.length );
// Fix: Use the Utf8 encoder
text = CryptoJS.enc.Utf8.parse(text);
// Fix: Use the Utf8 encoder (or apply in combination with the hex encoder a 32 hex digit key for AES-128)
key = CryptoJS.enc.Utf8.parse(key);
// Fix: Apply padding (e.g. Zero padding). Note that PKCS#7 padding is more reliable and that ECB is insecure
var encrypted = CryptoJS.AES.encrypt(text, key, { mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.ZeroPadding });
encrypted = encrypted.ciphertext.toString(CryptoJS.enc.Hex);
console.log('encrypted', encrypted);
// Fix: Pass a CipherParams object (or the Base64 encoded ciphertext)
var decrypted = CryptoJS.AES.decrypt({ciphertext: CryptoJS.enc.Hex.parse(encrypted)}, key, {mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.ZeroPadding });
// Fix: Utf8 decode the decrypted data
console.log('decrypted', decrypted.toString(CryptoJS.enc.Utf8));
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.min.js"></script>