I am trying to use AES as cipher for an application I am building. I am using a JavaScript library (https://code.google.com/p/crypto-js/) to perform encryption and decryption with AES. When I perform decryption, this happens:

AES.decrypt(ct, right_key) == 'message decrypted !' //true

AES.decrypt(ct, wrong_key) == '' //true

The problem is that I am using this decryption in a process in which there shouldn't be any way to determine if the key was right or wrong. I would like something like this to happen:

log(AES.decrypt(msg, wrong_key)) // 'random string fsdijw'

So that the result is 'compliant' to the expected result but it's not the expected result, and there is no way to understand if the key was right or wrong depending on the result of the decryption. I asked my professor and he told me that AES is probably bad implemented in that library, but he didn't understand my problem so clearly.

I wonder if the behavior described in the first snippet of code is expected or actually AES has been bad implemented in that library. If it was expected, is there any other cipher algorithm that doesn't allow to understand if the key was right or wrong from the result of decryption?

  • $\begingroup$ It could be the case that this is desired behavior, if a mode is used that authenticates the data and not only encrypts it (doesn't look like it). Does your "wrong" key matches the requirements (i.e. has the required length)? $\endgroup$ – SEJPM Jan 18 '16 at 11:51
  • $\begingroup$ no, there are no specific informations about the key requirements. I would want that any key outputs a wrong result but compliant to the right result (a string), so that it is impossible to determinate if the key was right or wrong from the decryption process @SEJPM $\endgroup$ – Morrisda Jan 18 '16 at 11:56
  • $\begingroup$ With the key matching the requirements I meant, does your "wrong key" has the required length (i.e. 16, 24 or 32 bytes?). An yes, it is possible to do what you want to do, this appears to be a problem with the implementation. $\endgroup$ – SEJPM Jan 18 '16 at 11:59
  • $\begingroup$ Yes, i use key stretching (PBKDF2) before that, so even wrong keys have always the same length. So do you think is this a problem with the implementation ? $\endgroup$ – Morrisda Jan 18 '16 at 14:23

AES is a block cipher and would return wrong data when a wrong key is used. It only works on a single block of data (16 bytes). The default CBC mode of operation enables you to encrypt multiple blocks of data. The padding then enables you to encrypt plaintexts of arbitrary length. The padding has to be removed somehow after the decryption.

You're seeing a blank output, because your data is short and the padding removes more bytes than necessary. Here is how the default PKCS#7 padding is implemented in CryptoJS:

unpad: function (data) {
    // Get number of padding bytes from last byte
    var nPaddingBytes = data.words[(data.sigBytes - 1) >>> 2] & 0xff;

    // Remove padding
    data.sigBytes -= nPaddingBytes;

So, it looks at the last byte of the decrypted byte and removes as many bytes from the ciphertext. If data.sigBytes is negative, it would handle it like 0 bytes where decrypted. If your message is longer than 255 bytes, then the decryption is guaranteed to print something, but it won't be as long as the initial plaintext. If you always want to print something then you need to decrypt without padding.

I wouldn't call this implementation wrong, because PKCS#7 padding is specified for up to 256 padding bytes, but rather data.sigBytes -= Math.min(nPaddingBytes, blocksize); would have been probably better.

Zero padding might be better suited in your case, because it's highly unlikely that a decryption with a wrong key results in a plaintext that ends with many zero bytes at the end that have to be removed. But such as padding should not be used when there is a chance that you might encrypt a plaintext which ends in 0x00 bytes.

So that the result is 'compliant' to the expected result but it's not the expected result, and there is no way to understand if the key was right or wrong depending on the result of the decryption.

This is not generally possible with a block cipher. A decryption with wrong key can result in some arbitrary plaintext bytes that doesn't have to make up a string with valid ASCII or UTF-8 encoding and if you try to force it, you will get errors, which can be used to distinguish the correct key from a wrong key.

If you're always encoding the plaintext to Hex, then you can get away with using arbitrary keys.


| improve this answer | |
  • 1
    $\begingroup$ See this code example where it decrypts something despite having a wrong key. Also note that, it's probably easy to determine if a wrong key was used, when you can run some heuristic over the recovered plaintext to check for example if it is english text. So, this behavior will cost you more than it will give you. You should be using a proper authenticated mode which either gives the correct plaintext or fails without anything in between. $\endgroup$ – Artjom B. Jan 18 '16 at 13:11

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.