Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does CryptoJS get an IV when none is specified?

When using CryptoJS.AES.encrypt how does it come up with an Initialization Vector if the third argument is not passed to the function? Is there a way to get it out of the encrypted string?

The reason I need this is I need to decrypt something CryptoJS.AES.encrypt returned using Lua, but I only have the key that was provided.

like image 588
warspyking Avatar asked Feb 18 '16 03:02

warspyking


People also ask

What is IV in CryptoJS?

In case of AES-256 - block size is, obviously, 256 bits, which is 32 bytes, which is exactly what you get by CryptoJS. enc. Base64. parse() of 22 byte Base64 string. According to specification and algorithm, IV is exactly block size length, which is 32 bytes with AES-256.

What is secret passphrase in CryptoJS?

It means that the key (secret passphrase) used to encrypt and decrypt is the same. So, it's security relies mostly in keeping the key secure. If someone obtains the key, they will be able to decrypt anything encrypted with that passphrase.

What encryption does CryptoJS use?

CryptoJS supports AES-128, AES-192, and AES-256. It will pick the variant by the size of the key you pass in. If you use a passphrase, then it will generate a 256-bit key. DES is a previously dominant algorithm for encryption, and was published as an official Federal Information Processing Standard (FIPS).

Do you need the same IV to decrypt?

Yes, you must provide the same IV for encryption and decryption.


1 Answers

CryptoJS' CryptoJS.<BlockCipher>.encrypt has two modes of encryption.

  1. If you pass in a key that is not a string, but rather a WordArray (CryptoJS's internal representation format for binary data), the key is taken as-is. This mode expects an IV for all modes of operation except ECB, which doesn't use an IV, so you don't have to specify one. If no IV is passed, it will default (through some JavaScript magic) to a zero filled IV (consisting of a full block of 0x00 bytes).

  2. If you pass in a "key" that is a string, it will assume the "key" is a password. In order to derive a key from the password, it uses the OpenSSL-compatible derivation function EVP_BytesToKey. This mode generates a new 8 byte random salt and uses it along with the password to generate a key and IV. Even if you explicitly pass in an IV, it won't be used.

     CryptoJS.AES.encrypt(msg, password).toString()
    

    results in a Base64-encoded ciphertext that contains the string "Salted__" at the beginning followed by the 8 byte salt and the actual ciphertext. You can explicitly split this before use with:

     var ct = CryptoJS.AES.encrypt(msg, password);
     var saltHex = ct.salt.toString();     // random salt
     var ctHex = ct.ciphertext.toString(); // actual ciphertext
     var ivHex = ct.iv.toString();         // generated IV
    

    If you need to recreate the same key derivation. Have a look at the code and the specification.

    Keys should have high entropy and be indistinguishable from random noise, which makes it hard for them to be brute-forced. The above mentioned EVP_BytesToKey is not secure, because MD5 hashing is very fast, which enables an attacker to brute-force the password. You either need to use a really long password (20-30 characters) or use an appropriate key derivation function such as PBKDF2, which CryptoJS provides.

like image 66
Artjom B. Avatar answered Oct 24 '22 04:10

Artjom B.