Sunday 19 November 2017

How do you use bcrypt for hashing passwords in PHP?

itemprop="text">


Every now and then I hear
the advice "Use bcrypt for storing passwords in PHP, bcrypt
rules".



But what is
bcrypt? PHP doesn't offer any such functions, Wikipedia babbles
about a file-encryption utility and Web searches just reveal a few implementations of
rel="noreferrer">Blowfish in different languages. Now Blowfish is also
available in PHP via mcrypt, but how does that help with
storing passwords? Blowfish is a general purpose cipher, it works two ways. If it could
be encrypted, it can be decrypted. Passwords need a one-way hashing
function.



What is the
explanation?


itemprop="text">
class="normal">Answer




bcrypt is a hashing
algorithm which is scalable with hardware (via a configurable number of rounds). Its
slowness and multiple rounds ensures that an attacker must deploy massive funds and
hardware to be able to crack your passwords. Add to that per-password href="https://en.wikipedia.org/wiki/Salt_%28cryptography%29"
rel="noreferrer">salts (bcrypt REQUIRES salts) and
you can be sure that an attack is virtually unfeasible without either ludicrous amount
of funds or
hardware.



bcrypt uses
the Eksblowfish algorithm to hash passwords. While the encryption
phase of Eksblowfish and Blowfish are exactly
the same, the key schedule phase of Eksblowfish ensures that any
subsequent state depends on both salt and key (user password), and no state can be
precomputed without the knowledge of both. Because of this key difference,
bcrypt is a one-way hashing algorithm.
You
cannot retrieve the plain text password without already knowing the salt, rounds
and key (password). [ href="http://www.usenix.org/events/usenix99/provos/provos_html/node4.html"
rel="noreferrer">Source]






Using
PHP >= 5.5-DEV



Password hashing functions
have now been built
directly into PHP >= 5.5
. You may now use href="http://php.net/password_hash"
rel="noreferrer">password_hash() to create a
bcrypt hash of any
password:



//
Usage 1:
echo password_hash('rasmuslerdorf',
PASSWORD_DEFAULT)."\n";
//
$2y$10$xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

// For
example:
//
$2y$10$.vGA1O9wmRjrwAVXD98HNOgsNpDczlqm3Jq7KnEd1rVAGv3Fykk1a

//
Usage 2:
$options = [
'cost' => 11
];
echo
password_hash('rasmuslerdorf', PASSWORD_BCRYPT, $options)."\n";
//
$2y$11$6DP.V0nO7YI3iSki4qog6OQI5eiO6Jnjsqg7vdnb.JgGIsxniOn4C



To
verify a user provided password against an existing hash, you may use the href="http://php.net/password_verify"
rel="noreferrer">password_verify() as
such:



// See
the password_hash() example to see where this came from.
$hash =
'$2y$07$BCryptRequires22Chrcte/VlQH0piJtjXl.0t1XkA8pw9dMXTpOq';

if
(password_verify('rasmuslerdorf', $hash)) {
echo 'Password is
valid!';
} else {

echo 'Invalid
password.';
}


Using
PHP >= 5.3.7, < 5.5-DEV (also RedHat PHP >=
5.3.3)



There is a href="https://github.com/ircmaxell/password_compat" rel="noreferrer">compatibility
library on rel="noreferrer">GitHub created based on the source code of the above
functions originally written in C, which provides the same functionality. Once the
compatibility library is installed, usage is the same as above (minus the shorthand
array notation if you are still on the 5.3.x
branch).



Using PHP < 5.3.7
(DEPRECATED)




You
can use crypt() function to generate bcrypt hashes of input
strings. This class can automatically generate salts and verify existing hashes against
an input. If you are using a version of PHP higher or equal to 5.3.7, it
is highly recommended you use the built-in function or the compat
library
. This alternative is provided only for historical
purposes.



class Bcrypt{

private $rounds;

public function __construct($rounds = 12)
{
if (CRYPT_BLOWFISH != 1) {
throw new Exception("bcrypt not
supported in this installation. See http://php.net/crypt");

}


$this->rounds = $rounds;

}

public function hash($input){
$hash = crypt($input,
$this->getSalt());

if (strlen($hash) > 13)
return
$hash;

return false;

}


public function verify($input, $existingHash){
$hash = crypt($input,
$existingHash);

return $hash === $existingHash;

}

private function getSalt(){
$salt =
sprintf('$2a$%02d$', $this->rounds);


$bytes =
$this->getRandomBytes(16);

$salt .=
$this->encodeBytes($bytes);

return $salt;

}

private $randomState;
private function
getRandomBytes($count){

$bytes = '';

if
(function_exists('openssl_random_pseudo_bytes') &&

(strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN')) { // OpenSSL is slow on Windows

$bytes = openssl_random_pseudo_bytes($count);
}

if
($bytes === '' && is_readable('/dev/urandom') &&
($hRand =
@fopen('/dev/urandom', 'rb')) !== FALSE) {
$bytes = fread($hRand,
$count);

fclose($hRand);
}

if
(strlen($bytes) < $count) {
$bytes = '';

if
($this->randomState === null) {
$this->randomState =
microtime();
if (function_exists('getmypid')) {

$this->randomState .= getmypid();

}

}

for ($i = 0; $i < $count; $i += 16) {

$this->randomState = md5(microtime() . $this->randomState);


if (PHP_VERSION >= '5') {
$bytes .= md5($this->randomState,
true);
} else {
$bytes .= pack('H*',
md5($this->randomState));

}
}


$bytes = substr($bytes, 0, $count);
}

return
$bytes;
}

private function
encodeBytes($input){

// The following is code from the PHP
Password Hashing Framework
$itoa64 =
'./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';


$output = '';
$i = 0;
do {
$c1 =
ord($input[$i++]);
$output .= $itoa64[$c1 >> 2];
$c1 = ($c1
& 0x03) << 4;
if ($i >= 16) {

$output .=
$itoa64[$c1];
break;
}

$c2 =
ord($input[$i++]);
$c1 |= $c2 >> 4;
$output .=
$itoa64[$c1];
$c1 = ($c2 & 0x0f) << 2;

$c2 =
ord($input[$i++]);

$c1 |= $c2 >> 6;
$output .=
$itoa64[$c1];
$output .= $itoa64[$c2 & 0x3f];
} while
(true);

return $output;

}
}



You
can use this code like
this:



$bcrypt = new
Bcrypt(15);

$hash = $bcrypt->hash('password');
$isGood
= $bcrypt->verify('password',
$hash);


Alternatively,
you may also use the rel="noreferrer">Portable PHP Hashing Framework.



No comments:

Post a Comment

php - file_get_contents shows unexpected output while reading a file

I want to output an inline jpg image as a base64 encoded string, however when I do this : $contents = file_get_contents($filename); print &q...