Encrypting with PHP; decrypting with CryptoJS

2.1k views Asked by At

I am having some trouble decrypting data using CryptoJS that was encrypted in PHP. Maybe somebody can advise me on where I am going wrong?

I am encrypting as follows:

  1. Get hashed password
  2. Take substring of (0,16) as the key
  3. Encrypt (MCRYPT_RIJNDAEL_128)
  4. Encode ciphertext as base64

When decrypting I do the same:

  1. Get hashed password
  2. Take substring of (0,16) as the key
  3. Base64 decode the ciphertext
  4. Decrypt

PHP:

public function encrypt($input, $key) {
    $size = mcrypt_get_block_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_ECB);
    $input = $this->_pkcs5_pad($input, $size);
    $td = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_ECB, '');
    $iv = mcrypt_create_iv (mcrypt_enc_get_iv_size($td), MCRYPT_RAND);
    mcrypt_generic_init($td, $key, $iv);
    $data = mcrypt_generic($td, $input);
    mcrypt_generic_deinit($td);
    mcrypt_module_close($td);
    $data = base64_encode($data);
    return $data;
}

JavaScript:

function decrypt(ciphertext, hashedPsw) {
        var key =  hashedPsw.substring(0, 16);

        var key = CryptoJS.enc.Hex.parse(key);

        var options = { mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.Pkcs7, keySize:128 / 32 };

        ciphertext = CryptoJS.enc.Base64.parse(ciphertext);
        var decrypted = CryptoJS.AES.decrypt(ciphertext, key);
        return decrypted;
    }
2

There are 2 answers

1
JB2 On BEST ANSWER

I just discovered the answer in a previous thread: Turns out that the problem was the key encoding.

9
Artjom B. On

The CryptoJS decrypt function expects an object that contains a WordArray and not the WordArray itself, so you need to use:

var decrypted = CryptoJS.AES.decrypt({ ciphertext: ciphertext }, key, options);

You also need to pass the options to the decrypt function. Otherwise, CryptoJS won't know that you wanted to use ECB mode.


Security

Don't use ECB mode! It's not semantically secure. You should at the very least use CBC mode with a random IV. The IV doesn't need to be secret, so you can simply prepend it to the ciphertext.

Then you should authenticate your ciphertexts. This can be done with authenticated modes like GCM or EAX, but they are not provided by mcrypt or CryptoJS. The next best thing is to use an encrypt-then-MAC scheme where you use a strong keyed hash function like HMAC-SHA256 over the ciphertext to make it infeasible for an attacker to change ciphertexts without you knowing it.