0
votes

I can AES-256 CBC encrypt a string in PHP or Ruby (using the gem symmetric-encryption) and get the same result.

<?php
openssl_encrypt(
  'Hello!', 'aes-256-cbc', '1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF', 0, '1234567890ABCDEF1234567890ABCDEF'
); // => 'BAd5fmmMTvRE4Ohvf3GpCw=='
ruby_cipher = SymmetricEncryption::Cipher.new(key: "1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF", iv: "1234567890ABCDEF1234567890ABCDEF", cipher_name: 'aes-256-cbc')
ruby_cipher.encrypt("Hello!") # => "BAd5fmmMTvRE4Ohvf3GpCw=="

But I fail to decrypt the same string with Javascript, using CryptoJS. As far as I can interpret the documentation:

var encrypted = CryptoJS.AES.encrypt("Message", key, { iv: iv });

var decrypted = CryptoJS.AES.decrypt("Message", key, { iv: iv });

Check out my failed attempt in my jsfiddle or here:

var key            = CryptoJS.enc.Hex.parse("1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF");
var iv             = CryptoJS.enc.Hex.parse"1234567890ABCDEF1234567890ABCDEF");

var ruby_encrypted = "BAd5fmmMTvRE4Ohvf3GpCw==";                            // Output from the Ruby encryption
var js_encrypted   = CryptoJS.AES.encrypt("Hello!", key, { iv: iv });       // Test to confirm that CryptoJS can decrypt its own encrypted

var ruby_decrypted = CryptoJS.AES.decrypt(ruby_encrypted, key, { iv: iv }); // Object { words: Array[4], sigBytes: -129 }
var js_decrypted   = CryptoJS.AES.decrypt(js_encrypted, key, { iv: iv });   // Object { words: Array[4], sigBytes: 6 }

console.log(ruby_decrypted.toString(CryptoJS.enc.Utf8));                    //
console.log(js_decrypted.toString(CryptoJS.enc.Utf8));                      // Hello!

Any idea why the decryption fails?

1
Btw, I clarified my answer a little bit for how OpenSSL behaves.Artjom B.

1 Answers

0
votes

PHP and Ruby take the key and IV as a binary string. They don't assume that it is Hex-encoded which means that only the first 32 characters of your 64 character key will be used. OpenSSL silently uses only the number of bytes it needs and doesn't throw an error (which it should in this case).

You probably want something like this in CryptoJS:

var key    = CryptoJS.enc.Utf8.parse("1234567890ABCDEF1234567890ABCDEF");
var iv     = CryptoJS.enc.Utf8.parse("1234567890ABCDEF");

So, although this key has 256 bits in it, the security is actually only 128 bits, because each character has only 4 bit in a Hex-encoded string.