Search code examples
javascriptencryptioncryptographyaescryptojs

Output is different every time when the same text is encrypted with CryptoJS


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?


Solution

  • 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.