[ Index ]

PHP Cross Reference of phpBB-3.1.12-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      * Construct a passwords object
  54      *
  55      * @param \phpbb\config\config $config phpBB configuration
  56      * @param array $hashing_algorithms Hashing driver
  57      *            service collection
  58      * @param \phpbb\passwords\helper $helper Passwords helper object
  59      * @param array $defaults List of default driver types
  60      */
  61  	public function __construct(\phpbb\config\config $config, $hashing_algorithms, helper $helper, $defaults)
  62      {
  63          $this->config = $config;
  64          $this->helper = $helper;
  65  
  66          $this->fill_type_map($hashing_algorithms);
  67          $this->register_default_type($defaults);
  68      }
  69  
  70      /**
  71      * Register default type
  72      * Will register the first supported type from the list of default types
  73      *
  74      * @param array $defaults List of default types in order from first to
  75      *            use to last to use
  76      */
  77  	protected function register_default_type($defaults)
  78      {
  79          foreach ($defaults as $type)
  80          {
  81              if ($this->algorithms[$type]->is_supported())
  82              {
  83                  $this->type = $this->algorithms[$type]->get_prefix();
  84                  break;
  85              }
  86          }
  87      }
  88  
  89      /**
  90      * Fill algorithm type map
  91      *
  92      * @param \phpbb\di\service_collection $hashing_algorithms
  93      */
  94  	protected function fill_type_map($hashing_algorithms)
  95      {
  96          foreach ($hashing_algorithms as $algorithm)
  97          {
  98              if (!isset($this->type_map[$algorithm->get_prefix()]))
  99              {
 100                  $this->type_map[$algorithm->get_prefix()] = $algorithm;
 101              }
 102          }
 103          $this->algorithms = $hashing_algorithms;
 104      }
 105  
 106      /**
 107      * Get the algorithm specified by a specific prefix
 108      *
 109      * @param string $prefix Password hash prefix
 110      *
 111      * @return object|bool The hash type object or false if prefix is not
 112      *            supported
 113      */
 114  	protected function get_algorithm($prefix)
 115      {
 116          if (isset($this->type_map[$prefix]))
 117          {
 118              return $this->type_map[$prefix];
 119          }
 120          else
 121          {
 122              return false;
 123          }
 124      }
 125  
 126      /**
 127      * Detect the hash type of the supplied hash
 128      *
 129      * @param string $hash Password hash that should be checked
 130      *
 131      * @return object|bool The hash type object or false if the specified
 132      *            type is not supported
 133      */
 134  	public function detect_algorithm($hash)
 135      {
 136          /*
 137          * preg_match() will also show hashing algos like $2a\H$, which
 138          * is a combination of bcrypt and phpass. Legacy algorithms
 139          * like md5 will not be matched by this and need to be treated
 140          * differently.
 141          */
 142          if (!preg_match('#^\$([a-zA-Z0-9\\\]*?)\$#', $hash, $match))
 143          {
 144              return false;
 145          }
 146  
 147          // Be on the lookout for multiple hashing algorithms
 148          // 2 is correct: H\2a > 2, H\P > 2
 149          if (strlen($match[1]) > 2)
 150          {
 151              $hash_types = explode('\\', $match[1]);
 152              $return_ary = array();
 153              foreach ($hash_types as $type)
 154              {
 155                  // we do not support the same hashing
 156                  // algorithm more than once
 157                  if (isset($return_ary[$type]))
 158                  {
 159                      return false;
 160                  }
 161  
 162                  $return_ary[$type] = $this->get_algorithm('$' . $type . '$');
 163  
 164                  if (empty($return_ary[$type]))
 165                  {
 166                      return false;
 167                  }
 168              }
 169              return $return_ary;
 170          }
 171  
 172          // get_algorithm() will automatically return false if prefix
 173          // is not supported
 174          return $this->get_algorithm($match[0]);
 175      }
 176  
 177      /**
 178      * Hash supplied password
 179      *
 180      * @param string $password Password that should be hashed
 181      * @param string $type Hash type. Will default to standard hash type if
 182      *            none is supplied
 183      * @return string|bool Password hash of supplied password or false if
 184      *            if something went wrong during hashing
 185      */
 186  	public function hash($password, $type = '')
 187      {
 188          if (strlen($password) > 4096)
 189          {
 190              // If the password is too huge, we will simply reject it
 191              // and not let the server try to hash it.
 192              return false;
 193          }
 194  
 195          // Try to retrieve algorithm by service name if type doesn't
 196          // start with dollar sign
 197          if (!is_array($type) && strpos($type, '$') !== 0 && isset($this->algorithms[$type]))
 198          {
 199              $type = $this->algorithms[$type]->get_prefix();
 200          }
 201  
 202          $type = ($type === '') ? $this->type : $type;
 203  
 204          if (is_array($type))
 205          {
 206              return $this->combined_hash_password($password, $type);
 207          }
 208  
 209          if (isset($this->type_map[$type]))
 210          {
 211              $hashing_algorithm = $this->type_map[$type];
 212          }
 213          else
 214          {
 215              return false;
 216          }
 217  
 218          return $hashing_algorithm->hash($password);
 219      }
 220  
 221      /**
 222      * Check supplied password against hash and set convert_flag if password
 223      * needs to be converted to different format (preferrably newer one)
 224      *
 225      * @param string $password Password that should be checked
 226      * @param string $hash Stored hash
 227      * @param array    $user_row User's row in users table
 228      * @return string|bool True if password is correct, false if not
 229      */
 230  	public function check($password, $hash, $user_row = array())
 231      {
 232          if (strlen($password) > 4096)
 233          {
 234              // If the password is too huge, we will simply reject it
 235              // and not let the server try to hash it.
 236              return false;
 237          }
 238  
 239          // Empty hashes can't be checked
 240          if (empty($hash))
 241          {
 242              return false;
 243          }
 244  
 245          // First find out what kind of hash we're dealing with
 246          $stored_hash_type = $this->detect_algorithm($hash);
 247          if ($stored_hash_type == false)
 248          {
 249              // Still check MD5 hashes as that is what the installer
 250              // will default to for the admin user
 251              return $this->get_algorithm('$H$')->check($password, $hash);
 252          }
 253  
 254          // Multiple hash passes needed
 255          if (is_array($stored_hash_type))
 256          {
 257              $correct = $this->check_combined_hash($password, $stored_hash_type, $hash);
 258              $this->convert_flag = ($correct === true) ? true : false;
 259              return $correct;
 260          }
 261  
 262          if ($stored_hash_type->get_prefix() !== $this->type)
 263          {
 264              $this->convert_flag = true;
 265          }
 266          else
 267          {
 268              $this->convert_flag = false;
 269          }
 270  
 271          // Check all legacy hash types if prefix is $CP$
 272          if ($stored_hash_type->get_prefix() === '$CP$')
 273          {
 274              // Remove $CP$ prefix for proper checking
 275              $hash = substr($hash, 4);
 276  
 277              foreach ($this->type_map as $algorithm)
 278              {
 279                  if ($algorithm->is_legacy() && $algorithm->check($password, $hash, $user_row) === true)
 280                  {
 281                      return true;
 282                  }
 283              }
 284          }
 285  
 286          return $stored_hash_type->check($password, $hash);
 287      }
 288  
 289      /**
 290      * Create combined hash from already hashed password
 291      *
 292      * @param string $password_hash Complete current password hash
 293      * @param string $type Type of the hashing algorithm the password hash
 294      *        should be combined with
 295      * @return string|bool Combined password hash if combined hashing was
 296      *        successful, else false
 297      */
 298  	public function combined_hash_password($password_hash, $type)
 299      {
 300          $data = array(
 301              'prefix' => '$',
 302              'settings' => '$',
 303          );
 304          $hash_settings = $this->helper->get_combined_hash_settings($password_hash);
 305          $hash = $hash_settings[0];
 306  
 307          // Put settings of current hash into data array
 308          $stored_hash_type = $this->detect_algorithm($password_hash);
 309          $this->helper->combine_hash_output($data, 'prefix', $stored_hash_type->get_prefix());
 310          $this->helper->combine_hash_output($data, 'settings', $stored_hash_type->get_settings_only($password_hash));
 311  
 312          // Hash current hash with the defined types
 313          foreach ($type as $cur_type)
 314          {
 315              if (isset($this->algorithms[$cur_type]))
 316              {
 317                  $new_hash_type = $this->algorithms[$cur_type];
 318              }
 319              else
 320              {
 321                  $new_hash_type = $this->get_algorithm($cur_type);
 322              }
 323  
 324              if (!$new_hash_type)
 325              {
 326                  return false;
 327              }
 328  
 329              $new_hash = $new_hash_type->hash(str_replace($stored_hash_type->get_settings_only($password_hash), '', $hash));
 330              $this->helper->combine_hash_output($data, 'prefix', $new_hash_type->get_prefix());
 331              $this->helper->combine_hash_output($data, 'settings', substr(str_replace('$', '\\', $new_hash_type->get_settings_only($new_hash, true)), 0));
 332              $hash = str_replace($new_hash_type->get_settings_only($new_hash), '', $this->helper->obtain_hash_only($new_hash));
 333          }
 334          return $this->helper->combine_hash_output($data, 'hash', $hash);
 335      }
 336  
 337      /**
 338      * Check combined password hash against the supplied password
 339      *
 340      * @param string $password Password entered by user
 341      * @param array $stored_hash_type An array containing the hash types
 342      *                as described by stored password hash
 343      * @param string $hash Stored password hash
 344      *
 345      * @return bool True if password is correct, false if not
 346      */
 347  	public function check_combined_hash($password, $stored_hash_type, $hash)
 348      {
 349          $i = 0;
 350          $data = array(
 351              'prefix' => '$',
 352              'settings' => '$',
 353          );
 354          $hash_settings = $this->helper->get_combined_hash_settings($hash);
 355          foreach ($stored_hash_type as $key => $hash_type)
 356          {
 357              $rebuilt_hash = $this->helper->rebuild_hash($hash_type->get_prefix(), $hash_settings[$i]);
 358              $this->helper->combine_hash_output($data, 'prefix', $key);
 359              $this->helper->combine_hash_output($data, 'settings', $hash_settings[$i]);
 360              $cur_hash = $hash_type->hash($password, $rebuilt_hash);
 361              $password = str_replace($rebuilt_hash, '', $cur_hash);
 362              $i++;
 363          }
 364          return ($hash === $this->helper->combine_hash_output($data, 'hash', $password));
 365      }
 366  }


Generated: Thu Jan 11 00:25:41 2018 Cross-referenced by PHPXref 0.7.1