Search code examples
javascriptphpaescryptojs

AES Encryption with CryptoJS and PHP


I want to implement AES encryption using JavaScript. Used AES CBC Mode. I have managed to do it in PHP. It looks like:

 public function encrypt($value) {
        if (empty($value)) {
          return $value;
        }
        $value = Unicode::convertToUtf8($value, 'UTF-8');
        if ($key = $this->getEncryptionKey()) {
          // Generates from key 1st 16 bytes.
          $iv = mb_substr($key, 0, 16);
          //encrypt message with key
          $message = openssl_encrypt($value, 'AES-256-CBC', $key, OPENSSL_RAW_DATA, $iv);
          return base64_encode($message);
        }
    }

    public function getEncryptionKey() {
        $key = 'secret';
        $key = Unicode::convertToUtf8($key, 'UTF-8');

        // Make sure the key is the correct size.
        if (strlen($key) < 32) {
          $key = str_pad($key, 32, "\0");
        }

        if (strlen($key) > 32) {
          $key = mb_substr($key, 0, 32);
        }

        return $key;
    }

If I give $value = retest2; it gives me ukUCH0SvgdmM8vTqQumAVg== output

I know it's right, I tried it using C# as well got the same result. But when I try to replicate this using JavaScript, I wasn't able to produce same PHP's output. Below is the javascript code that I have tried:

const message = utf8.encode('retest2');
const password = utf8.encode('secret').padEnd(32, '\0');
const key =  CryptoJS.enc.Hex.parse(password);
const iv =  CryptoJS.enc.Hex.parse(password.substring(0, 16));

const encrypted = CryptoJS.AES.encrypt(message, key, {
    iv: iv
});
console.log(btoa(encrypted.toString()));

Using the same value I get dzd4bjNwenduQT09. I have also read other similar questions asked on the same topic here, but I can't seem to figure out where I am going wrong? Thanks!


Solution

  • As @symcbean said,

    You shouldn't be using the key or data derived from it as your initialization vector.

    I assume, you have no option and you have to use key or data derived from it as your initialization vector.

    A few months ago, I had the exact same situation and I did something like this,

    const message = 'retest2';
    let password = 'secret';
    if (password.length < 32) {
        password = password.padEnd(32, '\0');
    }
    const iv = CryptoJS.enc.Utf8.parse(password.substring(0, 16));
    password = CryptoJS.enc.Utf8.parse(password);
    const encrypted = CryptoJS.AES.encrypt((message), (password), {
        iv: iv
    });
    console.log(CryptoJS.enc.Base64.stringify(encrypted.ciphertext));