Overview

Packages

  • application
    • commands
    • components
      • actions
      • filters
      • leftWidget
      • permissions
      • sortableWidget
      • util
      • webupdater
      • x2flow
        • actions
        • triggers
      • X2GridView
      • X2Settings
    • controllers
    • models
      • embedded
    • modules
      • accounts
        • controllers
        • models
      • actions
        • controllers
        • models
      • calendar
        • controllers
        • models
      • charts
        • models
      • contacts
        • controllers
        • models
      • docs
        • components
        • controllers
        • models
      • groups
        • controllers
        • models
      • marketing
        • components
        • controllers
        • models
      • media
        • controllers
        • models
      • mobile
        • components
      • opportunities
        • controllers
        • models
      • products
        • controllers
        • models
      • quotes
        • controllers
        • models
      • services
        • controllers
        • models
      • template
        • models
      • users
        • controllers
        • models
      • workflow
        • controllers
        • models
      • x2Leads
        • controllers
        • models
  • Net
  • None
  • PHP
  • system
    • base
    • caching
      • dependencies
    • collections
    • console
    • db
      • ar
      • schema
        • cubrid
        • mssql
        • mysql
        • oci
        • pgsql
        • sqlite
    • i18n
      • gettext
    • logging
    • test
    • utils
    • validators
    • web
      • actions
      • auth
      • filters
      • form
      • helpers
      • renderers
      • services
      • widgets
        • captcha
        • pagers
  • Text
    • Highlighter
  • zii
    • behaviors
    • widgets
      • grid
      • jui

