How to migrate from mcrypt to openssl with backward compatibility.
In my case I used Blowfish in ECB mode. The task was to decrypt data with openssl_decrypt, encrypted by mcrypt_encrypt and vice versa. It was obvious for a first sight. But in fact openssl_encrypt and mcrypt_encript give different results in most cases.
Investigating the web I found out that the reason is in different padding methods. And for some reasons openssl_encrypt behave the same strange way with OPENSSL_ZERO_PADDING and OPENSSL_NO_PADDING options: it returns FALSE if encrypted string doesn't divide to the block size. To solve the problem you have to pad your string with NULs by yourself.
The second question was the key length. Both functions give the same result if the key length is between 16 and 56 bytes. And I managed to find that if your key is shorter than 16 bytes, you just have to repeat it appropriate number of times.
And finally the code follows which works the same way on openssl and mcrypt libraries.
<?php
function encrypt($data, $key)
{
$l = strlen($key);
if ($l < 16)
$key = str_repeat($key, ceil(16/$l));
if ($m = strlen($data)%8)
$data .= str_repeat("\x00", 8 - $m);
if (function_exists('mcrypt_encrypt'))
$val = mcrypt_encrypt(MCRYPT_BLOWFISH, $key, $data, MCRYPT_MODE_ECB);
else
$val = openssl_encrypt($data, 'BF-ECB', $key, OPENSSL_RAW_DATA | OPENSSL_NO_PADDING);
return $val;
}
function decrypt($data, $key)
{
$l = strlen($key);
if ($l < 16)
$key = str_repeat($key, ceil(16/$l));
if (function_exists('mcrypt_encrypt'))
$val = mcrypt_decrypt(MCRYPT_BLOWFISH, $key, $data, MCRYPT_MODE_ECB);
else
$val = openssl_decrypt($data, 'BF-ECB', $key, OPENSSL_RAW_DATA | OPENSSL_NO_PADDING);
return $val;
}
$data = 'my secret message';
$key = 'dontsay';
$c = encrypt($data, $key);
$d = decrypt($c, $key);
var_dump($c);
var_dump($d);
?>
Gives:
string(32) "SWBMedXJIxuA9FcMOqCqomk0E5nFq6wv"
string(24) "my secret message\000\000\000\000\000\000\000"