Preparing for removal of Mcrypt in PHP 7.2

Scrumplex picture Scrumplex · Mar 9, 2017 · Viewed 7.8k times · Source

So as time moves on mcrypt will go in PHP 7.2. Of course there is an alternative: openssl.

I find it difficult to switch from mcrypt to openssl, using AES 256 CBC and preserving IVs. I am sort of new to cryptography, so I don't really know everything, but I understand the basics.

Let's say I have the following code

function encrypt($masterPassword, $data) 
{
    $keySize = mcrypt_get_key_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC);
    $ivSize = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC);
    $iv = mcrypt_create_iv($ivSize, MCRYPT_DEV_URANDOM);
    $key = mb_substr(hash('SHA256', $masterPassword), 0, $keySize);
    $encrypted = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $data, MCRYPT_MODE_CBC, $iv);
    return base64_encode($iv . $encrypted);
}

function decrypt($masterPassword, $base64) 
{
    $keySize = mcrypt_get_key_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC);
    $ivSize = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC);
    $key = mb_substr(hash('SHA256', $masterPassword), 0, $keySize);
    $data = base64_decode($base64);
    $iv = substr($data, 0, $ivSize);
    $encrypted = substr($data, $ivSize, strlen($data));
    $decrypted = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, $encrypted, MCRYPT_MODE_CBC, $iv);
    return trim($decrypted);
}

How can I "convert" this code to use openssl insted of mcrypt?

Answer

Narf picture Narf · Mar 9, 2017

You can't convert it, because Rijndael-256 is not AES-256, and the OpenSSL extension doesn't ship with Rijndael-256 support.
AES-256 is Rijndael-128 with a 256-bit (32-byte) key.

Unfortunately, you'll have to re-encrypt all of your data.

Edit: Also, the scheme you're currently using has some problems:

  • It lacks authentication (HMACs are the easiest way to do it in PHP)
  • It lacks proper padding (mcrypt pads with zero bytes; you need something like PKCS#5 padding instead), which is required for block mode encryption to be safe.
  • It's not byte-safe (you're using mb_substr())

The good news is that OpenSSL will do PKCS#5 padding for you automatically, but you should go even further and use a solid encryption library like defuse/php-encryption.