Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 4.3.x will end 7 October 2024 (12 months).
  • Bug fixes for security issues in 4.3.x will end 21 April 2025 (18 months).
  • PHP version: minimum PHP 8.0.0 Note: minimum PHP version has increased since Moodle 4.1. PHP 8.2.x is supported too.
   1  <?php
   2  /**
   3   * Copyright 2015-2017 Horde LLC (http://www.horde.org/)
   4   *
   5   * See the enclosed file LICENSE for license information (LGPL). If you
   6   * did not receive this file, see http://www.horde.org/licenses/lgpl21.
   7   *
   8   * @author   Michael Slusarz <slusarz@horde.org>
   9   * @category Horde
  10   * @license  http://www.horde.org/licenses/lgpl21 LGPL 2.1
  11   * @package  Crypt_Blowfish
  12   */
  13  
  14  /**
  15   * PBKDF2 (Password-Based Key Derivation Function 2) implementation (RFC
  16   * 2898; PKCS #5 v2.0).
  17   *
  18   * @author    Michael Slusarz <slusarz@horde.org>
  19   * @category  Horde
  20   * @copyright 2015-2017 Horde LLC
  21   * @license   http://www.horde.org/licenses/lgpl21 LGPL 2.1
  22   * @package   Crypt_Blowfish
  23   * @link      https://defuse.ca/php-pbkdf2.htm pbkdf2 code released to the
  24   *            public domain.
  25   */
  26  class Horde_Crypt_Blowfish_Pbkdf2
  27  {
  28      /**
  29       * Hash algorithm used to create key.
  30       *
  31       * @var string
  32       */
  33      public $hashAlgo;
  34  
  35      /**
  36       * Number of iterations to use.
  37       *
  38       * @var integer
  39       */
  40      public $iterations;
  41  
  42      /**
  43       * Salt.
  44       *
  45       * @var string
  46       */
  47      public $salt;
  48  
  49      /**
  50       * The derived key.
  51       *
  52       * @var string
  53       */
  54      protected $_key;
  55  
  56      /**
  57       * Constructor.
  58       *
  59       * @param string $pass        The password.
  60       * @param string $key_length  Length of the derived key (in bytes).
  61       * @param array $opts         Additional options:
  62       *   - algo: (string) Hash algorithm.
  63       *   - i_count: (integer) Iteration count.
  64       *   - salt: (string) The salt to use.
  65       */
  66      public function __construct($pass, $key_length, array $opts = array())
  67      {
  68          $this->iterations = isset($opts['i_count'])
  69              ? $opts['i_count']
  70              : 16384;
  71  
  72          if (($key_length <= 0) || ($this->iterations <= 0)) {
  73              throw new InvalidArgumentException('Invalid arguments');
  74          }
  75  
  76          $this->hashAlgo = isset($opts['algo'])
  77              ? $opts['algo']
  78              : 'SHA256';
  79  
  80          /* Nice to have, but salt does not need to be cryptographically
  81           * secure random value. */
  82          $this->salt = isset($opts['salt'])
  83              ? $opts['salt']
  84              : (function_exists('openssl_random_pseudo_bytes')
  85                    ? openssl_random_pseudo_bytes($key_length)
  86                    : substr(hash('sha512', new Horde_Support_Randomid(), true), 0, $key_length));
  87  
  88          if (function_exists('hash_pbkdf2')) {
  89              $this->_key = hash_pbkdf2(
  90                  $this->hashAlgo,
  91                  $pass,
  92                  $this->salt,
  93                  $this->iterations,
  94                  $key_length,
  95                  true
  96              );
  97              return;
  98          }
  99  
 100          $hash_length = strlen(hash($this->hashAlgo, '', true));
 101          $block_count = ceil($key_length / $hash_length);
 102  
 103          $hash = '';
 104          for ($i = 1; $i <= $block_count; ++$i) {
 105              // $i encoded as 4 bytes, big endian.
 106              $last = $this->salt . pack('N', $i);
 107              for ($j = 0; $j < $this->iterations; $j++) {
 108                  $last = hash_hmac($this->hashAlgo, $last, $pass, true);
 109                  if ($j) {
 110                      $xorsum ^= $last;
 111                  } else {
 112                      $xorsum = $last;
 113                  }
 114              }
 115              $hash .= $xorsum;
 116          }
 117  
 118          $this->_key = substr($hash, 0, $key_length);
 119      }
 120  
 121      /**
 122       */
 123      public function __toString()
 124      {
 125          return $this->_key;
 126      }
 127  
 128  }