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:  * BCrypt Module
 20:  *
 21:  * BCrypt is based on a version of the Blowfish stream cipher, and features
 22:  * a variable number of rounds and a large salt. BCrypt is recommended for
 23:  * new applications.
 24:  *
 25:  * Supported parameters:
 26:  *
 27:  * <ul>
 28:  *   <li><b>rounds:</b> Optional number of rounds to use. Must be an integer
 29:  *   between 4 and 31 inclusive. This value is logarithmic, meaning the actual
 30:  *   number of rounds will be 2^<rounds>. Defaults to 12.</li>
 31:  *
 32:  *   <li><b>ident:</b> Identifier which specifies the version of the algorithm
 33:  *   to use. The default of 2a is correct for most uses, but the following
 34:  *   values are supported: 2a, 2y, 2x. For more information on what these mean,
 35:  *   see http://php.net/security/crypt_blowfish.php.</li>
 36:  *
 37:  *   <li><b>salt:</b> Optional salt string. If provided, it must be a 22
 38:  *   character string containing only characters in the regex range
 39:  *   [./0-9A-Za-z]. It is highly recommended that this parameter be left blank,
 40:  *   in which case the library will generate a suitable salt for you.</li>
 41:  * </ul>
 42:  *
 43:  * This module uses PHP's native crypt() function, which has had native support
 44:  * for BCrypt since 5.3.0. PHP 5.3.7 introduced support for the 2x and 2y
 45:  * identifiers, and applications running on older versions will not be able
 46:  * to use the ident parameter with these values.
 47:  *
 48:  * @package PHPassLib\Hashes
 49:  * @author Ryan Chouinard <rchouinard@gmail.com>
 50:  * @copyright Copyright (c) 2012, Ryan Chouinard
 51:  * @license MIT License - http://www.opensource.org/licenses/mit-license.php
 52:  */
 53: class BCrypt implements Hash
 54: {
 55: 
 56:     /**
 57:      * Generate a config string from an array.
 58:      *
 59:      * @param array $config Array of configuration options.
 60:      * @return string Configuration string.
 61:      * @throws InvalidArgumentException Throws an InvalidArgumentException if
 62:      *     any passed-in configuration options are invalid.
 63:      */
 64:     public static function genConfig(array $config = array ())
 65:     {
 66:         $defaults = array (
 67:             'ident' => '2a',
 68:             'rounds' => 12,
 69:             'salt' => self::genSalt(),
 70:         );
 71:         $config = array_merge($defaults, array_change_key_case($config, CASE_LOWER));
 72: 
 73:         $string = '*1';
 74:         if (self::validateOptions($config)) {
 75:             $string = sprintf('$%s$%02d$%s', $config['ident'], (int) $config['rounds'], $config['salt']);
 76:         }
 77: 
 78:         return $string;
 79:     }
 80: 
 81:     /**
 82:      * Parse a config string into an array.
 83:      *
 84:      * @param string $config Configuration string.
 85:      * @return array Array of configuration options or false on failure.
 86:      */
 87:     public static function parseConfig($config)
 88:     {
 89:         $options = false;
 90:         $matches = array ();
 91:         if (preg_match('/^\$(2a|2y|2x)\$(\d{2})\$([\.\/0-9A-Za-z]{22})/', $config, $matches)) {
 92:             $options = array (
 93:                 'ident' => $matches[1],
 94:                 'rounds' => (int) $matches[2],
 95:                 'salt' => $matches[3],
 96:             );
 97: 
 98:             try {
 99:                 self::validateOptions($options);
100:             } catch (InvalidArgumentException $e) {
101:                 $options = false;
102:             }
103:         }
104: 
105:         return $options;
106:     }
107: 
108:     /**
109:      * Generate a password hash using a config string.
110:      *
111:      * @param string $password Password string.
112:      * @param string $config Configuration string.
113:      * @return string Returns the hash string on success. On failure, one of
114:      *     *0 or *1 is returned.
115:      */
116:     public static function genHash($password, $config)
117:     {
118:         $hash = crypt($password, $config);
119:         if (!preg_match('/^\$(?:2a|2y|2x)\$\d{2}\$[\.\/0-9A-Za-z]{53}$/', $hash)) {
120:             $hash = ($config == '*0') ? '*1' : '*0';
121:         }
122: 
123:         return $hash;
124:     }
125: 
126:     /**
127:      * Generate a password hash using a config string or array.
128:      *
129:      * @param string $password Password string.
130:      * @param string|array $config Optional config string or array of options.
131:      * @return string Returns the hash string on success. On failure, one of
132:      *     *0 or *1 is returned.
133:      * @throws InvalidArgumentException Throws an InvalidArgumentException if
134:      *     any passed-in configuration options are invalid.
135:      */
136:     public static function hash($password, $config = array ())
137:     {
138:         if (is_array($config)) {
139:             $config = self::genConfig($config);
140:         }
141: 
142:         return self::genHash($password, $config);
143:     }
144: 
145:     /**
146:      * Verify a password against a hash string.
147:      *
148:      * @param string $password Password string.
149:      * @param string $hash Hash string.
150:      * @return boolean Returns true if the password matches, false otherwise.
151:      */
152:     public static function verify($password, $hash)
153:     {
154:         return ($hash === self::hash($password, $hash));
155:     }
156: 
157:     /**
158:      * @param string $input
159:      * @return string
160:      */
161:     protected static function genSalt($input = null)
162:     {
163:         if (!$input) {
164:             $input = Utilities::genRandomBytes(16);
165:         }
166:         $count = strlen($input);
167: 
168:         $atoi64 = './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
169:         $output = '';
170:         $i = 0;
171:         do {
172:             $c1 = ord($input[$i++]);
173:             $output .= $atoi64[$c1 >> 2];
174:             $c1 = ($c1 & 0x03) << 4;
175:             if ($i >= $count) {
176:                 $output .= $atoi64[$c1];
177:                 break;
178:             }
179: 
180:             $c2 = ord($input[$i++]);
181:             $c1 |= $c2 >> 4;
182:             $output .= $atoi64[$c1];
183:             $c1 = ($c2 & 0x0f) << 2;
184: 
185:             $c2 = ord($input[$i++]);
186:             $c1 |= $c2 >> 6;
187:             $output .= $atoi64[$c1];
188:             $output .= $atoi64[$c2 & 0x3f];
189:         } while (1);
190: 
191:         return $output;
192:     }
193: 
194:     /**
195:      * @param array $options
196:      * @return boolean
197:      * @throws InvalidArgumentException
198:      */
199:     protected static function validateOptions(array $options)
200:     {
201:         $options = array_change_key_case($options, CASE_LOWER);
202:         foreach ($options as $option => $value) switch ($option) {
203: 
204:             case 'ident':
205:                 $idents = (version_compare('5.3.7', PHP_VERSION) === 1)
206:                     ? array ('2a') // <= 5.3.6
207:                     : array ('2a', '2y', '2x'); // >= 5.3.7
208:                 if (!in_array($value, $idents)) {
209:                     throw new InvalidArgumentException('Invalid ident parameter');
210:                 }
211:                 break;
212: 
213:             case 'rounds':
214:                 if ($value < 4 || $value > 31) {
215:                     throw new InvalidArgumentException('Invalid rounds parameter');
216:                 }
217:                 break;
218: 
219:             case 'salt':
220:                 if (!preg_match('/^[\.\/0-9A-Za-z]{22}$/', $value)) {
221:                     throw new InvalidArgumentException('Invalid salt parameter');
222:                 }
223:                 break;
224: 
225:             default:
226:                 break;
227: 
228:         }
229: 
230:         return true;
231:     }
232: 
233: }
234: 
PHP Password Library API documentation generated by ApiGen 2.8.0