Search code examples
phpmcryptphp-openssl

Replacing mcrypt_encrypt using MCRYPT_RIJNDAEL_256 with openssl_encrypt


As you guys probably know, the extension mcrypt will be deprecated on php 7.1.

I use to maintain a "legacy" application that I want to migrate eventually to this version so I ran the tests and verified that I can't get 100% of coverage anymore, since there's a piece of code that use the following code:

$key = 'sA*(DH';

// initialization vector
$iv = md5(md5($key));
$output = base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, md5($key), $string,     MCRYPT_MODE_CBC, $iv));

I tried to port this piece of code to openssl_encrypt using this code

$key = md5('sA*(DH');
$iv = md5($key);
echo base64_encode(openssl_encrypt($data, "aes-256-cbc", $key, OPENSSL_RAW_DATA, $iv));

But I have 2 problems with this:

  1. The IV lenght should be 16 chars (and md5 gives me 32), so I get a PHP Warning
  2. The output it's not the same (even if I truncate to 16 chars)

Anyone had similar problems (or know how to fix it?)

BTW: I'm using the dev master version of PHP (supposed to be 7.1.0 alpha 3).


Solution

  • Yet another tested solution taking and returning ANSI text to replace Mcrypt function with the openssl_encrypt() and openssl_decrypt():

    //Return encrypted string
    public function stringEncrypt ($plainText, $cryptKey = '7R7zX2Urc7qvjhkr') {
    
      $cipher   = 'aes-128-cbc';
    
      if (in_array($cipher, openssl_get_cipher_methods()))
      {
        $ivlen = openssl_cipher_iv_length($cipher);
        $iv = openssl_random_pseudo_bytes($ivlen);
        $ciphertext_raw = openssl_encrypt(
          $plainText, $cipher, $cryptKey, $options=OPENSSL_RAW_DATA, $iv);
        $hmac = hash_hmac('sha256', $ciphertext_raw, $cryptKey, $as_binary=true);
        $encodedText = base64_encode( $iv.$hmac.$ciphertext_raw );
      }
    
      return $encodedText;
    }
    
    
    //Return decrypted string
    public function stringDecrypt ($encodedText, $cryptKey = '7R7zX2Urc7qvjhkr') {
    
      $c = base64_decode($encodedText);
      $cipher   = 'aes-128-cbc';
    
      if (in_array($cipher, openssl_get_cipher_methods()))
      {
        $ivlen = openssl_cipher_iv_length($cipher);
        $iv = substr($c, 0, $ivlen);
        $hmac = substr($c, $ivlen, $sha2len=32);
        $ivlenSha2len = $ivlen+$sha2len;
        $ciphertext_raw = substr($c, $ivlen+$sha2len);
        $plainText = openssl_decrypt(
          $ciphertext_raw, $cipher, $cryptKey, $options=OPENSSL_RAW_DATA, $iv);
      }
    
      return $plainText;
    }
    

    More read in openssl documentation