5

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.

Artjom B.
  • 61,146
  • 24
  • 125
  • 222
Ernis
  • 645
  • 11
  • 22

1 Answers1

8

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.

Artjom B.
  • 61,146
  • 24
  • 125
  • 222
  • thank you for the answer, i'll try this tomorrow, the IV isn't static and is being sent together with the encrypted value, I just wanted to make everything as static as possible for this example. – Ernis Jul 13 '17 at 20:08
  • Yes that was it, thank you, for clarifying, that PHP was truncating the key :) – Ernis Jul 14 '17 at 05:10