[ Index ]

PHP Cross Reference of phpBB-3.2.11-deutsch

title

Body

[close]

/phpbb/passwords/ -> manager.php (source)

   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 (preferrably 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      *
 386      * @return bool True if password is correct, false if not
 387      */
 388  	public function check_combined_hash($password, $stored_hash_type, $hash)
 389      {
 390          $i = 0;
 391          $data = array(
 392              'prefix' => '$',
 393              'settings' => '$',
 394          );
 395          $hash_settings = $this->helper->get_combined_hash_settings($hash);
 396          foreach ($stored_hash_type as $key => $hash_type)
 397          {
 398              $rebuilt_hash = $this->helper->rebuild_hash($hash_type->get_prefix(), $hash_settings[$i]);
 399              $this->helper->combine_hash_output($data, 'prefix', $key);
 400              $this->helper->combine_hash_output($data, 'settings', $hash_settings[$i]);
 401              $cur_hash = $hash_type->hash($password, $rebuilt_hash);
 402              $password = str_replace($rebuilt_hash, '', $cur_hash);
 403              $i++;
 404          }
 405          return ($hash === $this->helper->combine_hash_output($data, 'hash', $password));
 406      }
 407  }


Generated: Wed Nov 11 20:33:01 2020 Cross-referenced by PHPXref 0.7.1