Highway to PSR2
[openemr.git] / portal / patient / fwk / libs / verysimple / Authentication / Bcrypt.php
blob58c5109bf32ce9c2a0a4fd7a3fb8c4f4b8d000b7
1 <?php
2 /** @package verysimple::Authentication */
4 /**
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/
11 * @example <code>
12 * $bcrypt = new Bcrypt(15);
13 * $hash = $bcrypt->hash('password');
14 * $isGood = $bcrypt->verify('password', $hash);
15 * </code>
17 class Bcrypt
19 private $rounds;
20 private $randomState;
22 /**
23 * Constructor
25 * @param
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;
38 /**
39 * Return true if the given hash is crypted with the blowfish algorithm
41 * @param string $hash
43 static function isBlowfish($hash)
45 return substr($hash, 0, 4) == '$2a$';
48 /**
49 * generate a hash
51 * @param
52 * string plain text input
54 public function hash($input)
56 $hash = crypt($input, $this->getSalt());
58 if (strlen($hash) > 13) {
59 return $hash;
62 return false;
65 /**
66 * Verify if the input is equal to the hashed value
68 * @param
69 * string plain text input
70 * @param
71 * string hashed input
73 public function verify($input, $existingHash)
75 $hash = crypt($input, $existingHash);
77 return $hash === $existingHash;
80 /**
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);
91 return $salt;
94 /**
95 * get random bytes to be used in random salts
97 * @param int $count
99 private function getRandomBytes($count)
101 $bytes = '';
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);
109 fclose($hRand);
112 if (strlen($bytes) < $count) {
113 $bytes = '';
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);
127 } else {
128 $bytes .= pack('H*', md5($this->randomState));
132 $bytes = substr($bytes, 0, $count);
135 return $bytes;
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';
148 $output = '';
149 $i = 0;
150 do {
151 $c1 = ord($input [$i ++]);
152 $output .= $itoa64 [$c1 >> 2];
153 $c1 = ($c1 & 0x03) << 4;
154 if ($i >= 16) {
155 $output .= $itoa64 [$c1];
156 break;
159 $c2 = ord($input [$i ++]);
160 $c1 |= $c2 >> 4;
161 $output .= $itoa64 [$c1];
162 $c1 = ($c2 & 0x0f) << 2;
164 $c2 = ord($input [$i ++]);
165 $c1 |= $c2 >> 6;
166 $output .= $itoa64 [$c1];
167 $output .= $itoa64 [$c2 & 0x3f];
168 } while (1);
170 return $output;