这个问题与 PHP 的crypt()
. 对于这个问题,不计算盐的前 7 个字符,因此盐 ' $2a$07$a
' 的长度为 1,因为它只有盐的 1 个字符和元数据的七个字符。
当使用长度超过 22 个字符的 salt 字符串时,生成的哈希值没有变化(即截断),而当使用少于 21 个字符的字符串时,salt 将自动被填充($
显然是用 ' ' 字符);这相当简单。但是,如果给定一个盐 20 个字符和一个盐 21 个字符,其中除了 21 长度盐的最后一个字符之外,两者相同,则两个散列字符串将相同。一个长度为 22 个字符的盐,除了最后一个字符外,它与 21 个长度的盐相同,哈希将再次不同。
代码示例:
$foo = 'bar';
$salt_xx = '$2a$07$';
$salt_19 = $salt_xx . 'b1b2ee48991281a439d';
$salt_20 = $salt_19 . 'a';
$salt_21 = $salt_20 . '2';
$salt_22 = $salt_21 . 'b';
var_dump(
crypt($foo, $salt_19),
crypt($foo, $salt_20),
crypt($foo, $salt_21),
crypt($foo, $salt_22)
);
将产生:
string(60) "$2a$07$b1b2ee48991281a439d$$.dEUdhUoQXVqUieLTCp0cFVolhFcbuNi"
string(60) "$2a$07$b1b2ee48991281a439da$.UxGYN739wLkV5PGoR1XA4EvNVPjwylG"
string(60) "$2a$07$b1b2ee48991281a439da2.UxGYN739wLkV5PGoR1XA4EvNVPjwylG"
string(60) "$2a$07$b1b2ee48991281a439da2O4AH0.y/AsOuzMpI.f4sBs8E2hQjPUQq"
为什么是这样?
编辑:
一些用户注意到整个字符串存在差异,这是真的。在salt_20
, 偏移量 (28, 4) 是da$.
, 而在salt_21
, 偏移量 (28, 4) 是da2.
; 但是,重要的是要注意生成的字符串包括哈希、盐以及生成盐的指令(即$2a$07$
);实际上,发生差异的部分仍然是盐。实际的哈希值不变UxGYN739wLkV5PGoR1XA4EvNVPjwylG
。
因此,这实际上不是产生的哈希的差异,而是用于存储哈希的盐的差异,这正是当前的问题:两个盐生成相同的哈希。
Rembmer:输出将采用以下格式:
"$2a$##$saltsaltsaltsaltsaltsaHASHhashHASHhashHASHhashHASHhash"
// ^ Hash Starts Here, offset 28,32
其中 ## 是 log-base-2 确定算法运行的迭代次数
编辑2:
在评论中,要求我发布一些附加信息,因为用户无法重现我的输出。执行以下代码:
var_dump(
PHP_VERSION,
PHP_OS,
CRYPT_SALT_LENGTH,
CRYPT_STD_DES,
CRYPT_EXT_DES,
CRYPT_MD5,
CRYPT_BLOWFISH
);
产生以下输出:
string(5) "5.3.0"
string(5) "WINNT"
int(60)
int(1)
int(1)
int(1)
int(1)
希望这可以帮助。