首页 > 解决方案 > Migration from mcrypt_encrypt() to openssl_encrypt()

问题描述

I have forced to migrate from PHP 5.6 to 7.0+, everything is fine except the mcrypt_encrypt(), it was deprecated already as stated in php.net.

Here's my code

$json = array(
    'Amount' => $amount
);

$data = json_encode($json);

function encrypt($data, $secret) 
{ 
    //Generate a key from a hash 
    $key    = md5(utf8_encode($secret), true); 
    $data2  = utf8_encode($data); 
    $iv     = utf8_encode("jvz8bUAx"); 

    //Take first 8 bytes of $key and append them to the end of $key. 
    $key .= substr($key, 0, 8); 

    //Pad for PKCS7 
    $blockSize = mcrypt_get_block_size('tripledes', 'cbc'); 

    //Encrypt data 
    $encData = mcrypt_encrypt('tripledes', $key, $data2, MCRYPT_MODE_CBC, $iv); 

    return urlencode(base64_encode($encData)); 
} 

I want to replace the deprecated lines with openssl_encrypt.

function encrypt($data, $secret) 
{ 
    //Generate a key from a hash 
    $key    = md5(utf8_encode($secret), true); 
    $data   = utf8_encode($data); 
    $iv     = utf8_encode("jvz8bUAx"); 

    $method = 'AES-256-CBC';

    $encrypted = openssl_encrypt($data, $method, $key, OPENSSL_RAW_DATA, $iv);

    $encrypted = base64_encode($iv . $encrypted);

    return $encrypted;
} 

Error:

IV passed is only 8 bytes long, cipher expects an IV of precisely 16 bytes, padding with \0

What I am missing?

UPDATE: Adding decryption part

 function decrypt($data, $secret) 
    { 
    //Generate a key from a hash 
    $data = urldecode($data); 
    $iv    = utf8_encode("jvz8bUAx"); 
    $key   = md5(utf8_encode($secret), true); 

    // Take first 8 bytes of $key and append them to the end of $key. 
    $key .= substr($key, 0, 8); 

    $data3 = base64_decode($data); 

    return $data4 = mcrypt_decrypt('tripledes', $key, $data3, MCRYPT_MODE_CBC, $iv); 

} 

标签: phpopenssl

解决方案


Updated

So what you are looking for is the des-ede3-cbc Openssl algorithm.

A convenient way to get a list of all your openssl algo's that are on your server is to run:

 print_r(openssl_get_cipher_methods(TRUE));

This will generate a list that makes for a good reference.

It looks like there was a padding issue as well. Mcrypt adds padding during the encryption routine and the Openssl does not. So you have to add padding on the encryption side for the Openssl. We also need to force the no_padding in the openssl functions.

These functions should work for you now.

function encryptNew($data, $secret){

  //Generate a key from a hash
  $key    = md5(utf8_encode($secret), true);
  $data   = utf8_encode($data);
  $iv     = utf8_encode("jvz8bUAx");

  //Take first 8 bytes of $key and append them to the end of $key.
  $key .= substr($key, 0, 8); //You key size has to be 192 bit for 3DES.

  $method = 'des-ede3-cbc'; //<----Change you method to this...

  //Mcrypt adds padding inside the function.  Openssl does not. So we have to pad the data.
  if (strlen($data) % 8) {

    $data = str_pad($data, strlen($data) + 8 - strlen($data) % 8, "\0");

  }

  $encrypted = openssl_encrypt($data, $method, $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $iv); //Force zero padding.

  $encrypted = urlencode(base64_encode($encrypted)); //Added the urlencode.....

  return $encrypted;

}


function decryptNew($data, $secret){

  //$data = base64_decode(urldecode($data));//<--If you have raw data coming in this needs to be commented out. 
  $iv    = utf8_encode("jvz8bUAx");
  $key   = md5(utf8_encode($secret), true);

  // Take first 8 bytes of $key and append them to the end of $key.
  $key .= substr($key, 0, 8);

  $method = 'des-ede3-cbc';

  return openssl_decrypt($data, $method, $key, OPENSSL_RAW_DATA | OPENSSL_NO_PADDING, $iv); //Force zero padding.

}

Hope this helps.


推荐阅读