空间减少确实发生了,但不是那样的。
安全散列函数的行为应该类似于随机函数的平均行为(即,在具有相同输入和输出长度的一组可能函数中统一选择的函数)。众所周知,MD5 和 SHA-1 最终不是安全的(因为我们可以比使用随机函数更有效地为它们找到冲突),但它们在这里仍然足够接近(不过,除了互操作性之外,您不应该使用它们使用遗留实现;您确实应该使用更现代和更安全的功能,例如 SHA-256)。
因此,假设一个n位输出,如果您散列所有 2 n个n位字符串,您可以期望所有输出覆盖2 n 个可能输出值(即 1-(1/ e ))的大约 63.21% 的空间. 你失去了超过三分之一的空间。但是,如果您再次对所有这些获得的值进行重新哈希处理,您将丢失其中的三分之一。每一轮的缩减因子不是恒定的。几轮之后,每轮的额外减少量非常小。
当你连续多次对给定值进行哈希处理时,实际上是在走一个“rho结构”,如下图所示:
这种结构之所以如此命名,是因为它看起来大致类似于希腊字母 ρ,“rho”。每个点是一个n位值,每个箭头代表您的哈希函数的应用。蓝点是您的起点。所以这个想法是,通过多次应用这个函数,你最终会进入一个循环。一旦进入循环,散列函数的连续应用不再减少可能值的空间:您只是在循环中无限期地走动。周期长度就是您可以达到的最小空间大小。
“尾巴”(进入循环之前通过的值)和“循环”本身的长度平均为 2 n /2。因此,对于一个 128 位输出的散列函数,连续应用不会将空间减少到 2 64以下,这是一个相当大的值;平均而言,即使达到最小空间也需要 2 64次哈希函数评估,这很昂贵。
通过遍历 rho 结构找到循环实际上是Floyd 循环查找算法的基础,该算法是可用于为哈希函数构建冲突的通用算法之一:在 rho 结构中,在尾部所在的点附加到循环中,存在冲突(两个不同的值散列为相同的值)。对于加密安全的散列函数,发现冲突应该是困难的;特别是,弗洛伊德算法在计算上应该是不可行的,这是通过使n足够大来实现的(例如,对于 SHA-256 ,n = 256:这将弗洛伊德算法的成本提高到 2 128,即在地球上实际上不可行)。
换句话说:如果你选择了一个安全的散列函数,具有足够宽的输出(安全的先决条件),那么你将无法到达循环和/或行走它,并且你的安全性不会受到任何“空间缩减”。推论:如果你有空间缩减的问题,那么你没有使用安全的散列函数,这就是你需要解决的问题。因此,请使用 SHA-256。