在使用静态盐进行足够多的迭代后,所有哈希不会发生冲突吗?

信息安全 哈希
2021-09-03 17:45:16

我们都知道我们应该采用相当慢的散列算法,对密码进行加盐,并运行散列进行多次迭代。假设我几乎遵循除了一条规则之外的所有内容,并且我有一个静态盐。像这样的东西:

password = 'yaypuppies' + some_static_salt

1000.times do
    password = amazing_hash(password)
end

现在password是一个伟大的哈希和盐渍的东西。世界一切安好。

但是如果我们运行它更多的迭代呢?

3000000000000000000.times do # 3 quintillion
    password = amazing_hash(password)
end

理论上,许多密码会发生冲突吗?即这会发生吗?

pass1 -> lkajsdlkajslkjda > 23oiuolekeq > n,mznxc,mnzxc > common_thing > 987123oijd > liasjdlkajsd > 09893oiehd > 09uasodij
pass2 -> loiuoklncas > 9830984cjlas > ioasjdknckauyieuh > common_thing > 987123oijd > liasjdlkajsd > 09893oiehd > 09uasodij

两个密码最终都散列到09uasodij?

使用非随机密码盐,每次添加的迭代都会增加冲突的可能性吗?

4个回答

迭代哈希函数时,会减少空间,但不会减少到一个点。对于随机选择的函数(您的“amazing_hash”应该接近),具有n位输出,您可能期望最终达到大小为2 n/2左右的循环,即如果您使用一个像样的输出大小(例如,n = 256)。

有关更详细的说明,请参阅此答案我在这里复制了该答案的方案,因为它很吸引眼球:

迭代哈希函数的“rho”图

当然,“静态盐”不是盐;这只是意味着您正在使用自定义哈希函数。盐是为了阻止并行攻击:当攻击者试图破解 10 个密码时,他的成本是破解一个密码的 10 倍。使用“静态加盐”,破解 10 个密码的成本不超过破解 1 个,即加盐完全失败。

盐不是为了避免冲突,特别是因为冲突不是密码散列的问题。您应该担心的是原像电阻。

我不这么认为,只是因为哈希几乎肯定会在不同的点达到“common_thing”。一个密码可能在第 10,000 步时必须为“common_thing”,而另一个密码在第 100,000 步时可能必须为“common_thing”。这些链将并行跟踪彼此,但在算法结束时它们不一定在同一点。

无论周期是大是小,概率仍然很低。如果有许多小循环,则一个值不太可能出现在其中任何一个特定的循环中;如果有几个大循环,则该值不太可能在同一点结束链。

正如其他人所说,您不使用静态盐的原因是为了防止攻击者创建彩虹表。我不确定静态盐是否会随着时间的推移对碰撞次数产生任何影响,当然除了相同的值将散列到相同的值之外。

不过,对这一切持保留态度;我是加密爱好者,但不是专家。如果其他人在这方面有更多的了解,我很想听到更多关于哈希算法循环的信息。

与静态盐有关的问题不是增加了碰撞的机会(没有)。只要所有密码具有相同的迭代次数,重复运行相同的算法就不会导致冲突增加(具有良好的散列函数)。

真正的问题是赔率游戏。

如果攻击者知道用于生成散列密码的代码(用于注入盐的机制,以及通过散列循环的迭代次数),那么攻击者可以重现您的算法。假设攻击者也知道你的实际散列结果。他们能算出你的实际密码吗?

使用该算法,攻击者可以将常用密码字典输入算法,并查找与您的散列结果匹配的内容。诚然,这可能需要很长时间,但最终攻击者可能会猜到您的密码。

问题是,您可能有一个“难以猜测”的密码……但是,系统中的其他人呢?您的散列密码只是众多密码之一。如果该站点是“堆栈交换”,则有成千上万的用户。如果他们都使用相同的盐,那么像这样的字典攻击可以检查所有用户的哈希密码是否匹配。如果他们得到匹配,那么他们也猜到了该用户的密码。这是一个数字游戏。如果系统中有 10,000 个用户,那么找到简单密码的几率会提高 10,000,可能远不止于此。

现在,如果您为每个用户使用唯一的盐,那么为用户获取匹配的哈希是没有用的,除非该用户也具有与您在算法中相同的盐。

换句话说,使用唯一的盐,您一次只能攻击一个用户帐户。使用静态盐,您可以一次攻击它们......并且命中的机会要大得多。

理论上,是的,这肯定会发生,因为“很多”和“很多”的足够定义。在实践中,不,这永远不会发生。安全加密散列函数的要点是“一大堆”和“很多”是无法达到的大得离谱的数字。如果你能接触到它们,要么是对算法的严重攻击,你不应该使用它,要么它不够大,你不应该使用它。

例如,以 MD5 为例。哈希是 128 位长。理想情况下,平均而言,您应该在 2 64次尝试中发现一次碰撞,或大约 18 quintillion。这将非常昂贵,但可以使用足够的硬件。然而,MD5 在密码分析中遭受了灾难性的打击,并且有些攻击可以在瞬间发现冲突。

另一方面,还有 SHA-256。它是 256 位——不可能计算 2 128个哈希,并且没有针对它的重大攻击。

因此,如果您使用像 SHA-256 或 SHA-512 这样的体面的散列,这不是问题。即使您不是,也不应该担心。我想不出为什么用户会尝试创建一个故意导致冲突的密码,并且使用大量迭代是不切实际的,除非您希望它需要数十年的计算才能让您的用户登录。(除了其他答案中提到的考虑因素之外。)

从本质上讲,我的问题是:对于每个密码的非随机盐,每次添加的迭代都会增加冲突的可能性吗?

是的,确实如此,从“如此接近于零,它永远不会发生”到“仍然如此接近于零,它永远不会发生”。