Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHP openssl_encrypt in JavaScript with CryptoJS

I have a problem generating the same ciphertext in JavaScript as provided in a third party PHP server. The server side uses a simple one-liner to generate a key, but I can't find a way to do the same in my JavaScript client.

I decided to use the CryptoJS library, from other SO answers , and I did generate a ciphertext but it was different that the one from a PHP server.

PHP encryption:

echo openssl_encrypt("5905","AES-256-CBC","FbcCY2yCFBwVCUE9R+6kJ4fAL4BJxxjdRcqy5rHVLwU=",NULL,"e16ce913a20dadb8");
// phgygAJB3GA0sa4D9k/d8A==

I have tried several solutions from Stack Overflow which failed to create the same ciphertext.

Also, the parameter "AES-256-CBC" in the PHP one-liner bothers me: I know what AES is, but I have no idea what those 256 or CBC parts are, and I don't know where to set those on the CryptoJS side.

My current attempt:

var key = 'FbcCY2yCFBwVCUE9R+6kJ4fAL4BJxxjdRcqy5rHVLwU=';
var iv = 'e16ce913a20dadb8';
var encrypted = CryptoJS.AES.encrypt("5905", CryptoJS.enc.Hex.parse(key), { iv: CryptoJS.enc.Hex.parse(iv) });
var r1 = encrypted.ciphertext.toString(); // def44f8822cfb3f317a3c5b67182b437
var r2 = CryptoJS.enc.Base64.stringify(encrypted.ciphertext) // 3vRPiCLPs/MXo8W2cYK0Nw==

My guess is that I am missing "256" and "CBC" parameters somewhere in JavaScript.

like image 802
Ernis Avatar asked Jul 13 '17 13:07

Ernis


1 Answers

Your "key" is 44 characters long which also equates to 44 bytes in PHP. This is not a valid key size. AES only supports 16, 24 and 32 byte keys. Anyway, this "key" will be truncated to 32 byte. So your actual key in PHP is:

"FbcCY2yCFBwVCUE9R+6kJ4fAL4BJxxjd"

Your IV is 16 characters (and byte) long, so it has the correct length and used as-is.

This is also why you can treat the key and IV in CryptoJS as strings:

CryptoJS.AES.encrypt("5905", CryptoJS.enc.Utf8.parse(key), { iv: CryptoJS.enc.Utf8.parse(iv) });

But the correct way would be to decode the key from Base64 and generate a proper IV which is twice as long when encoded to Hex. It should be decoded from Hex before use.

The IV must be unpredictable (read: random). Don't use a static IV, because that makes the cipher deterministic and therefore not semantically secure. An attacker who observes ciphertexts can determine when the same message prefix was sent before. The IV is not secret, so you can send it along with the ciphertext. Usually, it is simply prepended to the ciphertext and sliced off before decryption.

like image 142
Artjom B. Avatar answered Nov 14 '22 22:11

Artjom B.