Overview

Namespaces

  • PHP
  • PHPassLib
    • Application
    • Exception
    • Hash
    • Test
      • Application
      • Hash

Classes

  • BCrypt
  • BSDiCrypt
  • DESCrypt
  • MD5Crypt
  • PBKDF2
  • Portable
  • SHA1Crypt
  • SHA256Crypt
  • SHA512Crypt
  • Overview
  • Namespace
  • Class
  • Tree
  1: <?php
  2: /**
  3:  * PHP Password Library
  4:  *
  5:  * @package PHPassLib\Hashes
  6:  * @author Ryan Chouinard <rchouinard@gmail.com>
  7:  * @copyright Copyright (c) 2012, Ryan Chouinard
  8:  * @license MIT License - http://www.opensource.org/licenses/mit-license.php
  9:  * @version 3.0.0-dev
 10:  */
 11: 
 12: namespace PHPassLib\Hash;
 13: 
 14: use PHPassLib\Hash;
 15: use PHPassLib\Utilities;
 16: use PHPassLib\Exception\InvalidArgumentException;
 17: 
 18: /**
 19:  * PHPass Portable Module
 20:  *
 21:  * This module supports Openwall's PHPass Portable Hash format. Information
 22:  * about the original implementation may be found at
 23:  * http://www.openwall.com/phpass/.
 24:  *
 25:  * Supported parameters:
 26:  *
 27:  * <ul>
 28:  *   <li><b>ident:</b> The original implementation uses the identifier P, while
 29:  *   phpBB3 uses H. Defaults to P.</li>
 30:  *
 31:  *   <li><b>rounds:</b> Optional number of rounds to use. Must be an integer
 32:  *   between 7 and 30 inclusive. This value is logarithmic, meaning the actual
 33:  *   number of rounds will be 2^<rounds>. Defaults to 16.</li>
 34:  *
 35:  *   <li><b>salt:</b> Optional salt string. If provided, it must be an 8
 36:  *   character string containing only characters in the regex range
 37:  *   [./0-9A-Za-z]. It is highly recommended that this parameter be left blank,
 38:  *   in which case the library will generate a suitable salt for you.</li>
 39:  * </ul>
 40:  *
 41:  * @package PHPassLib\Hashes
 42:  * @author Ryan Chouinard <rchouinard@gmail.com>
 43:  * @copyright Copyright (c) 2012, Ryan Chouinard
 44:  * @license MIT License - http://www.opensource.org/licenses/mit-license.php
 45:  */
 46: class Portable implements Hash
 47: {
 48: 
 49:     const IDENT_PHPASS = 'P';
 50:     const IDENT_PHPBB = 'H';
 51: 
 52:     /**
 53:      * Generate a config string from an array.
 54:      *
 55:      * @param array $config Array of configuration options.
 56:      * @return string Configuration string.
 57:      * @throws InvalidArgumentException Throws an InvalidArgumentException if
 58:      *     any passed-in configuration options are invalid.
 59:      */
 60:     public static function genConfig(array $config = array ())
 61:     {
 62:         $defaults = array (
 63:             'ident' => self::IDENT_PHPASS,
 64:             'rounds' => 16,
 65:             'salt' => Utilities::encode64(Utilities::genRandomBytes(6)),
 66:         );
 67:         $config = array_merge($defaults, array_change_key_case($config, CASE_LOWER));
 68: 
 69:         $string = '*1';
 70:         if (self::validateOptions($config)) {
 71:             $charset = Utilities::CHARS_H64;
 72:             $string = sprintf('$%s$%s%s', $config['ident'], $charset[(int) $config['rounds']], $config['salt']);
 73:         }
 74: 
 75:         return $string;
 76:     }
 77: 
 78:     /**
 79:      * Parse a config string into an array.
 80:      *
 81:      * @param string $config Configuration string.
 82:      * @return array Array of configuration options or false on failure.
 83:      */
 84:     public static function parseConfig($config)
 85:     {
 86:         $options = false;
 87:         $matches = array ();
 88:         if (preg_match('/^\$(P|H)\$([5-9A-S]{1})([\.\/0-9A-Za-z]{8})/', $config, $matches)) {
 89:             $options = array (
 90:                 'ident' => $matches[1],
 91:                 'rounds' => strpos(Utilities::CHARS_H64, $config[3]),
 92:                 'salt' => $matches[3],
 93:             );
 94: 
 95:             try {
 96:                 self::validateOptions($options);
 97:             } catch (InvalidArgumentException $e) {
 98:                 $options = false;
 99:             }
100:         }
101: 
102:         return $options;
103:     }
104: 
105:     /**
106:      * Generate a password hash using a config string.
107:      *
108:      * @param string $password Password string.
109:      * @param string $config Configuration string.
110:      * @return string Returns the hash string on success. On failure, one of
111:      *     *0 or *1 is returned.
112:      */
113:     public static function genHash($password, $config)
114:     {
115:         $hash = ($config == '*0') ? '*1' : '*0';
116: 
117:         $config = self::parseConfig($config);
118:         if (is_array($config)) {
119:             $rounds = (1 << $config['rounds']);
120:             $checksum = md5($config['salt'] . $password, true);
121:             do {
122:                 $checksum = md5($checksum . $password, true);
123:             } while (--$rounds);
124:             $hash = self::genConfig($config) . Utilities::encode64($checksum);
125:         }
126: 
127:         return $hash;
128:     }
129: 
130:     /**
131:      * Generate a password hash using a config string or array.
132:      *
133:      * @param string $password Password string.
134:      * @param string|array $config Optional config string or array of options.
135:      * @return string Returns the hash string on success. On failure, one of
136:      *     *0 or *1 is returned.
137:      * @throws InvalidArgumentException Throws an InvalidArgumentException if
138:      *     any passed-in configuration options are invalid.
139:      */
140:     public static function hash($password, $config = array ())
141:     {
142:         if (is_array($config)) {
143:             $config = self::genConfig($config);
144:         }
145: 
146:         return self::genHash($password, $config);
147:     }
148: 
149:     /**
150:      * Verify a password against a hash string.
151:      *
152:      * @param string $password Password string.
153:      * @param string $hash Hash string.
154:      * @return boolean Returns true if the password matches, false otherwise.
155:      */
156:     public static function verify($password, $hash)
157:     {
158:         return ($hash === self::hash($password, $hash));
159:     }
160: 
161:     /**
162:      * @param array $options
163:      * @return boolean
164:      * @throws InvalidArgumentException
165:      */
166:     protected static function validateOptions(array $options)
167:     {
168:         $options = array_change_key_case($options, CASE_LOWER);
169:         foreach ($options as $option => $value) switch ($option) {
170: 
171:             case 'ident':
172:                 $idents = array (self::IDENT_PHPASS, self::IDENT_PHPBB);
173:                 if (!in_array($value, $idents)) {
174:                     throw new InvalidArgumentException('Invalid ident parameter');
175:                 }
176:                 break;
177: 
178:             case 'rounds':
179:                 if ($value < 7 || $value > 30) {
180:                     throw new InvalidArgumentException('Invalid rounds parameter');
181:                 }
182:                 break;
183: 
184:             case 'salt':
185:                 if (!preg_match('/^[\.\/0-9A-Za-z]{8}$/', $value)) {
186:                     throw new InvalidArgumentException('Invalid salt parameter');
187:                 }
188:                 break;
189: 
190:             default:
191:                 break;
192: 
193:         }
194: 
195:         return true;
196:     }
197: 
198: }
199: 
PHP Password Library API documentation generated by ApiGen 2.8.0