Skip to content Skip to sidebar Skip to footer

Incorrect Decrypted String Implemented Using Aes/ecb/nopadding And Base 64 With Crypto-js Library

I am trying to encrypt/decrypt the below data using crypto-js and getting unexpected results. Library: https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/crypto-js.min.js funct

Solution 1:

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 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:

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

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:

functiondecryptAndPrint(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 sigBytesvar ciphertext = CryptoJS.lib.WordArray.create([1216989226, 1168217134, 91026943, 1588012560]);
ciphertext.sigBytes = 16; 
decryptAndPrint(ciphertext);
<scriptsrc="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/crypto-js.min.js"></script>

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.

Post a Comment for "Incorrect Decrypted String Implemented Using Aes/ecb/nopadding And Base 64 With Crypto-js Library"