[ Index ]

PHP Cross Reference of phpBB-3.2.8-deutsch

title

Body

[close]

/vendor/ircmaxell/password-compat/lib/ -> password.php (source)

   1  <?php
   2  /**
   3   * A Compatibility library with PHP 5.5's simplified password hashing API.
   4   *
   5   * @author Anthony Ferrara <ircmaxell@php.net>
   6   * @license http://www.opensource.org/licenses/mit-license.html MIT License
   7   * @copyright 2012 The Authors
   8   */
   9  
  10  namespace {
  11  
  12      if (!defined('PASSWORD_BCRYPT')) {
  13          /**
  14           * PHPUnit Process isolation caches constants, but not function declarations.
  15           * So we need to check if the constants are defined separately from 
  16           * the functions to enable supporting process isolation in userland
  17           * code.
  18           */
  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  
  26          /**
  27           * Hash the password using the specified algorithm
  28           *
  29           * @param string $password The password to hash
  30           * @param int    $algo     The algorithm to use (Defined by PASSWORD_* constants)
  31           * @param array  $options  The options for the algorithm to use
  32           *
  33           * @return string|false The hashed password, or false on error.
  34           */
  35          function password_hash($password, $algo, array $options = array()) {
  36              if (!function_exists('crypt')) {
  37                  trigger_error("Crypt must be loaded for password_hash to function", E_USER_WARNING);
  38                  return null;
  39              }
  40              if (is_null($password) || is_int($password)) {
  41                  $password = (string) $password;
  42              }
  43              if (!is_string($password)) {
  44                  trigger_error("password_hash(): Password must be a string", E_USER_WARNING);
  45                  return null;
  46              }
  47              if (!is_int($algo)) {
  48                  trigger_error("password_hash() expects parameter 2 to be long, " . gettype($algo) . " given", E_USER_WARNING);
  49                  return null;
  50              }
  51              $resultLength = 0;
  52              switch ($algo) {
  53                  case PASSWORD_BCRYPT:
  54                      $cost = PASSWORD_BCRYPT_DEFAULT_COST;
  55                      if (isset($options['cost'])) {
  56                          $cost = $options['cost'];
  57                          if ($cost < 4 || $cost > 31) {
  58                              trigger_error(sprintf("password_hash(): Invalid bcrypt cost parameter specified: %d", $cost), E_USER_WARNING);
  59                              return null;
  60                          }
  61                      }
  62                      // The length of salt to generate
  63                      $raw_salt_len = 16;
  64                      // The length required in the final serialization
  65                      $required_salt_len = 22;
  66                      $hash_format = sprintf("$2y$%02d$", $cost);
  67                      // The expected length of the final crypt() output
  68                      $resultLength = 60;
  69                      break;
  70                  default:
  71                      trigger_error(sprintf("password_hash(): Unknown password hashing algorithm: %s", $algo), E_USER_WARNING);
  72                      return null;
  73              }
  74              $salt_requires_encoding = false;
  75              if (isset($options['salt'])) {
  76                  switch (gettype($options['salt'])) {
  77                      case 'NULL':
  78                      case 'boolean':
  79                      case 'integer':
  80                      case 'double':
  81                      case 'string':
  82                          $salt = (string) $options['salt'];
  83                          break;
  84                      case 'object':
  85                          if (method_exists($options['salt'], '__tostring')) {
  86                              $salt = (string) $options['salt'];
  87                              break;
  88                          }
  89                      case 'array':
  90                      case 'resource':
  91                      default:
  92                          trigger_error('password_hash(): Non-string salt parameter supplied', E_USER_WARNING);
  93                          return null;
  94                  }
  95                  if (PasswordCompat\binary\_strlen($salt) < $required_salt_len) {
  96                      trigger_error(sprintf("password_hash(): Provided salt is too short: %d expecting %d", PasswordCompat\binary\_strlen($salt), $required_salt_len), E_USER_WARNING);
  97                      return null;
  98                  } elseif (0 == preg_match('#^[a-zA-Z0-9./]+$#D', $salt)) {
  99                      $salt_requires_encoding = true;
 100                  }
 101              } else {
 102                  $buffer = '';
 103                  $buffer_valid = false;
 104                  if (function_exists('mcrypt_create_iv') && !defined('PHALANGER')) {
 105                      $buffer = mcrypt_create_iv($raw_salt_len, MCRYPT_DEV_URANDOM);
 106                      if ($buffer) {
 107                          $buffer_valid = true;
 108                      }
 109                  }
 110                  if (!$buffer_valid && function_exists('openssl_random_pseudo_bytes')) {
 111                      $buffer = openssl_random_pseudo_bytes($raw_salt_len);
 112                      if ($buffer) {
 113                          $buffer_valid = true;
 114                      }
 115                  }
 116                  if (!$buffer_valid && @is_readable('/dev/urandom')) {
 117                      $f = fopen('/dev/urandom', 'r');
 118                      $read = PasswordCompat\binary\_strlen($buffer);
 119                      while ($read < $raw_salt_len) {
 120                          $buffer .= fread($f, $raw_salt_len - $read);
 121                          $read = PasswordCompat\binary\_strlen($buffer);
 122                      }
 123                      fclose($f);
 124                      if ($read >= $raw_salt_len) {
 125                          $buffer_valid = true;
 126                      }
 127                  }
 128                  if (!$buffer_valid || PasswordCompat\binary\_strlen($buffer) < $raw_salt_len) {
 129                      $bl = PasswordCompat\binary\_strlen($buffer);
 130                      for ($i = 0; $i < $raw_salt_len; $i++) {
 131                          if ($i < $bl) {
 132                              $buffer[$i] = $buffer[$i] ^ chr(mt_rand(0, 255));
 133                          } else {
 134                              $buffer .= chr(mt_rand(0, 255));
 135                          }
 136                      }
 137                  }
 138                  $salt = $buffer;
 139                  $salt_requires_encoding = true;
 140              }
 141              if ($salt_requires_encoding) {
 142                  // encode string with the Base64 variant used by crypt
 143                  $base64_digits =
 144                      'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
 145                  $bcrypt64_digits =
 146                      './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
 147  
 148                  $base64_string = base64_encode($salt);
 149                  $salt = strtr(rtrim($base64_string, '='), $base64_digits, $bcrypt64_digits);
 150              }
 151              $salt = PasswordCompat\binary\_substr($salt, 0, $required_salt_len);
 152  
 153              $hash = $hash_format . $salt;
 154  
 155              $ret = crypt($password, $hash);
 156  
 157              if (!is_string($ret) || PasswordCompat\binary\_strlen($ret) != $resultLength) {
 158                  return false;
 159              }
 160  
 161              return $ret;
 162          }
 163  
 164          /**
 165           * Get information about the password hash. Returns an array of the information
 166           * that was used to generate the password hash.
 167           *
 168           * array(
 169           *    'algo' => 1,
 170           *    'algoName' => 'bcrypt',
 171           *    'options' => array(
 172           *        'cost' => PASSWORD_BCRYPT_DEFAULT_COST,
 173           *    ),
 174           * )
 175           *
 176           * @param string $hash The password hash to extract info from
 177           *
 178           * @return array The array of information about the hash.
 179           */
 180          function password_get_info($hash) {
 181              $return = array(
 182                  'algo' => 0,
 183                  'algoName' => 'unknown',
 184                  'options' => array(),
 185              );
 186              if (PasswordCompat\binary\_substr($hash, 0, 4) == '$2y$' && PasswordCompat\binary\_strlen($hash) == 60) {
 187                  $return['algo'] = PASSWORD_BCRYPT;
 188                  $return['algoName'] = 'bcrypt';
 189                  list($cost) = sscanf($hash, "$2y$%d$");
 190                  $return['options']['cost'] = $cost;
 191              }
 192              return $return;
 193          }
 194  
 195          /**
 196           * Determine if the password hash needs to be rehashed according to the options provided
 197           *
 198           * If the answer is true, after validating the password using password_verify, rehash it.
 199           *
 200           * @param string $hash    The hash to test
 201           * @param int    $algo    The algorithm used for new password hashes
 202           * @param array  $options The options array passed to password_hash
 203           *
 204           * @return boolean True if the password needs to be rehashed.
 205           */
 206          function password_needs_rehash($hash, $algo, array $options = array()) {
 207              $info = password_get_info($hash);
 208              if ($info['algo'] != $algo) {
 209                  return true;
 210              }
 211              switch ($algo) {
 212                  case PASSWORD_BCRYPT:
 213                      $cost = isset($options['cost']) ? $options['cost'] : PASSWORD_BCRYPT_DEFAULT_COST;
 214                      if ($cost != $info['options']['cost']) {
 215                          return true;
 216                      }
 217                      break;
 218              }
 219              return false;
 220          }
 221  
 222          /**
 223           * Verify a password against a hash using a timing attack resistant approach
 224           *
 225           * @param string $password The password to verify
 226           * @param string $hash     The hash to verify against
 227           *
 228           * @return boolean If the password matches the hash
 229           */
 230          function password_verify($password, $hash) {
 231              if (!function_exists('crypt')) {
 232                  trigger_error("Crypt must be loaded for password_verify to function", E_USER_WARNING);
 233                  return false;
 234              }
 235              $ret = crypt($password, $hash);
 236              if (!is_string($ret) || PasswordCompat\binary\_strlen($ret) != PasswordCompat\binary\_strlen($hash) || PasswordCompat\binary\_strlen($ret) <= 13) {
 237                  return false;
 238              }
 239  
 240              $status = 0;
 241              for ($i = 0; $i < PasswordCompat\binary\_strlen($ret); $i++) {
 242                  $status |= (ord($ret[$i]) ^ ord($hash[$i]));
 243              }
 244  
 245              return $status === 0;
 246          }
 247      }
 248  
 249  }
 250  
 251  namespace PasswordCompat\binary {
 252  
 253      if (!function_exists('PasswordCompat\\binary\\_strlen')) {
 254  
 255          /**
 256           * Count the number of bytes in a string
 257           *
 258           * We cannot simply use strlen() for this, because it might be overwritten by the mbstring extension.
 259           * In this case, strlen() will count the number of *characters* based on the internal encoding. A
 260           * sequence of bytes might be regarded as a single multibyte character.
 261           *
 262           * @param string $binary_string The input string
 263           *
 264           * @internal
 265           * @return int The number of bytes
 266           */
 267          function _strlen($binary_string) {
 268              if (function_exists('mb_strlen')) {
 269                  return mb_strlen($binary_string, '8bit');
 270              }
 271              return strlen($binary_string);
 272          }
 273  
 274          /**
 275           * Get a substring based on byte limits
 276           *
 277           * @see _strlen()
 278           *
 279           * @param string $binary_string The input string
 280           * @param int    $start
 281           * @param int    $length
 282           *
 283           * @internal
 284           * @return string The substring
 285           */
 286          function _substr($binary_string, $start, $length) {
 287              if (function_exists('mb_substr')) {
 288                  return mb_substr($binary_string, $start, $length, '8bit');
 289              }
 290              return substr($binary_string, $start, $length);
 291          }
 292  
 293          /**
 294           * Check if current PHP version is compatible with the library
 295           *
 296           * @return boolean the check result
 297           */
 298          function check() {
 299              static $pass = NULL;
 300  
 301              if (is_null($pass)) {
 302                  if (function_exists('crypt')) {
 303                      $hash = '$2y$04$usesomesillystringfore7hnbRJHxXVLeakoG8K30oukPsA.ztMG';
 304                      $test = crypt("password", $hash);
 305                      $pass = $test == $hash;
 306                  } else {
 307                      $pass = false;
 308                  }
 309              }
 310              return $pass;
 311          }
 312  
 313      }
 314  }


Generated: Tue Apr 7 19:42:26 2020 Cross-referenced by PHPXref 0.7.1