CMSimple_XH 開発者ドキュメント
password.php
[詳解]
1 <?php
2 
13 namespace {
14 
15  if (!function_exists('random_bytes')) {
16 
21  function random_bytes($length)
22  {
23  $buffer = '';
24  $buffer_valid = false;
25  if (function_exists('mcrypt_create_iv') && !defined('PHALANGER')) {
26  $buffer = mcrypt_create_iv($length, MCRYPT_DEV_URANDOM);
27  if ($buffer) {
28  $buffer_valid = true;
29  }
30  }
31  if (!$buffer_valid && function_exists('openssl_random_pseudo_bytes')) {
32  $strong = false;
33  $buffer = openssl_random_pseudo_bytes($length, $strong);
34  if ($buffer && $strong) {
35  $buffer_valid = true;
36  }
37  }
38  if (!$buffer_valid && @is_readable('/dev/urandom')) {
39  $file = fopen('/dev/urandom', 'r');
40  $read = 0;
41  $local_buffer = '';
42  while ($read < $length) {
43  $local_buffer .= fread($file, $length - $read);
44  $read = PasswordCompat\binary\_strlen($local_buffer);
45  }
46  fclose($file);
47  if ($read >= $length) {
48  $buffer_valid = true;
49  }
50  $buffer = str_pad($buffer, $length, "\0") ^ str_pad($local_buffer, $length, "\0");
51  }
52  if (!$buffer_valid || PasswordCompat\binary\_strlen($buffer) < $length) {
53  $buffer_length = PasswordCompat\binary\_strlen($buffer);
54  for ($i = 0; $i < $length; $i++) {
55  if ($i < $buffer_length) {
56  $buffer[$i] = $buffer[$i] ^ chr(mt_rand(0, 255));
57  } else {
58  $buffer .= chr(mt_rand(0, 255));
59  }
60  }
61  }
62  return $buffer;
63  }
64  }
65 
66  if (!defined('PASSWORD_BCRYPT')) {
73  define('PASSWORD_BCRYPT', 1);
74  define('PASSWORD_DEFAULT', PASSWORD_BCRYPT);
75  define('PASSWORD_BCRYPT_DEFAULT_COST', 10);
76  }
77 
78  if (!function_exists('password_hash')) {
79 
89  function password_hash($password, $algo, array $options = array())
90  {
91  if (!function_exists('crypt')) {
92  trigger_error("Crypt must be loaded for password_hash to function", E_USER_WARNING);
93  return null;
94  }
95  if (is_null($password) || is_int($password)) {
96  $password = (string) $password;
97  }
98  if (!is_string($password)) {
99  trigger_error("password_hash(): Password must be a string", E_USER_WARNING);
100  return null;
101  }
102  if (!is_int($algo)) {
103  trigger_error(
104  "password_hash() expects parameter 2 to be long, " . gettype($algo) . " given",
105  E_USER_WARNING
106  );
107  return null;
108  }
109  $resultLength = 0;
110  switch ($algo) {
111  case PASSWORD_BCRYPT:
112  $cost = PASSWORD_BCRYPT_DEFAULT_COST;
113  if (isset($options['cost'])) {
114  $cost = (int) $options['cost'];
115  if ($cost < 4 || $cost > 31) {
116  trigger_error(
117  sprintf("password_hash(): Invalid bcrypt cost parameter specified: %d", $cost),
118  E_USER_WARNING
119  );
120  return null;
121  }
122  }
123  // The length of salt to generate
124  $raw_salt_len = 16;
125  // The length required in the final serialization
126  $required_salt_len = 22;
127  $hash_format = sprintf("$2y$%02d$", $cost);
128  // The expected length of the final crypt() output
129  $resultLength = 60;
130  break;
131  default:
132  trigger_error(
133  sprintf("password_hash(): Unknown password hashing algorithm: %s", $algo),
134  E_USER_WARNING
135  );
136  return null;
137  }
138  $salt_req_encoding = false;
139  if (isset($options['salt'])) {
140  switch (gettype($options['salt'])) {
141  case 'NULL':
142  case 'boolean':
143  case 'integer':
144  case 'double':
145  case 'string':
146  $salt = (string) $options['salt'];
147  break;
148  case 'object':
149  if (method_exists($options['salt'], '__tostring')) {
150  $salt = (string) $options['salt'];
151  break;
152  }
153  // no break
154  case 'array':
155  case 'resource':
156  default:
157  trigger_error('password_hash(): Non-string salt parameter supplied', E_USER_WARNING);
158  return null;
159  }
160  if (PasswordCompat\binary\_strlen($salt) < $required_salt_len) {
161  trigger_error(
162  sprintf(
163  "password_hash(): Provided salt is too short: %d expecting %d",
164  PasswordCompat\binary\_strlen($salt),
165  $required_salt_len
166  ),
167  E_USER_WARNING
168  );
169  return null;
170  } elseif (0 == preg_match('#^[a-zA-Z0-9./]+$#D', $salt)) {
171  $salt_req_encoding = true;
172  }
173  } else {
174  $salt = random_bytes($raw_salt_len);
175  $salt_req_encoding = true;
176  }
177  if ($salt_req_encoding) {
178  // encode string with the Base64 variant used by crypt
179  $base64_digits =
180  'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
181  $bcrypt64_digits =
182  './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
183 
184  $base64_string = base64_encode($salt);
185  $salt = strtr(rtrim($base64_string, '='), $base64_digits, $bcrypt64_digits);
186  }
187  $salt = PasswordCompat\binary\_substr($salt, 0, $required_salt_len);
188 
189  $hash = $hash_format . $salt;
190 
191  $ret = crypt($password, $hash);
192 
193  if (!is_string($ret) || PasswordCompat\binary\_strlen($ret) != $resultLength) {
194  return false;
195  }
196 
197  return $ret;
198  }
199 
200  }
201 
202  if (!function_exists('password_get_info')) {
203 
220  function password_get_info($hash)
221  {
222  $return = array(
223  'algo' => 0,
224  'algoName' => 'unknown',
225  'options' => array(),
226  );
227  if (PasswordCompat\binary\_substr($hash, 0, 4) == '$2y$' && PasswordCompat\binary\_strlen($hash) == 60) {
228  $return['algo'] = PASSWORD_BCRYPT;
229  $return['algoName'] = 'bcrypt';
230  list($cost) = sscanf($hash, "$2y$%d$");
231  $return['options']['cost'] = $cost;
232  }
233  return $return;
234  }
235 
236  }
237 
238  if (!function_exists('password_needs_rehash')) {
239 
251  function password_needs_rehash($hash, $algo, array $options = array())
252  {
253  $info = password_get_info($hash);
254  if ($info['algo'] !== (int) $algo) {
255  return true;
256  }
257  switch ($algo) {
258  case PASSWORD_BCRYPT:
259  $cost = isset($options['cost']) ? (int) $options['cost'] : PASSWORD_BCRYPT_DEFAULT_COST;
260  if ($cost !== $info['options']['cost']) {
261  return true;
262  }
263  break;
264  }
265  return false;
266  }
267 
268  }
269 
270  if (!function_exists('password_verify')) {
271 
280  function password_verify($password, $hash)
281  {
282  if (!function_exists('crypt')) {
283  trigger_error("Crypt must be loaded for password_verify to function", E_USER_WARNING);
284  return false;
285  }
286  $ret = crypt($password, $hash);
287  if (!is_string($ret) || PasswordCompat\binary\_strlen($ret) != PasswordCompat\binary\_strlen($hash)
288  || PasswordCompat\binary\_strlen($ret) <= 13) {
289  return false;
290  }
291 
292  $status = 0;
293  for ($i = 0; $i < PasswordCompat\binary\_strlen($ret); $i++) {
294  $status |= (ord($ret[$i]) ^ ord($hash[$i]));
295  }
296 
297  return $status === 0;
298  }
299  }
300 
301 }
302 
303 namespace PasswordCompat\binary {
304 
305  if (!function_exists('PasswordCompat\\binary\\_strlen')) {
306 
319  function _strlen($binary_string)
320  {
321  if (function_exists('mb_strlen')) {
322  return mb_strlen($binary_string, '8bit');
323  }
324  return strlen($binary_string);
325  }
326 
339  function _substr($binary_string, $start, $length)
340  {
341  if (function_exists('mb_substr')) {
342  return mb_substr($binary_string, $start, $length, '8bit');
343  }
344  return substr($binary_string, $start, $length);
345  }
346 
352  function check()
353  {
354  static $pass = null;
355 
356  if (is_null($pass)) {
357  if (function_exists('crypt')) {
358  $hash = '$2y$04$usesomesillystringfore7hnbRJHxXVLeakoG8K30oukPsA.ztMG';
359  $test = crypt("password", $hash);
360  $pass = $test == $hash;
361  } else {
362  $pass = false;
363  }
364  }
365  return $pass;
366  }
367 
368  }
369 }
$i
Definition: cms.php:193
$file
Definition: cms.php:640