2 /** @package verysimple::Authentication */
5 * Bcrypt abstracts the use of bcrypt for secure password hashing.
6 * The verify method is backwards compatible with any algorithm
7 * supported by php crypt function
9 * @author http://stackoverflow.com/questions/4795385/how-do-you-use-bcrypt-for-hashing-passwords-in-php
10 * @author J.Hinkle http://verysimple.com/
12 * $bcrypt = new Bcrypt(15);
13 * $hash = $bcrypt->hash('password');
14 * $isGood = $bcrypt->verify('password', $hash);
26 * int number of crypt rounds
27 * @throws Exception if bcrypt is not supported
29 public function __construct($rounds = 12)
31 if (CRYPT_BLOWFISH
!= 1) {
32 throw new Exception("bcrypt not supported in this installation. See http://php.net/crypt");
35 $this->rounds
= $rounds;
39 * Return true if the given hash is crypted with the blowfish algorithm
43 static function isBlowfish($hash)
45 return substr($hash, 0, 4) == '$2a$';
52 * string plain text input
54 public function hash($input)
56 $hash = crypt($input, $this->getSalt());
58 if (strlen($hash) > 13) {
66 * Verify if the input is equal to the hashed value
69 * string plain text input
73 public function verify($input, $existingHash)
75 $hash = crypt($input, $existingHash);
77 return $hash === $existingHash;
81 * return an ascii-encoded 16 char salt
83 private function getSalt()
85 $salt = sprintf('$2a$%02d$', $this->rounds
);
87 $bytes = $this->getRandomBytes(16);
89 $salt .= $this->encodeBytes($bytes);
95 * get random bytes to be used in random salts
99 private function getRandomBytes($count)
103 if (function_exists('openssl_random_pseudo_bytes') && (strtoupper(substr(PHP_OS
, 0, 3)) !== 'WIN')) { // OpenSSL slow on Win
104 $bytes = openssl_random_pseudo_bytes($count);
107 if ($bytes === '' && is_readable('/dev/urandom') && ($hRand = @fopen
('/dev/urandom', 'rb')) !== false) {
108 $bytes = fread($hRand, $count);
112 if (strlen($bytes) < $count) {
115 if ($this->randomState
=== null) {
116 $this->randomState
= microtime();
117 if (function_exists('getmypid')) {
118 $this->randomState
.= getmypid();
122 for ($i = 0; $i < $count; $i +
= 16) {
123 $this->randomState
= md5(microtime() . $this->randomState
);
125 if (PHP_VERSION
>= '5') {
126 $bytes .= md5($this->randomState
, true);
128 $bytes .= pack('H*', md5($this->randomState
));
132 $bytes = substr($bytes, 0, $count);
139 * ascii-encode used for converting random salt into legit ascii value
141 * @param string $input
143 private function encodeBytes($input)
145 // The following is code from the PHP Password Hashing Framework
146 $itoa64 = './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
151 $c1 = ord($input [$i ++
]);
152 $output .= $itoa64 [$c1 >> 2];
153 $c1 = ($c1 & 0x03) << 4;
155 $output .= $itoa64 [$c1];
159 $c2 = ord($input [$i ++
]);
161 $output .= $itoa64 [$c1];
162 $c1 = ($c2 & 0x0f) << 2;
164 $c2 = ord($input [$i ++
]);
166 $output .= $itoa64 [$c1];
167 $output .= $itoa64 [$c2 & 0x3f];