I want to know if these encryption functions are ok for a live production application. Based on resources here and here and here I have put together these three functions.
Purpose
This code is for a encryption and decryption system that allows a user to encrypt certain data. The encrypted data is stored, while the keys are not stored at all.
The hash function is not used for verification but rather to add 'rounds', computational work to ensure that an attacker has to run many rounds whilst brute forcing through encryption keys. In addition the hash function extends the encryption key to the length of 32 bytes for use in the encryption functions.
I'm looking for advice regarding:
- Are the salts ok?
- Is this actually proper 256 bit encryption?
- Have I messed up any of my hash algo's etc.?
- These functions will be using encryption keys from the user side. Is there anything else I need to do that I am not doing?
- Are
encrypt256,decrypt256, andhashRoundsuitable for production?
Here are some notes regarding my code:
- They are salted via the
mcrypt_create_ivfunction. hashRoundis meant to slow down any brute force attacks.- Each round is actually 4 rounds, I guess the more hash functions the better right? In case one ever gets compromised.
- This is meant to be 256bit encrypted and this link suggests that you are to use
MCRYPT_RIJNDAEL_128with a 256 bit key to attain that level of encryption, which is what the hash function spits out here. - This does confuse me a little bit, as the hash algo
ripemd128actually produces 256bit - 32byte hashes, so why is it labelled 128?
Here is the algorithm:
- Start with the
EncryptionKeyandUserData. - The user supplies both the
EncryptionKeyandUserData. - To get (1) A 256 Bit key and (2) force a certain amount of computational work, hash the
EncryptionKeyXrounds through aRoundsHashfunction. This outputsNewEncryptionKey. - Now encrypt the
UserDatawithNewEncryptionKey. - Save the
UserDatainto the database.
I could skip the RoundsHash and get the same result, encrypted and decrypted data.
However, as I want to extend the EncryptionKey to precisely 32 bytes and also make any brute force attempt at decrypting the data slowly, I prefer to put the key first through the RoundsHash function.
As I do not store either EncryptionKey or NewEncryptionKey, if the RoundsHash function were to add a salt it would produce a different output (NewEncryptionKey) and I would never be able to decrypt the data.
Remember that I am only using this hash function to extend the key and add computational work, I am not verifying a password hash as I never store anything other than the UserData.
Here is the code listing:
function encrypt256($key, $input){
$ivSize = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
$iv = mcrypt_create_iv($ivSize, MCRYPT_DEV_URANDOM);
$crypt = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $input, MCRYPT_MODE_CBC, $iv);
$encrypted = base64_encode($iv . $crypt);
return $encrypted;
}
function decrypt256($key, $input){
$ivSize = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
$input = base64_decode($input);
$iv = substr($input, 0, $ivSize);
$crypt = substr($input, $ivSize, strlen($input));
$decrypted = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $crypt, MCRYPT_MODE_CBC, $iv);
return $decrypted;
}
function hashRound($rounds, $input){
for($x = 0; $x < $rounds; $x++){
$input = hash('sha512', hash('ripemd320', hash('whirlpool', $input)));
}
return hash('ripemd128', $input); // Sets the length of the key to 256 bits (32 bytes)
}
$rounds = 10000;
$testVal = "This is some test data";
$encryptionKey = "this is a Secure encryptionKey 12345 ##### 212312"; // encryptionKeys supplied by the user.
$enc = hashRound($rounds, $encryptionKey);
$mbStrlen = mb_strlen($enc);
$encrypted = encrypt256($pass, $testVal);
$decrypted = decrypt256($pass, $encrypted);
echo "<p>\$testVal: $testVal</p>";
echo "<p>\$encryptionKey: $encryptionKey</p>";
echo "<p>\$mbStrlen: $mbStrlen</p>";
echo "<p>\$encrypted: $encrypted</p>";
echo "<p>\$decrypted: $decrypted</p>";
password_hash()andpassword_verify()should be strongly considered for this purpose. They represent probably the most authoritative, secure, peer-reviewed, and therefore trusted implementation for this functionality in PHP. \$\endgroup\$