[ Index ] |
PHP Cross Reference of phpBB-3.2.11-deutsch |
[Summary view] [Print] [Text view]
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 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Wed Nov 11 20:33:01 2020 | Cross-referenced by PHPXref 0.7.1 |