I need to encrypt some data and have it decrypted on a later point in time. The data is tied to specific users. I've gathered two possible solutions...
1: The first one is derived from the official docs (example #1 @ http://php.net/manual/en/function.mcrypt-encrypt.php):
function encrypt($toEncrypt)
{
global $key;
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
return base64_encode($iv . mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $toEncrypt, MCRYPT_MODE_CBC, $iv));
}
function decrypt($toDecrypt)
{
global $key;
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC);
$toDecrypt = base64_decode($toDecrypt);
return rtrim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, substr($toDecrypt, $iv_size), MCRYPT_MODE_CBC, substr($toDecrypt, 0, $iv_size)));
}
The key is generated once using:
pack('H*', bin2hex(openssl_random_pseudo_bytes(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC))));
1.1: I've noticed that the encrypted result always ends in two equal signs ('=='). Why? - Using bin2hex() and hex2bin() in encrypt() and decrypt() instead of base64_encode()/base64_decode() respectively does not yield these results.
1.2: Will using bin2hex()/hex2bin() have any consequence on the outcome (other than length)?
1.3: There seems to be some discussion whether or not to call a trim-function on the return result when decrypting (this applies to the solution below as well). Why would this be necessary?
2: Second solution comes from here, Stackoverflow (https://stackoverflow.com/questions/9262109/php-simplest-two-way-encryption):
function encrypt($key, $toEncrypt)
{
return base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, md5($key), $toEncrypt, MCRYPT_MODE_CBC, md5(md5($key))));
}
function decrypt($key, $toDecrypt)
{
return rtrim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, md5($key), base64_decode($toDecrypt), MCRYPT_MODE_CBC, md5(md5($key))), "\0");
}
I'm aware that both approaches to the key handling is interchangeable, I purposely made them different in that respect in order to highlight possible solutions, please feel free to mix and match.
Personally I feel that the first one offers tighter security since both key and initialization vector is properly randomized. The second solution however, does offer some form of non-predictability since the key is unique for each piece of encrypted data (even though it suffers under the weak randomization of md5()). The key could for example be the user's name.
3: So, which one is preferable? I'm slightly in the dark since the Stackoverflow answer got a whopping 105 votes. Other thoughts, tips?
4: Bonus question!: I'm not incredibly brainy on server security aspects, but obviously gaining access to the PHP files would expose the key, which as a direct result, would render the encryption useless, assuming the attacker also has access to the DB. Is there any way to obscure the key?
Thank you for reading and have a nice day!