1
\$\begingroup\$

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
 * find more information about this setting. Returns null on failure.
 */
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;
}
?>
asked Jan 8, 2014 at 6:08
\$\endgroup\$
3
  • 3
    \$\begingroup\$ 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)); \$\endgroup\$ Commented Jan 8, 2014 at 7:11
  • \$\begingroup\$ 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) \$\endgroup\$ Commented Jan 8, 2014 at 10:46
  • 1
    \$\begingroup\$ 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 \$\endgroup\$ Commented Feb 19, 2014 at 19:08

1 Answer 1

3
\$\begingroup\$

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.

Documentation for the former and latter.

answered Feb 19, 2014 at 18:54
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.