9

I'm extremely frustrated about a lot of time wasted trying to encrypt something with CryptoJS, after some time, I have realized that every time I encrypt the result is different with the same input! How can this be possible?

This is my code and you can check is true: https://jsfiddle.net/z5dg623q/1/

<script>
    function encrypt() {
        document.getElementById("stringOutput").value = CryptoJS.AES.encrypt("lorem ipsum", "hAPgT2mj0ZzD1epO").toString();
    }
</script>

<textarea id="stringOutput" cols="100" rows="10"></textarea>
<button type="button" onClick="encrypt()">Encrypt that!</button>

Can anybody help me?

Artjom B.
  • 61,146
  • 24
  • 125
  • 222
Jose Ignacio Hita
  • 874
  • 1
  • 10
  • 17
  • 7
    And you are complaining about that? You should dance and praise it! Thank God the output is different!!! Have you ever imagined what it is like encoding `abc` 20 times and the output being all the same? You should celebrate that it isn't! – Ismael Miguel Aug 05 '15 at 15:01
  • 9
    The mathematicians worked so hard on that... – EugenSunic Aug 05 '15 at 15:04
  • Also, notice that encoding anything anything will result in `U2FsdGVkX1` as the common part. I've encoded at least 30 different things. If you want something to be always the same, you have this bit. – Ismael Miguel Aug 05 '15 at 15:05
  • `atob('U2FsdGVkX1') == 'Salted_'`. [Fiddle without base64](https://jsfiddle.net/z5dg623q/3/). – Siguza Aug 05 '15 at 15:22
  • Its okay if its different... check this fiddle: https://jsfiddle.net/beay7nds/ – Glen Keane Aug 05 '15 at 15:26
  • The ciphertext being different each time is not a problem. All that matters is that using the same key for decryption should yield the original plaintext. See [a modified version](https://jsfiddle.net/z5dg623q/4/) of your Fiddle. – manish Aug 06 '15 at 03:56

2 Answers2

10

When you pass two strings into CryptoJS.<Cipher>.encrypt() you tell CryptoJS to use password-based encryption. It will assume that the first string is UTF-8 encoded data and the second one is a password which will be sent through MD5 to get a 256-bit key and a 128-bit IV. This done by the so-called EvpKDF (see 1 and 2) with a random salt (see here).

This means that in every invocation the code will generate a new random salt which is then used to derive a different key and IV every time which results in a different ciphertext every time. This property is called semantic security and prevents for example attackers to determine whether the plaintexts are equal only by looking at the ciphertexts. This is sometimes a crucial security property.

When you call toString() on the encrypt() result, it will serialize the ciphertext into an OpenSSL-compatible format which includes the salt. So you only need the password and this string to decrypt it.

When you try to decrypt it, the salt in the ciphertext and your password are used to derive the same key and IV that where used for encryption. Therefore it can recover the original plaintext. If a wrong password is used, the result will either be empty or it will be gibberish.

Artjom B.
  • 61,146
  • 24
  • 125
  • 222
0

I faced the same issue. This is simply due to us not knowing the working of algorithm. Simply put, the key and IV are different for each call of the encrypt method, as mentioned in the above answer by Artjom B.

To ensure the exact same value for each iteration - you can refer to this answer https://stackoverflow.com/a/47096284/4098272

Alternatively, you can use the SHA3 function and compare the two Hash values.

Jonathan Cardoz
  • 874
  • 9
  • 12