Last active
January 4, 2018 13:15
-
-
Save rk/1070401 to your computer and use it in GitHub Desktop.
Simple bcrypt object to wrap crypt() with.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
// Originally by Andrew Moore | |
// Src: http://stackoverflow.com/questions/4795385/how-do-you-use-bcrypt-for-hashing-passwords-in-php/6337021#6337021 | |
// | |
// Heavily modified by Robert Kosek, from data at php.net/crypt | |
class Bcrypt { | |
private $rounds; | |
private $prefix; | |
private $salt_prefix; | |
public function __construct($prefix = '', $rounds = 12) { | |
if(CRYPT_BLOWFISH != 1) { | |
throw new Exception("bcrypt not supported in this installation. See http://php.net/crypt"); | |
} | |
$this->rounds = $rounds; | |
$this->prefix = $prefix; | |
// Determine if this version of PHP has the Bcrypt fix | |
$this->salt_prefix = version_compare(PHP_VERSION, '5.3.7') >= 0 ? '$2y' : '$2a'; | |
} | |
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() { | |
// the base64 function uses +'s and ending ='s; translate the first, and cut out the latter | |
return sprintf('%s$%02d$%s', $this->salt_prefix, $this->rounds, substr(strtr(base64_encode($this->getBytes()), '+', '.'), 0, 22)); | |
} | |
private function getBytes() { | |
$bytes = ''; | |
if(function_exists('openssl_random_pseudo_bytes') && | |
(strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN')) { // OpenSSL slow on Win | |
$bytes = openssl_random_pseudo_bytes(18); | |
} | |
if($bytes === '' && is_readable('/dev/urandom') && | |
($hRand = @fopen('/dev/urandom', 'rb')) !== FALSE) { | |
$bytes = fread($hRand, 18); | |
fclose($hRand); | |
} | |
if($bytes === '') { | |
$key = uniqid($this->prefix, true); | |
// 12 rounds of HMAC must be reproduced / created verbatim, no known shortcuts. | |
// Changed the hash algorithm from salsa20, which has been removed from PHP 5.4. | |
for($i = 0; $i < 12; $i++) { | |
$bytes = hash_hmac('snefru256', microtime() . $bytes, $key, true); | |
usleep(10); | |
} | |
} | |
return $bytes; | |
} | |
} | |
?> |
I've updated this gist by switching from salsa20 to snefru256 as the fallback method for generating random bytes.
I've updated the gist to check for the PHP 5.3.7 or higher, and use the fixed bcrypt implementation.
You should probably remove the last line of this script. It should not include the closing tag of php
unpack() returns an array, the part mt_srand(unpack('N1', uniqid()));
is wrong
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
My previous response was discussing the derivation of the final hash.
What you're saying is correct though, only 1 iteration is strictly required because they will know the first 11 bytes of the result anyway. And that's all that matters for bcrypt.