Search code examples
javascriptencryptioncryptographyaescryptojs

CryptoJS AES pattern always ends with =


I'm using CryptoJS to encrypt some usernames and passwords, it's working well enough I think.

But I have some questions regarding the encrypted data plaintext.

  1. No matter what the key or data is it always starts with "U2FsdGVkX1...".
  2. The encrypted data changes constantly even if the input data remains the same as shown below:

U2FsdGVkX1/BshMm2v/DcA6fkBQGPss6xKa9BTyC8g0= U2FsdGVkX1/uc5OTSD7CfumdgqK1vN2LU4ISwaQsTQE= U2FsdGVkX1/8OOLOTZlfunN4snEVUdF2ugiL7SeAluE= U2FsdGVkX1+c8j3l1NRBJDb1byHwOmmNSmbTci22vsA=

username_encrypted = CryptoJS.AES.encrypt(username, key);
password_encrypted = CryptoJS.AES.encrypt(password, key);
console.log(username_encrypted.toString());
console.log(password_encrypted.toString());
console.log(CryptoJS.AES.decrypt(username_encrypted, key).toString(CryptoJS.enc.Utf8));
console.log(CryptoJS.AES.decrypt(password_encrypted, key).toString(CryptoJS.enc.Utf8));

Is this the way it is supposed to work or am I doing something wrong? Because on some online AES encryption sites I get very different results, encrypted data not changing all the time for one.


Solution

  • That's correct. CryptoJS uses the OpenSSL proprietary format. If it uses a salted password to derive a key, it has a magic value in front. E.g. your first base64 translates into

     53616C7465645F5F C1B21326DAFFC3700E9F9014063ECB3AC4A6BD053C82F20D
    

    in hex. Connoisseurs will immediately recognize the first 8 bytes as being ASCII,

     Salted__ | C1B21326DAFFC370 0E9F9014063ECB3AC4A6BD053C82F20D
    

    So what you have is first a 8 byte magic, then an 8 byte salt, then the ciphertext.

    The actual key and IV are derived from the key in your code (which is actually interpreted as being a passphrase). As the salt is always random, so are the derived key and IV. This is how it should be as otherwise you could distinguish plaintext that start with (or is fully identical) to other plaintext.