我正在尝试使用crypto-js加密/解密以下数据并获得意外的结果。
库:https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/crypto-js.min.js
function encryptByAESECB(message, key) {
var keyHex = CryptoJS.enc.Utf8.parse(key);
var encrypted = CryptoJS.AES.encrypt(message, keyHex, {
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.NoPadding
});
return encrypted.toString();
}
function decryptByAESECB(ciphertext, key) {
var keyHex = CryptoJS.enc.Utf8.parse(key);
// direct decrypt ciphertext
var decrypted = CryptoJS.AES.decrypt({
ciphertext: CryptoJS.enc.Base64.parse(ciphertext)
}, keyHex, {
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.NoPadding
});
return decrypted.toString(CryptoJS.enc.Utf8);
}
var message = 'Message';
var key = '5401cae4-2c89-49';
var ciphertext = encryptByAESECB(message, key);
// ciphertext: 8dKft9vkZ4I=
console.info('ciphertext:', ciphertext);
var plaintext = decryptByAESECB(ciphertext, key);
// plaintext : Message
console.info('plaintext :', plaintext);
预期输出:"Message"
当前输出:错误消息“格式错误的UTF-8数据”
代码调试链接:https://stackblitz.com/edit/aes-ecb-bhardwaj
NOTE: If I am using other paddings like Pkcs7 and ZeroPadding it seems to be working fine.
实际上,如果禁用了填充,则长度不是块大小的整数倍的纯文本无法使用AES-ECB进行加密。因此,(至少)必须隐式更改这些条件之一,以便完全可以进行加密。
CryptoJS使用WordArray
数据类型封装单词数组(WordArray
)和该数组中的有效字节数(words
)。事实证明,在上述条件下执行的加密会在单词数组中生成same密文,作为显式填充sigBytes
值的纯文本或内置的零填充。但是,在第一种情况下,0
中未考虑用于加密的0
值,而在后两种情况下会发生这种情况:
sigBytes
function encryptAndPrint(message, padding){
var encrypted = CryptoJS.AES.encrypt(message, keyHex, {
mode: CryptoJS.mode.ECB,
padding: padding
});
console.log("words: " + encrypted.ciphertext.words);
console.log("sigBytes: " + encrypted.ciphertext.sigBytes);
}
var keyHex = CryptoJS.enc.Utf8.parse('5401cae4-2c89-49');
// Implicit padding (not considered in sigBytes)
var message = 'Message';
encryptAndPrint(message, CryptoJS.pad.NoPadding);
// Explicit padding (considered in sigBytes)
var message = 'Message\0\0\0\0\0\0\0\0\0';
encryptAndPrint(message, CryptoJS.pad.NoPadding);
// built-in Zero padding (considered in sigBytes)
var message = 'Message';
encryptAndPrint(message, CryptoJS.pad.ZeroPadding);
但是,在解密期间,[[仅”将考虑有效字节(更精确的<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/crypto-js.min.js"></script>
字),以便有效地解密与原始密文不同的密文。在上面的示例中,单词数组中包含的密文为ceil(sigBytes/4)
,但是由于未考虑[1216989226, 1168217134, 91026943, 1588012560]
中的0
值,因此sigBytes
被有效地解密,因此解密后的明文与not匹配原始的纯文本:
[1216989226, 1168217134, 0, 0]
function decryptAndPrint(ciphertext){
var decrypted = CryptoJS.AES.decrypt(
{ciphertext: ciphertext},
keyHex,
{mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.NoPadding}
);
console.log("Decrypted (hex): " + decrypted.toString(CryptoJS.enc.Hex));
}
var keyHex = CryptoJS.enc.Utf8.parse('5401cae4-2c89-49');
// Decryption: The last two words are ignored
var ciphertext = CryptoJS.lib.WordArray.create([1216989226, 1168217134, 91026943, 1588012560]);
ciphertext.sigBytes = 7;
decryptAndPrint(ciphertext);
// Proof: The result is identical if the last two words are explicitly set to an arbitrary value, e.g. 0.
var ciphertext = CryptoJS.lib.WordArray.create([1216989226, 1168217134, 0, 0]);
ciphertext.sigBytes = 7;
decryptAndPrint(ciphertext);
// The correct result, if padding is considered in sigBytes
var ciphertext = CryptoJS.lib.WordArray.create([1216989226, 1168217134, 91026943, 1588012560]);
ciphertext.sigBytes = 16;
decryptAndPrint(ciphertext);
这可能是中的错误。对于禁用填充的分组密码,CryptoJS
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/crypto-js.min.js"></script>
应为分组大小的整数倍(如果未使用流密码模式)。如果不满足此条件,则应将其视为错误,例如有一个例外。这既适用于加密的明文,也适用于解密的密文。