1 <?php |
1 <?php |
2 /** |
2 /** |
3 * Portable PHP password hashing framework. |
3 * Portable PHP password hashing framework. |
4 * @package phpass |
4 * @package phpass |
5 * @since 2.5.0 |
5 * @since 2.5.0 |
6 * @version 0.3 / WordPress |
6 * @version 0.5 / WordPress |
7 * @link https://www.openwall.com/phpass/ |
7 * @link https://www.openwall.com/phpass/ |
8 */ |
8 */ |
9 |
9 |
10 # |
10 # |
|
11 # Portable PHP password hashing framework. |
|
12 # |
|
13 # Version 0.5 / WordPress. |
|
14 # |
11 # Written by Solar Designer <solar at openwall.com> in 2004-2006 and placed in |
15 # Written by Solar Designer <solar at openwall.com> in 2004-2006 and placed in |
12 # the public domain. Revised in subsequent years, still public domain. |
16 # the public domain. Revised in subsequent years, still public domain. |
13 # |
17 # |
14 # There's absolutely no warranty. |
18 # There's absolutely no warranty. |
|
19 # |
|
20 # The homepage URL for this framework is: |
|
21 # |
|
22 # http://www.openwall.com/phpass/ |
15 # |
23 # |
16 # Please be sure to update the Version line if you edit this file in any way. |
24 # Please be sure to update the Version line if you edit this file in any way. |
17 # It is suggested that you leave the main version number intact, but indicate |
25 # It is suggested that you leave the main version number intact, but indicate |
18 # your project name (after the slash) and add your own revision information. |
26 # your project name (after the slash) and add your own revision information. |
19 # |
27 # |
27 |
35 |
28 /** |
36 /** |
29 * Portable PHP password hashing framework. |
37 * Portable PHP password hashing framework. |
30 * |
38 * |
31 * @package phpass |
39 * @package phpass |
32 * @version 0.3 / WordPress |
40 * @version 0.5 / WordPress |
33 * @link https://www.openwall.com/phpass/ |
41 * @link https://www.openwall.com/phpass/ |
34 * @since 2.5.0 |
42 * @since 2.5.0 |
35 */ |
43 */ |
36 class PasswordHash { |
44 class PasswordHash { |
37 var $itoa64; |
45 var $itoa64; |
38 var $iteration_count_log2; |
46 var $iteration_count_log2; |
39 var $portable_hashes; |
47 var $portable_hashes; |
40 var $random_state; |
48 var $random_state; |
41 |
49 |
42 /** |
50 function __construct($iteration_count_log2, $portable_hashes) |
43 * PHP5 constructor. |
|
44 */ |
|
45 function __construct( $iteration_count_log2, $portable_hashes ) |
|
46 { |
51 { |
47 $this->itoa64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'; |
52 $this->itoa64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'; |
48 |
53 |
49 if ($iteration_count_log2 < 4 || $iteration_count_log2 > 31) |
54 if ($iteration_count_log2 < 4 || $iteration_count_log2 > 31) |
50 $iteration_count_log2 = 8; |
55 $iteration_count_log2 = 8; |
51 $this->iteration_count_log2 = $iteration_count_log2; |
56 $this->iteration_count_log2 = $iteration_count_log2; |
52 |
57 |
53 $this->portable_hashes = $portable_hashes; |
58 $this->portable_hashes = $portable_hashes; |
54 |
59 |
55 $this->random_state = microtime() . uniqid(rand(), TRUE); // removed getmypid() for compatibility reasons |
60 $this->random_state = microtime(); |
56 } |
61 if (function_exists('getmypid')) |
57 |
62 $this->random_state .= getmypid(); |
58 /** |
63 } |
59 * PHP4 constructor. |
64 |
60 */ |
65 function PasswordHash($iteration_count_log2, $portable_hashes) |
61 public function PasswordHash( $iteration_count_log2, $portable_hashes ) { |
66 { |
62 self::__construct( $iteration_count_log2, $portable_hashes ); |
67 self::__construct($iteration_count_log2, $portable_hashes); |
63 } |
68 } |
64 |
69 |
65 function get_random_bytes($count) |
70 function get_random_bytes($count) |
66 { |
71 { |
67 $output = ''; |
72 $output = ''; |
68 if ( @is_readable('/dev/urandom') && |
73 if (@is_readable('/dev/urandom') && |
69 ($fh = @fopen('/dev/urandom', 'rb'))) { |
74 ($fh = @fopen('/dev/urandom', 'rb'))) { |
70 $output = fread($fh, $count); |
75 $output = fread($fh, $count); |
71 fclose($fh); |
76 fclose($fh); |
72 } |
77 } |
73 |
78 |
74 if (strlen($output) < $count) { |
79 if (strlen($output) < $count) { |
75 $output = ''; |
80 $output = ''; |
76 for ($i = 0; $i < $count; $i += 16) { |
81 for ($i = 0; $i < $count; $i += 16) { |
77 $this->random_state = |
82 $this->random_state = |
78 md5(microtime() . $this->random_state); |
83 md5(microtime() . $this->random_state); |
79 $output .= |
84 $output .= md5($this->random_state, TRUE); |
80 pack('H*', md5($this->random_state)); |
|
81 } |
85 } |
82 $output = substr($output, 0, $count); |
86 $output = substr($output, 0, $count); |
83 } |
87 } |
84 |
88 |
85 return $output; |
89 return $output; |
119 } |
123 } |
120 |
124 |
121 function crypt_private($password, $setting) |
125 function crypt_private($password, $setting) |
122 { |
126 { |
123 $output = '*0'; |
127 $output = '*0'; |
124 if (substr($setting, 0, 2) == $output) |
128 if (substr($setting, 0, 2) === $output) |
125 $output = '*1'; |
129 $output = '*1'; |
126 |
130 |
127 $id = substr($setting, 0, 3); |
131 $id = substr($setting, 0, 3); |
128 # We use "$P$", phpBB3 uses "$H$" for the same thing |
132 # We use "$P$", phpBB3 uses "$H$" for the same thing |
129 if ($id != '$P$' && $id != '$H$') |
133 if ($id !== '$P$' && $id !== '$H$') |
130 return $output; |
134 return $output; |
131 |
135 |
132 $count_log2 = strpos($this->itoa64, $setting[3]); |
136 $count_log2 = strpos($this->itoa64, $setting[3]); |
133 if ($count_log2 < 7 || $count_log2 > 30) |
137 if ($count_log2 < 7 || $count_log2 > 30) |
134 return $output; |
138 return $output; |
135 |
139 |
136 $count = 1 << $count_log2; |
140 $count = 1 << $count_log2; |
137 |
141 |
138 $salt = substr($setting, 4, 8); |
142 $salt = substr($setting, 4, 8); |
139 if (strlen($salt) != 8) |
143 if (strlen($salt) !== 8) |
140 return $output; |
144 return $output; |
141 |
145 |
142 # We're kind of forced to use MD5 here since it's the only |
146 # We were kind of forced to use MD5 here since it's the only |
143 # cryptographic primitive available in all versions of PHP |
147 # cryptographic primitive that was available in all versions |
144 # currently in use. To implement our own low-level crypto |
148 # of PHP in use. To implement our own low-level crypto in PHP |
145 # in PHP would result in much worse performance and |
149 # would have resulted in much worse performance and |
146 # consequently in lower iteration counts and hashes that are |
150 # consequently in lower iteration counts and hashes that are |
147 # quicker to crack (by non-PHP code). |
151 # quicker to crack (by non-PHP code). |
148 if (PHP_VERSION >= '5') { |
152 $hash = md5($salt . $password, TRUE); |
149 $hash = md5($salt . $password, TRUE); |
153 do { |
150 do { |
154 $hash = md5($hash . $password, TRUE); |
151 $hash = md5($hash . $password, TRUE); |
155 } while (--$count); |
152 } while (--$count); |
|
153 } else { |
|
154 $hash = pack('H*', md5($salt . $password)); |
|
155 do { |
|
156 $hash = pack('H*', md5($hash . $password)); |
|
157 } while (--$count); |
|
158 } |
|
159 |
156 |
160 $output = substr($setting, 0, 12); |
157 $output = substr($setting, 0, 12); |
161 $output .= $this->encode64($hash, 16); |
158 $output .= $this->encode64($hash, 16); |
162 |
|
163 return $output; |
|
164 } |
|
165 |
|
166 function gensalt_extended($input) |
|
167 { |
|
168 $count_log2 = min($this->iteration_count_log2 + 8, 24); |
|
169 # This should be odd to not reveal weak DES keys, and the |
|
170 # maximum valid value is (2**24 - 1) which is odd anyway. |
|
171 $count = (1 << $count_log2) - 1; |
|
172 |
|
173 $output = '_'; |
|
174 $output .= $this->itoa64[$count & 0x3f]; |
|
175 $output .= $this->itoa64[($count >> 6) & 0x3f]; |
|
176 $output .= $this->itoa64[($count >> 12) & 0x3f]; |
|
177 $output .= $this->itoa64[($count >> 18) & 0x3f]; |
|
178 |
|
179 $output .= $this->encode64($input, 3); |
|
180 |
159 |
181 return $output; |
160 return $output; |
182 } |
161 } |
183 |
162 |
184 function gensalt_blowfish($input) |
163 function gensalt_blowfish($input) |
228 return '*'; |
207 return '*'; |
229 } |
208 } |
230 |
209 |
231 $random = ''; |
210 $random = ''; |
232 |
211 |
233 if (CRYPT_BLOWFISH == 1 && !$this->portable_hashes) { |
212 if (CRYPT_BLOWFISH === 1 && !$this->portable_hashes) { |
234 $random = $this->get_random_bytes(16); |
213 $random = $this->get_random_bytes(16); |
235 $hash = |
214 $hash = |
236 crypt($password, $this->gensalt_blowfish($random)); |
215 crypt($password, $this->gensalt_blowfish($random)); |
237 if (strlen($hash) == 60) |
216 if (strlen($hash) === 60) |
238 return $hash; |
|
239 } |
|
240 |
|
241 if (CRYPT_EXT_DES == 1 && !$this->portable_hashes) { |
|
242 if (strlen($random) < 3) |
|
243 $random = $this->get_random_bytes(3); |
|
244 $hash = |
|
245 crypt($password, $this->gensalt_extended($random)); |
|
246 if (strlen($hash) == 20) |
|
247 return $hash; |
217 return $hash; |
248 } |
218 } |
249 |
219 |
250 if (strlen($random) < 6) |
220 if (strlen($random) < 6) |
251 $random = $this->get_random_bytes(6); |
221 $random = $this->get_random_bytes(6); |
252 $hash = |
222 $hash = |
253 $this->crypt_private($password, |
223 $this->crypt_private($password, |
254 $this->gensalt_private($random)); |
224 $this->gensalt_private($random)); |
255 if (strlen($hash) == 34) |
225 if (strlen($hash) === 34) |
256 return $hash; |
226 return $hash; |
257 |
227 |
258 # Returning '*' on error is safe here, but would _not_ be safe |
228 # Returning '*' on error is safe here, but would _not_ be safe |
259 # in a crypt(3)-like function used _both_ for generating new |
229 # in a crypt(3)-like function used _both_ for generating new |
260 # hashes and for validating passwords against existing hashes. |
230 # hashes and for validating passwords against existing hashes. |
266 if ( strlen( $password ) > 4096 ) { |
236 if ( strlen( $password ) > 4096 ) { |
267 return false; |
237 return false; |
268 } |
238 } |
269 |
239 |
270 $hash = $this->crypt_private($password, $stored_hash); |
240 $hash = $this->crypt_private($password, $stored_hash); |
271 if ($hash[0] == '*') |
241 if ($hash[0] === '*') |
272 $hash = crypt($password, $stored_hash); |
242 $hash = crypt($password, $stored_hash); |
273 |
243 |
|
244 # This is not constant-time. In order to keep the code simple, |
|
245 # for timing safety we currently rely on the salts being |
|
246 # unpredictable, which they are at least in the non-fallback |
|
247 # cases (that is, when we use /dev/urandom and bcrypt). |
274 return $hash === $stored_hash; |
248 return $hash === $stored_hash; |
275 } |
249 } |
276 } |
250 } |