我需要一个4个字符的哈希值。目前我正在使用md5()
哈希的前4个字符。我正在散列一个长度不超过80个字符的字符串。这会导致碰撞吗?或者,碰撞的几率是多少,假设我的哈希值小于65,536(16 4 )不同的元素?
答案 0 :(得分:4)
好吧,md5
的每个字符都是十六进制位。这意味着它可以具有16个可能值中的一个。因此,如果您只使用前4个“十六位”,则表示您可以拥有16 * 16 * 16 * 16
或16^4
或65536或2^16
种可能性。
因此,这意味着结果的总可用“空间”仅为16位宽。现在,根据Birthday Attack/Problem,碰撞有以下几率:
50%
偶然 - > 300
条目1%
偶然 - > 36
条目0.0000001%
偶然 - > 2
条目。因此碰撞的可能性非常大。
现在,你说你需要一个4个字符的哈希值。根据具体要求,您可以:
16^4
(65,536)个可能值的4个十六进制位26^4
(456,976)个可能值的4个字母位36^4
(1,679,616)个可能值的4个字母数字位93^4
(74,805,201)个可能的值(假设ASCII 33 - > 126)256^4
(4,294,967,296)个可能值的4个完整字节。现在,您选择的将取决于实际用例。哈希是否需要传输到浏览器?你是如何存储的等等。
我将举一个例子(在PHP中,但应该很容易翻译/看看发生了什么):
4个Hex-Bits :
$hash = substr(md5($data), 0, 4);
4位字:
$hash = substr(base_convert(md5($data), 16, 26)0, 4);
$hash = str_replace(range(0, 9), range('S', 'Z'), $hash);
4个字母数字位:
$hash = substr(base_convert(md5($data), 16, 36), 0, 4);
4个可打印的Assci位:
$hash = hash('md5', $data, true); // We want the raw bytes
$out = '';
for ($i = 0; $i < 4; $i++) {
$out .= chr((ord($hash[$i]) % 93) + 33);
}
4个完整字节:
$hash = substr(hash('md5', $data, true), 0, 4); // We want the raw bytes
答案 1 :(得分:1)
Surprisingly high indeed.正如您从this graph of an approximate collision probability(来自wikipedia page的公式)所看到的那样,只有几百个元素,您发生碰撞的概率超过50%。
当然,请注意,如果您面临攻击者提供字符串的可能性,您可能会认为它是100% - 在16位搜索空间中发现碰撞的扫描几乎可以在任何时候完成现代PC。或者甚至是任何现代手机。
答案 2 :(得分:0)
4个第一个字符包含4 * 4 = 16位数据,因此碰撞肯定会达到65536个元素,并且由于生日攻击,它将被发现更快。你应该使用更多的哈希值。