Classes

  • CDateTimeParser
  • CFileHelper
  • CFormatter
  • CLocalizedFormatter
  • CMarkdownParser
  • CPasswordHelper
  • CPropertyValue
  • CTimestamp
  • CVarDumper
  • Overview
  • Package
  • Class
  • Tree
  1: <?php
  2: /**
  3:  * CPasswordHelper class file.
  4:  *
  5:  * @author Tom Worster <fsb@thefsb.org>
  6:  * @link http://www.yiiframework.com/
  7:  * @copyright 2008-2013 Yii Software LLC
  8:  * @license http://www.yiiframework.com/license/
  9:  */
 10: 
 11: /**
 12:  * CPasswordHelper provides a simple API for secure password hashing and verification.
 13:  *
 14:  * CPasswordHelper uses the Blowfish hash algorithm available in many PHP runtime
 15:  * environments through the PHP {@link http://php.net/manual/en/function.crypt.php crypt()}
 16:  * built-in function. As of Dec 2012 it is the strongest algorithm available in PHP
 17:  * and the only algorithm without some security concerns surrounding it. For this reason,
 18:  * CPasswordHelper fails to initialize when run in and environment that does not have
 19:  * crypt() and its Blowfish option. Systems with the option include:
 20:  * (1) Most *nix systems since PHP 4 (the algorithm is part of the library function crypt(3));
 21:  * (2) All PHP systems since 5.3.0; (3) All PHP systems with the
 22:  * {@link http://www.hardened-php.net/suhosin/ Suhosin patch}.
 23:  * For more information about password hashing, crypt() and Blowfish, please read
 24:  * the Yii Wiki article
 25:  * {@link http://www.yiiframework.com/wiki/425/use-crypt-for-password-storage/ Use crypt() for password storage}.
 26:  * and the
 27:  * PHP RFC {@link http://wiki.php.net/rfc/password_hash Adding simple password hashing API}.
 28:  *
 29:  * CPasswordHelper throws an exception if the Blowfish hash algorithm is not
 30:  * available in the runtime PHP's crypt() function. It can be used as follows
 31:  *
 32:  * Generate a hash from a password:
 33:  * <pre>
 34:  * $hash = CPasswordHelper::hashPassword($password);
 35:  * </pre>
 36:  * This hash can be stored in a database (e.g. CHAR(60) CHARACTER SET latin1). The
 37:  * hash is usually generated and saved to the database when the user enters a new password.
 38:  * But it can also be useful to generate and save a hash after validating a user's
 39:  * password in order to change the cost or refresh the salt.
 40:  *
 41:  * To verify a password, fetch the user's saved hash from the database (into $hash) and:
 42:  * <pre>
 43:  * if (CPasswordHelper::verifyPassword($password, $hash))
 44:  *     // password is good
 45:  * else
 46:  *     // password is bad
 47:  * </pre>
 48:  *
 49:  * @author Tom Worster <fsb@thefsb.org>
 50:  * @package system.utils
 51:  * @since 1.1.14
 52:  */
 53: class CPasswordHelper
 54: {
 55:     /**
 56:      * Check for availability of PHP crypt() with the Blowfish hash option.
 57:      * @throws CException if the runtime system does not have PHP crypt() or its Blowfish hash option.
 58:      */
 59:     protected static function checkBlowfish()
 60:     {
 61:         if(!function_exists('crypt'))
 62:             throw new CException(Yii::t('yii','{class} requires the PHP crypt() function. This system does not have it.',
 63:                 array('{class}'=>__CLASS__)));
 64: 
 65:         if(!defined('CRYPT_BLOWFISH') || !CRYPT_BLOWFISH)
 66:             throw new CException(Yii::t('yii',
 67:                 '{class} requires the Blowfish option of the PHP crypt() function. This system does not have it.',
 68:                 array('{class}'=>__CLASS__)));
 69:     }
 70: 
 71:     /**
 72:      * Generate a secure hash from a password and a random salt.
 73:      *
 74:      * Uses the
 75:      * PHP {@link http://php.net/manual/en/function.crypt.php crypt()} built-in function
 76:      * with the Blowfish hash option.
 77:      *
 78:      * @param string $password The password to be hashed.
 79:      * @param int $cost Cost parameter used by the Blowfish hash algorithm.
 80:      * The higher the value of cost,
 81:      * the longer it takes to generate the hash and to verify a password against it. Higher cost
 82:      * therefore slows down a brute-force attack. For best protection against brute for attacks,
 83:      * set it to the highest value that is tolerable on production servers. The time taken to
 84:      * compute the hash doubles for every increment by one of $cost. So, for example, if the
 85:      * hash takes 1 second to compute when $cost is 14 then then the compute time varies as
 86:      * 2^($cost - 14) seconds.
 87:      * @return string The password hash string, always 60 ASCII characters.
 88:      * @throws CException on bad password parameter or if crypt() with Blowfish hash is not available.
 89:      */
 90:     public static function hashPassword($password,$cost=13)
 91:     {
 92:         self::checkBlowfish();
 93:         $salt=self::generateSalt($cost);
 94:         $hash=crypt($password,$salt);
 95: 
 96:         if(!is_string($hash) || (function_exists('mb_strlen') ? mb_strlen($hash, '8bit') : strlen($hash))<32)
 97:             throw new CException(Yii::t('yii','Internal error while generating hash.'));
 98: 
 99:         return $hash;
100:     }
101: 
102:     /**
103:      * Verify a password against a hash.
104:      *
105:      * @param string $password The password to verify. If password is empty or not a string, method will return false.
106:      * @param string $hash The hash to verify the password against.
107:      * @return bool True if the password matches the hash.
108:      * @throws CException on bad password or hash parameters or if crypt() with Blowfish hash is not available.
109:      */
110:     public static function verifyPassword($password, $hash)
111:     {
112:         self::checkBlowfish();
113:         if(!is_string($password) || $password==='')
114:             return false;
115: 
116:         if (!$password || !preg_match('{^\$2[axy]\$(\d\d)\$[\./0-9A-Za-z]{22}}',$hash,$matches) ||
117:             $matches[1]<4 || $matches[1]>31)
118:             return false;
119: 
120:         $test=crypt($password,$hash);
121:         if(!is_string($test) || strlen($test)<32)
122:             return false;
123: 
124:         return self::same($test, $hash);
125:     }
126: 
127:     /**
128:      * Check for sameness of two strings using an algorithm with timing
129:      * independent of the string values if the subject strings are of equal length.
130:      *
131:      * The function can be useful to prevent timing attacks. For example, if $a and $b
132:      * are both hash values from the same algorithm, then the timing of this function
133:      * does not reveal whether or not there is a match.
134:      *
135:      * NOTE: timing is affected if $a and $b are different lengths or either is not a
136:      * string. For the purpose of checking password hash this does not reveal information
137:      * useful to an attacker.
138:      *
139:      * @see http://blog.astrumfutura.com/2010/10/nanosecond-scale-remote-timing-attacks-on-php-applications-time-to-take-them-seriously/
140:      * @see http://codereview.stackexchange.com/questions/13512
141:      * @see https://github.com/ircmaxell/password_compat/blob/master/lib/password.php
142:      *
143:      * @param string $a First subject string to compare.
144:      * @param string $b Second subject string to compare.
145:      * @return bool true if the strings are the same, false if they are different or if
146:      * either is not a string.
147:      */
148:     public static function same($a,$b)
149:     {
150:         if(!is_string($a) || !is_string($b))
151:             return false;
152: 
153:         $mb=function_exists('mb_strlen');
154:         $length=$mb ? mb_strlen($a,'8bit') : strlen($a);
155:         if($length!==($mb ? mb_strlen($b,'8bit') : strlen($b)))
156:             return false;
157: 
158:         $check=0;
159:         for($i=0;$i<$length;$i+=1)
160:             $check|=(ord($a[$i])^ord($b[$i]));
161: 
162:         return $check===0;
163:     }
164: 
165:     /**
166:      * Generates a salt that can be used to generate a password hash.
167:      *
168:      * The PHP {@link http://php.net/manual/en/function.crypt.php crypt()} built-in function
169:      * requires, for the Blowfish hash algorithm, a salt string in a specific format:
170:      *  "$2y$" (in which the "y" may be replaced by "a" or "y" see PHP manual for details),
171:      *  a two digit cost parameter,
172:      *  "$",
173:      *  22 characters from the alphabet "./0-9A-Za-z".
174:      *
175:      * @param int $cost Cost parameter used by the Blowfish hash algorithm.
176:      * @return string the random salt value.
177:      * @throws CException in case of invalid cost number
178:      */
179:     public static function generateSalt($cost=13)
180:     {
181:         if(!is_numeric($cost))
182:             throw new CException(Yii::t('yii','{class}::$cost must be a number.',array('{class}'=>__CLASS__)));
183: 
184:         $cost=(int)$cost;
185:         if($cost<4 || $cost>31)
186:             throw new CException(Yii::t('yii','{class}::$cost must be between 4 and 31.',array('{class}'=>__CLASS__)));
187: 
188:         if(($random=Yii::app()->getSecurityManager()->generateRandomString(22,true))===false)
189:             if(($random=Yii::app()->getSecurityManager()->generateRandomString(22,false))===false)
190:                 throw new CException(Yii::t('yii','Unable to generate random string.'));
191:         return sprintf('$2y$%02d$',$cost).strtr($random,array('_'=>'.','~'=>'/'));
192:     }
193: }
194: 
API documentation generated by ApiGen 2.8.0