在 PHP 手册中指出:
CRYPT_BLOWFISH - Blowfish 使用盐进行散列,如下所示:“$2a$”,一个两位数的成本参数,“$”,以及来自字母表“./0-9A-Za-z”的 22 位数字。
我意识到盐的长度是 22。我编写了以下代码并注意到salt的输出长度是21。
$encoded = crypt('pass','$2a$08$QAZXSWEDCVFRTGBNHYUJMK'); // Lenght of Q . . . K is 22
echo $encoded;
Run Code Online (Sandbox Code Playgroud)
输出:
$2a$08$QAZXSWEDCVFRTGBNHYUJM./CR85.t4YytTnmLXsRJMfbYWopbT8Nu
K在盐中不存在:QAZXSWEDCVFRTGBNHYUJM
有什么我不明白的吗?
这是由于盐是如何编码的。实际盐是 128 位,但crypt格式中的编码盐是 22 个字符·8 位/字符·3/4 = 132 位。所以实际上没有使用 4 位编码盐。
这也意味着有 16 个编码的盐会产生相同的哈希值,因为它们的最低有效字符的前四位是相同的:
$hashes = array();
$chars = array_merge(array('.','/'), range('A','Z'), range('a','z'), range('0','9'));
foreach ($chars as $char) {
$salt = 'QAZXSWEDCVFRTGBNHYUJM'.$char;
$hashes[$salt] = crypt('pass','$2a$08$'.$salt);
}
var_dump($hashes);
Run Code Online (Sandbox Code Playgroud)
以下是产生相同散列的编码盐:
QAZXSWEDCVFRTGBNHYUJM.
QAZXSWEDCVFRTGBNHYUJM/
QAZXSWEDCVFRTGBNHYUJMA
QAZXSWEDCVFRTGBNHYUJMB
QAZXSWEDCVFRTGBNHYUJMC
QAZXSWEDCVFRTGBNHYUJMD
QAZXSWEDCVFRTGBNHYUJME
QAZXSWEDCVFRTGBNHYUJMF
QAZXSWEDCVFRTGBNHYUJMG
QAZXSWEDCVFRTGBNHYUJMH
QAZXSWEDCVFRTGBNHYUJMI
QAZXSWEDCVFRTGBNHYUJMJ
QAZXSWEDCVFRTGBNHYUJMK
QAZXSWEDCVFRTGBNHYUJML
QAZXSWEDCVFRTGBNHYUJMM
QAZXSWEDCVFRTGBNHYUJMN
Run Code Online (Sandbox Code Playgroud)
crypt可能只是使用第一个编码内部使用的 128 位盐,即QAZXSWEDCVFRTGBNHYUJM..