【发布时间】:2011-01-14 14:33:00
【问题描述】:
这个问题与 PHP 的 crypt() 实现有关。对于这个问题,盐的前 7 个字符不计算在内,因此盐 '$2a$07$a' 的长度为 1,因为它只有盐的 1 个字符和元数据的七个字符。
当使用长度超过 22 个字符的 salt 字符串时,生成的哈希值没有变化(即截断),而当使用长度小于 21 个字符的字符串时,salt 将自动被填充(显然是 '$' 字符);这相当简单。但是,如果给定一个盐 20 个字符和一个盐 21 个字符,其中除了 21 长度盐的最后一个字符之外,两者相同,则两个散列字符串将相同。一个长度为 22 个字符的 salt,除了最后一个字符外,与 21 个长度的 salt 相同,hash 将再次不同。
代码示例:
$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 中,offset (28, 4) 为da$.,而在salt_21 中,offset (28, 4) 为da2.;但是,重要的是要注意生成的字符串包括哈希、盐以及生成盐的指令(即$2a$07$);实际上,发生差异的部分仍然是盐。实际哈希值不变为UxGYN739wLkV5PGoR1XA4EvNVPjwylG。
因此,这实际上不是产生的哈希值的差异,而是用于存储哈希值的盐的差异,这正是手头的问题:两个盐生成相同的哈希值。
记住:输出将采用以下格式:
"$2a$##$saltsaltsaltsaltsaltsaHASHhashHASHhashHASHhashHASHhash"
// ^ Hash Starts Here, offset 28,32
其中 ## 是 log-base-2,确定算法运行的迭代次数
编辑 2:
在 cmets 中,要求我发布一些附加信息,因为用户无法重现我的输出。执行以下代码:
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)
希望这会有所帮助。
【问题讨论】:
-
如果您快速浏览一下,它们看起来相同,但有 1 个字符差异
-
@Craig:实际上,那部分实际上仍然是哈希的盐,而不是哈希本身。哈希只是最后 32 个字符。
-
嗯好吧,对不起,让我看起来很愚蠢:D
标签: php hash salt blowfish crypt