因此,我遇到了以下用于哈希密码的算法

function hashpassword($str, $salt)
{
$hashed_password = md5($str);
$hash = md5('more_salt');
$hash = sha1($hash.$salt);
$hashed_password = crc32($hashed_password.$hash);
$hashed_password = sha1($hashed_password.$hash);
$hashed_password = md5($hashed_password.$salt);
return $hashed_password;
}


像这样混合哈希算法会增加还是减少冲突的机会?难道不是最后一个发现最弱链接的情况吗?在我看来,使用crc32似乎是个糟糕的主意,因为它甚至都不是这个意思,但是我不了解其背后的数学原理,因此无法确定它是否是这样。

这看起来像是由知道他们在做什么的人完成的,还是只是有人将他们找到的所有算法都扔在一起,并希望这是一个好的解决方案?

我基本上是什么问的是,这是强还是弱?有明显的问题吗?

评论

中间的那个crc32使得蛮力很容易。由于crc32仅输出32位,因此2 ^ 32中的1个密码将与最终的哈希匹配。

如果您确实担心某个方法可能被破坏,那么通过串联进行某种组合可能会有所帮助。

@DennisJaheruddin我认为。可能是OP使用的任何语言的串联运算符。

@Philipp我也这样认为,但我的意思是,与其通过按照F(G(x))的趋势做一些事情来组合F和G,一种更好的组合函数的方法可能是基于F(X1)的趋势。 F(X2)。 -这只是概念性的,不是实施的建议。

#1 楼


这看起来像是由知道自己在做什么的人完成的,还是只是有人将他们找到的所有算法都扔到了一起,并希望这是一个好的解决方案呢?


显然,这是一个不知道自己在干什么的人。如果他们知道自己在做什么,就不会使用自己的算法(“戴夫,您不是密码学家。请停止。”),他们将使用PBDKF2,bcrypt或scrypt等标准算法之一。 br />
PBKDF2从5.5.0开始就已经存在于PHP的标准库中,并且有许多开放源代码实现稍慢一些,但可以在早期版本中使用。 PBKDF2是否是最佳选择尚有争议,但这是一个合理的选择。



没有任何借口。













用自己的双手滚滚是没有道理的。使用它真的很糟糕。如果用md5替换crc32,该算法就很糟糕,因为它并不慢。密码哈希算法必须很慢才能抵抗暴力猜测。 PBKDF2通过执行与您正在查看的算法类似的操作(重复的哈希)来实现此目的,但是1.哈希被合理地组装在一起,并且2.通常运行数十万次迭代,而不仅仅是几次迭代。 >
算法使用CRC32的方式是一个毁灭性的缺陷。这使得通过蛮力查找密码变得容易。无需猜测:只需几分钟的计算机时间就可以找到有效的密码。这可能不是用户选择的密码,但是会产生相同的哈希值。

关键问题是CRC32仅具有$ 2 ^ {32} $可能的值,大约为40亿。 CPU在短短几秒钟内执行了许多操作。如果您查看哈希的结构,则为F(CRC32(G(password)), salt)FG的确切结构无关紧要,问题在于密码仅影响进入CRC32函数的内容。仅需几分钟即可计算出数十亿个G(P)的值。它们中的一些会导致CRC32冲突,但是P的$ 2 ^ {32} $个值会超过P的所有$ 2 ^ {32} $个可能值,但不会更多。因此,如果您为CRC32(G(P))计算的值略多于40亿,则其中一个将成为目标哈希。

这并不一定会为您提供原始密码,只是一个可以在使用此哈希算法的系统。如果您想查找原始密码(因为用户经常重复使用他们的密码,并且其他站点可能不使用这种破坏性的哈希算法),那么您就必须加倍努力。但是难度不大。枚举所有CRC32值时,发现F(CRC32(G(P)), salt)。进行哈希传递的值P等于G(password),其中CRC32(G(P))是原始密码,因为函数CRC32(G(password))没有任何“随机”冲突(实际上,它没有已知的冲突,尽管MD5和SHA-1分别存在) ,甚至对于那些散列而言,碰撞也需要制作两个源值,而不只是一个,然后再寻找碰撞)。取得一张常用密码的MD5值表,并过滤具有目标CRC32的密码;除非密码很少出现在表中(并且有一些制作大表的技术),否则您将找到原始密码。

万一发现其中的一个弱点,使用多个散列函数不是一个坏主意,但是需要正确完成。 PBKDF2在每次迭代时使用密码。如果此问题中的算法被修改为在最后的SHA-1和MD5步骤中使用密码,则它将从极差变为极差。尽管使用多个散列函数不是一个坏主意,但这绝不是必需的。实际上,它可能不值得增加复杂性(即增加了出错的风险)。

评论


$ \ begingroup $
CSC32甚至比这更糟-给定一条消息,您可以计算对消息的四个连续字节进行必要的修改才能获得所需的结果。
$ \ endgroup $
– Eugene Styer
17年8月17日在14:09

$ \ begingroup $
@EugeneStyer是的,但这对这里没有帮助,因为它是CRC32(MD5(password))。如果需要更改MD5值中的某些字节,没有比强行使用密码更好的方法了,如果这样做,那么反转CRC32的功能就没有优势。
$ \ endgroup $
–吉尔斯'所以-不再是邪恶的'
17年8月17日在15:09

$ \ begingroup $
@Gilles所以我知道这是非常不安全的,但是我很难理解有关破坏它的部分。您说密码只影响进入CRC32的内容,但是第一轮MD5呢?如果有可能创建可以快速破解这些哈希值的东西,我想尝试一下,我不在乎结果是否是真实的通过。
$ \ endgroup $
–卢克
17年8月17日在20:52

$ \ begingroup $
@Luke给定Z,很容易找到c,使crcC32(Y)= Z。但是在这里Y = md5(X),并且在给定Y的情况下,没有比猜测更好的方法来找到X了。根据密码的强度,猜测可能快还是慢。 (续)
$ \ endgroup $
–吉尔斯'所以-不再是邪恶的'
17年8月17日在21:15

$ \ begingroup $
@Luke但是您也可以从另一端解决问题。运行许多X值,计算Y = md5(X)和Z = crc32(Y)。除非您有意制造MD5,否则不会发生冲突,因此每个X值都会为您提供不同的Y。通常,不同的Y值也会为您提供不同的Z,因为您还需要付出一些努力才能获得crc32冲突。如果您通过的X值大于不同的Z值,则最终将遍历所有可能的Z值。由于只有40亿,这在PC上是可行的。
$ \ endgroup $
–吉尔斯'所以-不再是邪恶的'
17年8月17日在21:16

#2 楼

数学上的问题是:

Is F(G(H(x))) more secure than F(x)?


一次:如果F(x)是安全的,则F(G(x))甚至F(F(x))都不安全。

另一方面,如果在F(G(x))中G不安全,则F(G(x))也可能变得不安全。 br />
以CRC32为例:简单地说,该算法实际上会将任何密码减少到大约5个字符(请参阅Gilles的详细说明)。由于5字符密码更容易用蛮力破解,因此降低了安全性。有了运气,F足以掩盖那个问题,但是如果没有G的话,整个事情就更安全了。

在连接函数时留下了3种情况: >如果所有功能都是安全的,它将不会有任何改善。
如果某些功能不安全,则安全性将变得更差。
如果-由于运气不好或难以置信的技能-您碰巧找到了一种组合可以提高安全性的半安全功能中,您已经发明了新算法。

几乎在所有情况下,选项3都不会发生。