[ Index ] |
PHP Cross Reference of phpBB-3.3.14-deutsch |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * 4 * This file is part of the phpBB Forum Software package. 5 * 6 * @copyright (c) phpBB Limited <https://www.phpbb.com> 7 * @license GNU General Public License, version 2 (GPL-2.0) 8 * 9 * For full copyright and license information, please see 10 * the docs/CREDITS.txt file. 11 * 12 */ 13 14 namespace phpbb\passwords; 15 16 class manager 17 { 18 /** 19 * Default hashing method 20 */ 21 protected $type = false; 22 23 /** 24 * Hashing algorithm type map 25 * Will be used to map hash prefix to type 26 */ 27 protected $type_map = false; 28 29 /** 30 * Service collection of hashing algorithms 31 * Needs to be public for passwords helper 32 */ 33 public $algorithms = false; 34 35 /** 36 * Password convert flag. Signals that password should be converted 37 */ 38 public $convert_flag = false; 39 40 /** 41 * Passwords helper 42 * @var \phpbb\passwords\helper 43 */ 44 protected $helper; 45 46 /** 47 * phpBB configuration 48 * @var \phpbb\config\config 49 */ 50 protected $config; 51 52 /** 53 * @var bool Whether or not initialized() has been called 54 */ 55 private $initialized = false; 56 57 /** 58 * @var array Hashing driver service collection 59 */ 60 private $hashing_algorithms; 61 62 /** 63 * @var array List of default driver types 64 */ 65 private $defaults; 66 67 /** 68 * Construct a passwords object 69 * 70 * @param \phpbb\config\config $config phpBB configuration 71 * @param array $hashing_algorithms Hashing driver service collection 72 * @param \phpbb\passwords\helper $helper Passwords helper object 73 * @param array $defaults List of default driver types 74 */ 75 public function __construct(\phpbb\config\config $config, $hashing_algorithms, helper $helper, $defaults) 76 { 77 $this->config = $config; 78 $this->helper = $helper; 79 $this->hashing_algorithms = $hashing_algorithms; 80 $this->defaults = $defaults; 81 } 82 83 /** 84 * Initialize the internal state 85 */ 86 protected function initialize() 87 { 88 if (!$this->initialized) 89 { 90 $this->initialized = true; 91 $this->fill_type_map($this->hashing_algorithms); 92 $this->register_default_type($this->defaults); 93 } 94 } 95 96 /** 97 * Register default type 98 * Will register the first supported type from the list of default types 99 * 100 * @param array $defaults List of default types in order from first to 101 * use to last to use 102 */ 103 protected function register_default_type($defaults) 104 { 105 foreach ($defaults as $type) 106 { 107 if ($this->algorithms[$type]->is_supported()) 108 { 109 $this->type = $this->algorithms[$type]->get_prefix(); 110 break; 111 } 112 } 113 } 114 115 /** 116 * Fill algorithm type map 117 * 118 * @param \phpbb\di\service_collection $hashing_algorithms 119 */ 120 protected function fill_type_map($hashing_algorithms) 121 { 122 foreach ($hashing_algorithms as $algorithm) 123 { 124 if (!isset($this->type_map[$algorithm->get_prefix()])) 125 { 126 $this->type_map[$algorithm->get_prefix()] = $algorithm; 127 } 128 } 129 $this->algorithms = $hashing_algorithms; 130 } 131 132 /** 133 * Get the algorithm specified by a specific prefix 134 * 135 * @param string $prefix Password hash prefix 136 * 137 * @return object|bool The hash type object or false if prefix is not 138 * supported 139 */ 140 protected function get_algorithm($prefix) 141 { 142 if (isset($this->type_map[$prefix])) 143 { 144 return $this->type_map[$prefix]; 145 } 146 else 147 { 148 return false; 149 } 150 } 151 152 /** 153 * Detect the hash type of the supplied hash 154 * 155 * @param string $hash Password hash that should be checked 156 * 157 * @return object|bool The hash type object or false if the specified 158 * type is not supported 159 */ 160 public function detect_algorithm($hash) 161 { 162 /* 163 * preg_match() will also show hashing algos like $2a\H$, which 164 * is a combination of bcrypt and phpass. Legacy algorithms 165 * like md5 will not be matched by this and need to be treated 166 * differently. 167 */ 168 if (!preg_match('#^\$([a-zA-Z0-9\\\]*?)\$#', $hash, $match)) 169 { 170 return false; 171 } 172 173 $this->initialize(); 174 175 // Be on the lookout for multiple hashing algorithms 176 // 2 is correct: H\2a > 2, H\P > 2 177 if (strlen($match[1]) > 2 && strpos($match[1], '\\') !== false) 178 { 179 $hash_types = explode('\\', $match[1]); 180 $return_ary = array(); 181 foreach ($hash_types as $type) 182 { 183 // we do not support the same hashing 184 // algorithm more than once 185 if (isset($return_ary[$type])) 186 { 187 return false; 188 } 189 190 $return_ary[$type] = $this->get_algorithm('$' . $type . '$'); 191 192 if (empty($return_ary[$type])) 193 { 194 return false; 195 } 196 } 197 return $return_ary; 198 } 199 200 // get_algorithm() will automatically return false if prefix 201 // is not supported 202 return $this->get_algorithm($match[0]); 203 } 204 205 /** 206 * Hash supplied password 207 * 208 * @param string $password Password that should be hashed 209 * @param string $type Hash type. Will default to standard hash type if 210 * none is supplied 211 * @return string|bool Password hash of supplied password or false if 212 * if something went wrong during hashing 213 */ 214 public function hash($password, $type = '') 215 { 216 if (strlen($password) > 4096) 217 { 218 // If the password is too huge, we will simply reject it 219 // and not let the server try to hash it. 220 return false; 221 } 222 223 $this->initialize(); 224 225 // Try to retrieve algorithm by service name if type doesn't 226 // start with dollar sign 227 if (!is_array($type) && strpos($type, '$') !== 0 && isset($this->algorithms[$type])) 228 { 229 $type = $this->algorithms[$type]->get_prefix(); 230 } 231 232 $type = ($type === '') ? $this->type : $type; 233 234 if (is_array($type)) 235 { 236 return $this->combined_hash_password($password, $type); 237 } 238 239 if (isset($this->type_map[$type])) 240 { 241 $hashing_algorithm = $this->type_map[$type]; 242 } 243 else 244 { 245 return false; 246 } 247 248 return $hashing_algorithm->hash($password); 249 } 250 251 /** 252 * Check supplied password against hash and set convert_flag if password 253 * needs to be converted to different format (preferably newer one) 254 * 255 * @param string $password Password that should be checked 256 * @param string $hash Stored hash 257 * @param array $user_row User's row in users table 258 * @return string|bool True if password is correct, false if not 259 */ 260 public function check($password, $hash, $user_row = array()) 261 { 262 if (strlen($password) > 4096) 263 { 264 // If the password is too huge, we will simply reject it 265 // and not let the server try to hash it. 266 return false; 267 } 268 269 // Empty hashes can't be checked 270 if (empty($hash)) 271 { 272 return false; 273 } 274 275 $this->initialize(); 276 277 // First find out what kind of hash we're dealing with 278 $stored_hash_type = $this->detect_algorithm($hash); 279 if ($stored_hash_type == false) 280 { 281 // Still check MD5 hashes as that is what the installer 282 // will default to for the admin user 283 return $this->get_algorithm('$H$')->check($password, $hash); 284 } 285 286 // Multiple hash passes needed 287 if (is_array($stored_hash_type)) 288 { 289 $correct = $this->check_combined_hash($password, $stored_hash_type, $hash); 290 $this->convert_flag = ($correct === true) ? true : false; 291 return $correct; 292 } 293 294 if ($stored_hash_type->get_prefix() !== $this->type) 295 { 296 $this->convert_flag = true; 297 } 298 else 299 { 300 if ($stored_hash_type instanceof driver\rehashable_driver_interface) 301 { 302 $this->convert_flag = $stored_hash_type->needs_rehash($hash); 303 } 304 else 305 { 306 $this->convert_flag = false; 307 } 308 } 309 310 // Check all legacy hash types if prefix is $CP$ 311 if ($stored_hash_type->get_prefix() === '$CP$') 312 { 313 // Remove $CP$ prefix for proper checking 314 $hash = substr($hash, 4); 315 316 foreach ($this->type_map as $algorithm) 317 { 318 if ($algorithm->is_legacy() && $algorithm->check($password, $hash, $user_row) === true) 319 { 320 return true; 321 } 322 } 323 } 324 325 return $stored_hash_type->check($password, $hash); 326 } 327 328 /** 329 * Create combined hash from already hashed password 330 * 331 * @param string $password_hash Complete current password hash 332 * @param string $type Type of the hashing algorithm the password hash 333 * should be combined with 334 * @return string|bool Combined password hash if combined hashing was 335 * successful, else false 336 */ 337 public function combined_hash_password($password_hash, $type) 338 { 339 $this->initialize(); 340 341 $data = array( 342 'prefix' => '$', 343 'settings' => '$', 344 ); 345 $hash_settings = $this->helper->get_combined_hash_settings($password_hash); 346 $hash = $hash_settings[0]; 347 348 // Put settings of current hash into data array 349 $stored_hash_type = $this->detect_algorithm($password_hash); 350 $this->helper->combine_hash_output($data, 'prefix', $stored_hash_type->get_prefix()); 351 $this->helper->combine_hash_output($data, 'settings', $stored_hash_type->get_settings_only($password_hash)); 352 353 // Hash current hash with the defined types 354 foreach ($type as $cur_type) 355 { 356 if (isset($this->algorithms[$cur_type])) 357 { 358 $new_hash_type = $this->algorithms[$cur_type]; 359 } 360 else 361 { 362 $new_hash_type = $this->get_algorithm($cur_type); 363 } 364 365 if (!$new_hash_type) 366 { 367 return false; 368 } 369 370 $new_hash = $new_hash_type->hash(str_replace($stored_hash_type->get_settings_only($password_hash), '', $hash)); 371 $this->helper->combine_hash_output($data, 'prefix', $new_hash_type->get_prefix()); 372 $this->helper->combine_hash_output($data, 'settings', substr(str_replace('$', '\\', $new_hash_type->get_settings_only($new_hash, true)), 0)); 373 $hash = str_replace($new_hash_type->get_settings_only($new_hash), '', $this->helper->obtain_hash_only($new_hash)); 374 } 375 return $this->helper->combine_hash_output($data, 'hash', $hash); 376 } 377 378 /** 379 * Check combined password hash against the supplied password 380 * 381 * @param string $password Password entered by user 382 * @param array $stored_hash_type An array containing the hash types 383 * as described by stored password hash 384 * @param string $hash Stored password hash 385 * @param bool $skip_phpbb2_check True if phpBB2 password check should be skipped 386 * 387 * @return bool True if password is correct, false if not 388 */ 389 public function check_combined_hash($password, $stored_hash_type, $hash, bool $skip_phpbb2_check = false) 390 { 391 // Special case for passwords converted from phpBB2: 392 // These could be phpass(md5(password)) and hence already be double 393 // hashed. For these, try to also check combined hash output of 394 // md5 version of supplied password. 395 $is_valid_phpbb2_pass = false; 396 if (!$skip_phpbb2_check) 397 { 398 $is_valid_phpbb2_pass = $this->check_combined_hash(md5($password), $stored_hash_type, $hash, true); 399 } 400 401 $i = 0; 402 $data = array( 403 'prefix' => '$', 404 'settings' => '$', 405 ); 406 $hash_settings = $this->helper->get_combined_hash_settings($hash); 407 foreach ($stored_hash_type as $key => $hash_type) 408 { 409 $rebuilt_hash = $this->helper->rebuild_hash($hash_type->get_prefix(), $hash_settings[$i]); 410 $this->helper->combine_hash_output($data, 'prefix', $key); 411 $this->helper->combine_hash_output($data, 'settings', $hash_settings[$i]); 412 $cur_hash = $hash_type->hash($password, $rebuilt_hash); 413 $password = str_replace($rebuilt_hash, '', $cur_hash); 414 $i++; 415 } 416 417 return hash_equals($hash, $this->helper->combine_hash_output($data, 'hash', $password)) || $is_valid_phpbb2_pass; 418 } 419 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Mon Nov 25 19:05:08 2024 | Cross-referenced by PHPXref 0.7.1 |