# PHP secure hash generator

As I understand it, blowfish (actually eksblowfish, as it's used one way) is generally seen a secure hashing algorithm, even for enterprise use (correct me if I'm wrong). Because of this, I created functions to create and check secure password hashes using this algorithm, and using the (also deemed cryptographically secure) openssl_random_pseudo_bytes function to generate the salt.

<?php
/*
* Generate a secure hash for a given password. The cost is passed
* to the blowfish algorithm. Check the PHP manual page for crypt to
*/
function generate_hash($password,$cost=11){
/* To generate the salt, first generate enough random bytes. Because
* base64 returns one character for each 6 bits, the we should generate
* at least 22*6/8=16.5 bytes, so we generate 17. Then we get the first
* 22 base64 characters
*/
$salt=substr(base64_encode(openssl_random_pseudo_bytes(17,$secure)),0,22);
/* If the random generation was not secure enough, do not continue
*/
if(!$secure) return null; /* As blowfish takes a salt with the alphabet ./A-Za-z0-9 we have to * replace any '+' in the base64 string with '.'. We don't have to do * anything about the '=', as this only occurs when the b64 string is * padded, which is always after the first 22 characters. */$salt=str_replace("+",".",$salt); /* Next, create a string that will be passed to crypt, containing all * of the settings, separated by dollar signs */$param='$'.implode('$',array(
"2y", //select the most secure version of blowfish (>=PHP 5.3.7)
str_pad($cost,2,"0",STR_PAD_LEFT), //add the cost in two digits$salt //add the salt
));

/* Now do the actual hashing
*/
$hash=crypt($password,$param); if(strlen($hash)!=60) return null;
return $hash; } /* * Check the password against a hash generated by the generate_hash * function. */ function validate_pw($password, $hash){ /* Regenerating the with an available hash as the options parameter should * produce the same hash if the same password is passed. */ return crypt($password, $hash)===$hash;
}
?>

• Why bother reinventing the wheel? Time and energy best spent upgrading your PHP version to 5.5, which introduced the password_hash function, to be called like so: password_hash(\$password, PASSWORD_BCRYPT, array('salt' => 'yourSalt', 'cost' => 15)); – Elias Van Ootegem Jan 8 '14 at 7:11
• Or even use something like phpass openwall.com/phpass . I feel that it is better to use something tested than roll your own (which may include vulnerabilities) – Sam Jan 8 '14 at 10:46
• If PHP 5.5 isn't available, ircmaxell has made a drop in PHP version that just requires PHP 5.3: github.com/ircmaxell/password_compat – Corbin Feb 19 '14 at 19:08

I would have to agree with @EliasVanOotegem. Consider using password_hash() and password_verify(). All you've done is recreate something, which we know shouldn't be done.