Hash a password using a secure stretched hash.
By using a salt and repeated hashing the password is "stretched". Its security is increased because it becomes much more computationally costly for an attacker to try to break the hash by brute-force computation of the hashes of a large number of plain-text words or strings to find a match.
String $algo: The string name of a hashing algorithm usable by hash(), like 'sha256'.
String $password: The plain-text password to hash.
String $setting: An existing hash or the output of $this->generateSalt(). Must be at least 12 characters (the settings and salt).
String A string containing the hashed password (and salt) or FALSE on failure. The return string will be truncated at HASH_LENGTH characters max.
protected function crypt($algo, $password, $setting) {
// The first 12 characters of an existing hash are its setting string.
$setting = substr($setting, 0, 12);
if ($setting[0] != '$' || $setting[2] != '$') {
return FALSE;
}
$count_log2 = $this
->getCountLog2($setting);
// Stored hashes may have been crypted with any iteration count. However we
// do not allow applying the algorithm for unreasonable low and heigh
// values respectively.
if ($count_log2 != $this
->enforceLog2Boundaries($count_log2)) {
return FALSE;
}
$salt = substr($setting, 4, 8);
// Hashes must have an 8 character salt.
if (strlen($salt) != 8) {
return FALSE;
}
// Convert the base 2 logarithm into an integer.
$count = 1 << $count_log2;
// We rely on the hash() function being available in PHP 5.2+.
$hash = hash($algo, $salt . $password, TRUE);
do {
$hash = hash($algo, $hash . $password, TRUE);
} while (--$count);
$len = strlen($hash);
$output = $setting . $this
->base64Encode($hash, $len);
// $this->base64Encode() of a 16 byte MD5 will always be 22 characters.
// $this->base64Encode() of a 64 byte sha512 will always be 86 characters.
$expected = 12 + ceil(8 * $len / 6);
return strlen($output) == $expected ? substr($output, 0, static::HASH_LENGTH) : FALSE;
}