本文介绍了使用 AES/ECB/NoPadding 和 base 64 和 crypto-js 库实现的不正确的解密字符串的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用 crypto-js 加密/解密以下数据并获得意外结果.

I am trying to encrypt/decrypt the below data using crypto-js and getting unexpected results.

库: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 数据"

Current output: Error Message "Malformed UTF-8 data"

代码调试链接:https://stackblitz.com/edit/aes-ecb-bhardwaj

注意:如果我使用 Pkcs7 和 ZeroPadding 等其他填充,它似乎工作正常.

推荐答案

实际上,如果禁用填充,则长度不是块大小整数倍的明文无法使用 AES-ECB 进行加密.因此,(至少)必须隐式更改这些条件之一,以便完全可以进行加密.

Actually, a plaintext whose length is not an integer multiple of the blocksize cannot be encrypted with AES-ECB if padding is disabled. Therefore, (at least) one of these conditions must be changed implicitly so that encryption is possible at all.

CryptoJS 使用 WordArray 数据类型,封装了一个字数组 (words) 和该数组中的有效字节数 (sigBytes).事实证明,在所描述的条件下执行的加密在单词数组中生成 相同 密文作为显式填充 0 值的明文或作为内置零填充.但是,对于第一种情况,sigBytes 中不考虑用于加密的 0 值,而在后两种情况下会发生这种情况:

CryptoJS uses the WordArray data type that encapsulates a word array (words) and the number of significant bytes (sigBytes) in that array. It turns out that the encryption performed under the described conditions produces the same ciphertext in the word array as a plaintext explicitly padded with 0-values or as the builtin Zero padding. However, the 0-values used for encryption are not taken into account in sigBytes for the first case, whereas this happens for the last two cases:

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],但是因为在sigBytes中没有考虑0-values [1216989226, 1168217134, 0, 0] 被有效解密,使得解密后的明文与原始明文匹配:

However, during decryption only the significant bytes (more precise ceil(sigBytes/4) words) are taken into account, so that effectively a different ciphertext is decrypted than the original one. In the above example the ciphertext contained in the word array is [1216989226, 1168217134, 91026943, 1588012560], but because of the not considered 0-values in sigBytes [1216989226, 1168217134, 0, 0] is effectively decrypted, so that the decrypted plaintext does not match the original plaintext:

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);
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/crypto-js.min.js"></script>

这可能是 CryptoJS 中的一个错误.对于禁用填充的块密码,sigBytes 应该是块大小的整数倍(如果没有使用流密码模式).如果不满足此条件,则应将其作为错误处理,例如除了一个例外.这适用于加密的明文和解密的密文.

This is probably a bug in CryptoJS. For a block cipher with padding disabled, sigBytes should be an integer multiple of the blocksize (if no stream cipher mode is used). If this condition is not met, it should be handled as an error, e.g. with an exception. This applies to both, the plaintext for encryption and the ciphertext for decryption.

这篇关于使用 AES/ECB/NoPadding 和 base 64 和 crypto-js 库实现的不正确的解密字符串的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-31 09:22