所以我正在尝试使用bcrypt。我有一个课程(如下所示,我从http://www.firedartstudios.com/articles/read/php-security-how-to-safely-store-your-passwords获得),其中有3个函数。第一个是生成随机Salt,第二个是使用第一个生成的Salt生成哈希,最后一个是通过将其与哈希密码进行比较来验证提供的密码。
<?php
/* Bcrypt Example */
class bcrypt {
private $rounds;
public function __construct($rounds = 12) {
if(CRYPT_BLOWFISH != 1) {
throw new Exception("Bcrypt is not supported on this server, please see the following to learn more: http://php.net/crypt");
}
$this->rounds = $rounds;
}
/* Gen Salt */
public function genSalt() {
/* openssl_random_pseudo_bytes(16) Fallback */
$seed = '';
for($i = 0; $i < 16; $i++) {
$seed .= chr(mt_rand(0, 255));
}
/* GenSalt */
$salt = substr(strtr(base64_encode($seed), '+', '.'), 0, 22);
/* Return */
return $salt;
}
/* Gen Hash */
public function genHash($password) {
/* Explain '$2y$' . $this->rounds . '$' */
/* 2a selects bcrypt algorithm */
/* $this->rounds is the workload factor */
/* GenHash */
$hash = crypt($password, '$2y$' . $this->rounds . '$' . $this->genSalt());
/* Return */
return $hash;
}
/* Verify Password */
public function verify($password, $existingHash) {
/* Hash new password with old hash */
$hash = crypt($password, $existingHash);
/* Do Hashs match? */
if($hash === $existingHash) {
return true;
} else {
return false;
}
}
}
/* Next the Usage */
/* Start Instance */
$bcrypt = new bcrypt(12);
/* Two create a Hash you do */
echo 'Bcrypt Password: ' . $bcrypt->genHash('password');
/* Two verify a hash you do */
$HashFromDB = $bcrypt->genHash('password'); /* This is an example you would draw the hash from your db */
echo 'Verify Password: ' . $bcrypt->verify('password', $HashFromDB);
?>
现在,如果我生成一个带有'password'的哈希值,我会得到一个哈希密码,它接受了randmonly生成的Salt。接下来,如果我再次输入'password'并使用验证功能,我会认为密码匹配。如果我输入错误的密码,我会弄错。我的问题是这怎么可能?随机生成的盐怎么样?怎么没有任何影响?
答案 0 :(得分:14)
好好看看你正在处理的价值观。产生的随机盐将是:
abcdefg...
喂入crypt
的内容如下:
crypt($password, '$2y$10$abcdefg...')
| | |
| | +- the salt
| +- the cost parameter
+- the algorithm type
结果如下:
$2y$10$abcdefg...123456789...
| | | |
| | | +- the password hash
| | +- the salt
| +- the cost parameter
+- the algorithm type
换句话说,结果哈希的第一部分与crypt
函数的原始输入相同;它包含算法类型和参数,随机盐和哈希结果。
Input: $password + $2y$10$abcdefg...
Output: $2y$10$abcdefg...123456789...
^^^^^^^^^^^^^^^^^
first part identical
当您确认密码时,再次需要相同的原始盐。只有使用相同的salt才能将相同的密码哈希到相同的哈希。并且它仍然存在于散列中,其格式可以传递给crypt
,以重复与生成散列时相同的操作。这就是为什么你需要将密码和哈希都提供给验证函数的原因:
crypt($passwordToCheck, '$2y$10$abcdefg...123456789...')
crypt
获取第一个定义的字符数,包括abcdefg...
,并将其余部分抛弃(这就是为什么salt需要是固定数量的字符)。因此它等于以前的操作:
crypt($passwordToCheck, '$2y$10$abcdefg...')
当且仅当 $passwordToCheck
相同时,才会生成相同的哈希值。