XCL Web Application Platform 2.5.0
The XoopsCube Legacy Project
Loading...
Searching...
No Matches
password.php
1<?php
9
10namespace {
11
12 if (!defined('PASSWORD_BCRYPT')) {
19 define('PASSWORD_BCRYPT', 1);
20 define('PASSWORD_DEFAULT', PASSWORD_BCRYPT);
21 define('PASSWORD_BCRYPT_DEFAULT_COST', 10);
22 }
23
24 if (!function_exists('password_hash')) {
25
36 function password_hash($password, $algo, array $options = []) {
37 if (!function_exists('crypt')) {
38 trigger_error('Crypt must be loaded for password_hash to function', E_USER_WARNING);
39 return null;
40 }
41 if (null === $password || is_int($password)) {
42 $password = (string) $password;
43 }
44 if (!is_string($password)) {
45 trigger_error('password_hash(): Password must be a string', E_USER_WARNING);
46 return null;
47 }
48 if (!is_int($algo)) {
49 trigger_error('password_hash() expects parameter 2 to be long, ' . gettype($algo) . ' given', E_USER_WARNING);
50 return null;
51 }
52 $resultLength = 0;
53 switch ($algo) {
54 case PASSWORD_BCRYPT:
55 $cost = PASSWORD_BCRYPT_DEFAULT_COST;
56 if (isset($options['cost'])) {
57 $cost = (int) $options['cost'];
58 if ($cost < 4 || $cost > 31) {
59 trigger_error(sprintf('password_hash(): Invalid bcrypt cost parameter specified: %d', $cost), E_USER_WARNING);
60 return null;
61 }
62 }
63 // The length of salt to generate
64 $raw_salt_len = 16;
65 // The length required in the final serialization
66 $required_salt_len = 22;
67 $hash_format = sprintf('$2y$%02d$', $cost);
68 // The expected length of the final crypt() output
69 $resultLength = 60;
70 break;
71 default:
72 trigger_error(sprintf('password_hash(): Unknown password hashing algorithm: %s', $algo), E_USER_WARNING);
73 return null;
74 }
75 $salt_req_encoding = false;
76 if (isset($options['salt'])) {
77 switch (gettype($options['salt'])) {
78 case 'NULL':
79 case 'boolean':
80 case 'integer':
81 case 'double':
82 case 'string':
83 $salt = (string) $options['salt'];
84 break;
85 case 'object':
86 if (method_exists($options['salt'], '__tostring')) {
87 $salt = (string) $options['salt'];
88 break;
89 }
90 case 'array':
91 case 'resource':
92 default:
93 trigger_error('password_hash(): Non-string salt parameter supplied', E_USER_WARNING);
94 return null;
95 }
96 if (PasswordCompat\binary\_strlen($salt) < $required_salt_len) {
97 trigger_error(sprintf('password_hash(): Provided salt is too short: %d expecting %d', PasswordCompat\binary\_strlen($salt), $required_salt_len), E_USER_WARNING);
98 return null;
99 } elseif (0 == preg_match('#^[a-zA-Z0-9./]+$#D', $salt)) {
100 $salt_req_encoding = true;
101 }
102 } else {
103 $buffer = '';
104 $buffer_valid = false;
105 if (function_exists('mcrypt_create_iv') && !defined('PHALANGER')) {
106 $buffer = mcrypt_create_iv($raw_salt_len, MCRYPT_DEV_URANDOM);
107 if ($buffer) {
108 $buffer_valid = true;
109 }
110 }
111 if (!$buffer_valid && function_exists('openssl_random_pseudo_bytes')) {
112 $strong = false;
113 $buffer = openssl_random_pseudo_bytes($raw_salt_len, $strong);
114 if ($buffer && $strong) {
115 $buffer_valid = true;
116 }
117 }
118 if (!$buffer_valid && @is_readable('/dev/urandom')) {
119 $file = fopen('/dev/urandom', 'r');
120 $read = 0;
121 $local_buffer = '';
122 while ($read < $raw_salt_len) {
123 $local_buffer .= fread($file, $raw_salt_len - $read);
124 $read = PasswordCompat\binary\_strlen($local_buffer);
125 }
126 fclose($file);
127 if ($read >= $raw_salt_len) {
128 $buffer_valid = true;
129 }
130 $buffer = str_pad($buffer, $raw_salt_len, "\0") ^ str_pad($local_buffer, $raw_salt_len, "\0");
131 }
132 if (!$buffer_valid || PasswordCompat\binary\_strlen($buffer) < $raw_salt_len) {
133 $buffer_length = PasswordCompat\binary\_strlen($buffer);
134 for ($i = 0; $i < $raw_salt_len; $i++) {
135 if ($i < $buffer_length) {
136 $buffer[$i] = $buffer[$i] ^ chr(random_int(0, 255));
137 } else {
138 $buffer .= chr(random_int(0, 255));
139 }
140 }
141 }
142 $salt = $buffer;
143 $salt_req_encoding = true;
144 }
145 if ($salt_req_encoding) {
146 // encode string with the Base64 variant used by crypt
147 $base64_digits =
148 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
149 $bcrypt64_digits =
150 './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
151
152 $base64_string = base64_encode($salt);
153 $salt = strtr(rtrim($base64_string, '='), $base64_digits, $bcrypt64_digits);
154 }
155 $salt = PasswordCompat\binary\_substr($salt, 0, $required_salt_len);
156
157 $hash = $hash_format . $salt;
158
159 $ret = crypt($password, $hash);
160
161 if (!is_string($ret) || PasswordCompat\binary\_strlen($ret) != $resultLength) {
162 return false;
163 }
164
165 return $ret;
166 }
167
184 function password_get_info($hash) {
185 $return = [
186 'algo' => 0,
187 'algoName' => 'unknown',
188 'options' => [],
189 ];
190 if ('$2y$' == PasswordCompat\binary\_substr($hash, 0, 4) && 60 == PasswordCompat\binary\_strlen($hash)) {
191 $return['algo'] = PASSWORD_BCRYPT;
192 $return['algoName'] = 'bcrypt';
193 [ $cost ] = sscanf( $hash, '$2y$%d$' );
194 $return['options']['cost'] = $cost;
195 }
196 return $return;
197 }
198
210 function password_needs_rehash($hash, $algo, array $options = []) {
211 $info = password_get_info($hash);
212 if ($info['algo'] !== (int) $algo) {
213 return true;
214 }
215 switch ($algo) {
216 case PASSWORD_BCRYPT:
217 $cost = isset($options['cost']) ? (int) $options['cost'] : PASSWORD_BCRYPT_DEFAULT_COST;
218 if ($cost !== $info['options']['cost']) {
219 return true;
220 }
221 break;
222 }
223 return false;
224 }
225
234 function password_verify($password, $hash) {
235 if (!function_exists('crypt')) {
236 trigger_error('Crypt must be loaded for password_verify to function', E_USER_WARNING);
237 return false;
238 }
239 $ret = crypt($password, $hash);
240 if (!is_string($ret) || PasswordCompat\binary\_strlen($ret) != PasswordCompat\binary\_strlen($hash) || PasswordCompat\binary\_strlen($ret) <= 13) {
241 return false;
242 }
243
244 $status = 0;
245 for ($i = 0; $i < PasswordCompat\binary\_strlen($ret); $i++) {
246 $status |= (ord($ret[$i]) ^ ord($hash[$i]));
247 }
248
249 return 0 === $status;
250 }
251 }
252
253}
254
255namespace PasswordCompat\binary {
256
257 if (!function_exists('PasswordCompat\\binary\\_strlen')) {
258
271 function _strlen($binary_string) {
272 if (function_exists('mb_strlen')) {
273 return mb_strlen($binary_string, '8bit');
274 }
275 return strlen($binary_string);
276 }
277
290 function _substr($binary_string, $start, $length) {
291 if (function_exists('mb_substr')) {
292 return mb_substr($binary_string, $start, $length, '8bit');
293 }
294 return substr($binary_string, $start, $length);
295 }
296
302 function check() {
303 static $pass = NULL;
304
305 if (null === $pass) {
306 if (function_exists('crypt')) {
307 $hash = '$2y$04$usesomesillystringfore7hnbRJHxXVLeakoG8K30oukPsA.ztMG';
308 $test = crypt('password', $hash);
309 $pass = $test == $hash;
310 } else {
311 $pass = false;
312 }
313 }
314 return $pass;
315 }
316
317 }
318}