Package | system.utils |
---|---|
Inheritance | class CPasswordHelper |
Since | 1.1.14 |
Source Code | framework/utils/CPasswordHelper.php |
$hash = CPasswordHelper::hashPassword($password);This hash can be stored in a database (e.g. CHAR(60) CHARACTER SET latin1). The hash is usually generated and saved to the database when the user enters a new password. But it can also be useful to generate and save a hash after validating a user's password in order to change the cost or refresh the salt.
if (CPasswordHelper::verifyPassword($password, $hash)) // password is good else // password is bad
Method | Description | Defined By |
---|---|---|
generateSalt() | Generates a salt that can be used to generate a password hash. | CPasswordHelper |
hashPassword() | Generate a secure hash from a password and a random salt. | CPasswordHelper |
same() | Check for sameness of two strings using an algorithm with timing | CPasswordHelper |
verifyPassword() | Verify a password against a hash. | CPasswordHelper |
Method | Description | Defined By |
---|---|---|
checkBlowfish() | Check for availability of PHP crypt() with the Blowfish hash option. | CPasswordHelper |
protected static void checkBlowfish()
|
protected static function checkBlowfish()
{
if(!function_exists('crypt'))
throw new CException(Yii::t('yii','{class} requires the PHP crypt() function. This system does not have it.',
array('{class}'=>__CLASS__)));
if(!defined('CRYPT_BLOWFISH') || !CRYPT_BLOWFISH)
throw new CException(Yii::t('yii',
'{class} requires the Blowfish option of the PHP crypt() function. This system does not have it.',
array('{class}'=>__CLASS__)));
}
Check for availability of PHP crypt() with the Blowfish hash option.
public static string generateSalt(int $cost=13)
| ||
$cost | int | Cost parameter used by the Blowfish hash algorithm. |
{return} | string | the random salt value. |
public static function generateSalt($cost=13)
{
if(!is_numeric($cost))
throw new CException(Yii::t('yii','{class}::$cost must be a number.',array('{class}'=>__CLASS__)));
$cost=(int)$cost;
if($cost<4 || $cost>31)
throw new CException(Yii::t('yii','{class}::$cost must be between 4 and 31.',array('{class}'=>__CLASS__)));
if(($random=Yii::app()->getSecurityManager()->generateRandomString(22,true))===false)
if(($random=Yii::app()->getSecurityManager()->generateRandomString(22,false))===false)
throw new CException(Yii::t('yii','Unable to generate random string.'));
return sprintf('$2y$%02d$',$cost).strtr($random,array('_'=>'.','~'=>'/'));
}
Generates a salt that can be used to generate a password hash.
The PHP crypt() built-in function
requires, for the Blowfish hash algorithm, a salt string in a specific format:
"$2y$" (in which the "y" may be replaced by "a" or "y" see PHP manual for details),
a two digit cost parameter,
"$",
22 characters from the alphabet "./0-9A-Za-z".
public static string hashPassword(string $password, int $cost=13)
| ||
$password | string | The password to be hashed. |
$cost | int | Cost parameter used by the Blowfish hash algorithm. The higher the value of cost, the longer it takes to generate the hash and to verify a password against it. Higher cost therefore slows down a brute-force attack. For best protection against brute for attacks, set it to the highest value that is tolerable on production servers. The time taken to compute the hash doubles for every increment by one of $cost. So, for example, if the hash takes 1 second to compute when $cost is 14 then then the compute time varies as 2^($cost - 14) seconds. |
{return} | string | The password hash string, always 60 ASCII characters. |
public static function hashPassword($password,$cost=13)
{
self::checkBlowfish();
$salt=self::generateSalt($cost);
$hash=crypt($password,$salt);
if(!is_string($hash) || (function_exists('mb_strlen') ? mb_strlen($hash, '8bit') : strlen($hash))<32)
throw new CException(Yii::t('yii','Internal error while generating hash.'));
return $hash;
}
Generate a secure hash from a password and a random salt.
Uses the
PHP crypt() built-in function
with the Blowfish hash option.
public static bool same(string $a, string $b)
| ||
$a | string | First subject string to compare. |
$b | string | Second subject string to compare. |
{return} | bool | true if the strings are the same, false if they are different or if either is not a string. |
public static function same($a,$b)
{
if(!is_string($a) || !is_string($b))
return false;
$mb=function_exists('mb_strlen');
$length=$mb ? mb_strlen($a,'8bit') : strlen($a);
if($length!==($mb ? mb_strlen($b,'8bit') : strlen($b)))
return false;
$check=0;
for($i=0;$i<$length;$i+=1)
$check|=(ord($a[$i])^ord($b[$i]));
return $check===0;
}
Check for sameness of two strings using an algorithm with timing
independent of the string values if the subject strings are of equal length.
The function can be useful to prevent timing attacks. For example, if $a and $b
are both hash values from the same algorithm, then the timing of this function
does not reveal whether or not there is a match.
NOTE: timing is affected if $a and $b are different lengths or either is not a
string. For the purpose of checking password hash this does not reveal information
useful to an attacker.
public static bool verifyPassword(string $password, string $hash)
| ||
$password | string | The password to verify. If password is empty or not a string, method will return false. |
$hash | string | The hash to verify the password against. |
{return} | bool | True if the password matches the hash. |
public static function verifyPassword($password, $hash)
{
self::checkBlowfish();
if(!is_string($password) || $password==='')
return false;
if (!$password || !preg_match('{^\$2[axy]\$(\d\d)\$[\./0-9A-Za-z]{22}}',$hash,$matches) ||
$matches[1]<4 || $matches[1]>31)
return false;
$test=crypt($password,$hash);
if(!is_string($test) || strlen($test)<32)
return false;
return self::same($test, $hash);
}
Verify a password against a hash.
Signup or Login in order to comment.