所以我正在试验bcrypt.我有一个类(如下所示,我从http://www.firedartstudios.com/articles/read/php-security-how-to-safely-store-your-passwords获得),其中有3个函数.第一个是生成随机Salt,第二个是使用第一个生成的Salt生成哈希,最后一个是通过将其与哈希密码进行比较来验证提供的密码.
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'并使用验证功能,我会认为密码匹配.如果我输入错误的密码,我会弄错.我的问题是这怎么可能?随机生成的盐怎么样?怎么没有任何影响?
好好看看你正在处理的价值观.生成的随机盐将是:
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
是一样的.