I want to do simple encryption using PHP 5.5. By “simple” I mean I want to use native PHP functions. I have created this code that works, can it be improved? It's to encrypt/decrypt strings and binary files that are to be stored in a database and accessed via a website. Assume that it is done over SSL and that the password isn't hard-coded or stored anywhere on the web server.
Here's what I have (and it works). Is this secure? All the examples I found do not use PHP 5.5's hash_pbkdf2 function. I wanted a simple example that uses this.
Are there any downsides to using MCRYPT_MODE_CFB? Are 5000 iterations enough for PBKDF2 in this context?
// Check hash_pbkdf2 exists as it's not available < 5.5
if(function_exists('hash_pbkdf2') === false) {
// A fallback could be implemented here
exit('hash_pbkdf2() does not exist');
}
// Settings
$stringToEncrypt = 'This was encrypted'; // The plain text string to encrypt; binary files should be base64 encoded
$encryptionPassword = 'MyP@$$w0rd'; // The password; the only data that should be kept private
$pbkdf2Iterations = 5000; // More iterations = more secure, 1000 should be used as a minimum
$pbkdf2HashAlgo = 'sha256'; // 256-bit key size
$cipher = MCRYPT_RIJNDAEL_128; // Note: 128 refers to block size, not key size; MCRYPT_RIJNDAEL_128 is similar to 256-bit AES
$blockMode = MCRYPT_MODE_CFB; // CFB mode requires a random IV and does not require padding
$ivSource = MCRYPT_DEV_URANDOM; // URANDOM is faster than RANDOM in some environments
// Create key using PBKDF2 hash
$ivSize = mcrypt_get_iv_size($cipher, $blockMode);
$pbkdf2Salt = mcrypt_create_iv($ivSize, $ivSource);
$key = hash_pbkdf2($pbkdf2HashAlgo, $encryptionPassword, $pbkdf2Salt, $pbkdf2Iterations);
// Pack the key into a binary hex string
$key = pack('H*', $key);
// Create random IV
$iv = mcrypt_create_iv($ivSize, $ivSource);
// Encrypt the data
$encryptedData = mcrypt_encrypt($cipher, $key, $stringToEncrypt, $blockMode, $iv);
// Prepend the IV as it's needed for decryption
$encryptedData = $iv . $encryptedData;
// Base64 encode it
$encryptedData = base64_encode($encryptedData);
// Decrypt
$decryptedData = base64_decode($encryptedData);
// Get the IV
$ivDecrypted = substr($decryptedData, 0, $ivSize); // Don't need to use mb_substr as it's hexadecimal
// Get the encrypted data on its own
$decryptedData = substr($decryptedData, $ivSize);
// Decrypted data
$decryptedData = mcrypt_decrypt($cipher, $key, $decryptedData, $blockMode, $ivDecrypted);
// Output for testing
echo "<p>stringToEncrypt: $stringToEncrypt</p>";
echo "<p>encryptionPassword: $encryptionPassword</p>";
echo "<p>pbkdf2Iterations: $pbkdf2Iterations</p>";
echo "<p>pbkdf2HashAlgo: $pbkdf2HashAlgo</p>";
echo "<p>ivSize: $ivSize</p>";
echo "<p>iv: $iv</p>";
echo "<p>pbkdf2Salt: $pbkdf2Salt</p>";
echo "<p>key: $key</p>";
echo "<p>encryptedData: $encryptedData</p>";
echo "<p>ivDecrypted: $ivDecrypted</p>";
echo "<p>decryptedData: $decryptedData</p>";