使用AES / ECB / NoPadding和带有crypto-js库的base 64实现的不正确的解密字符串

问题描述 投票:4回答:1

我正在尝试使用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.

javascript aes cryptojs ecb
1个回答
2
投票

实际上,如果禁用了填充,则长度不是块大小的整数倍的纯文本无法使用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>应为分组大小的整数倍(如果未使用流密码模式)。如果不满足此条件,则应将其视为错误,例如有一个例外。这既适用于加密的明文,也适用于解密的密文。
© www.soinside.com 2019 - 2024. All rights reserved.