我正在开发一个程序,将图像URL哈希为一个由十六进制字符组成的10个字符的字符串,例如64fd54ad29。
这个程序是用Python编写的,哈希值的计算方式如下:
我对使用如此短的哈希值存在碰撞问题感到担忧。我预计在大约一百万次哈希后会发生碰撞,但当我进行暴力破解时,我需要进行十万次哈希才发生了碰撞。
计算:
一个十六进制数字有16种可能的值,或者2^4。使用十个字符,我有2^40种可能性,或者40位熵。
要达到概率为1,我们需要查看2^40 + 1个URL(根据鸽巢原理),但我们预计会更早发生碰撞。
一个n位哈希的生日攻击(即暴力破解)将在2^(n/2)次尝试后找到碰撞。因此,我们预计在大约2^20个URL后会看到碰撞,即1,048,576个URL。
暴力破解:
我编写了一个简单的Python脚本,迭代了一个长列表的URL,并将每个哈希与之前看到的哈希进行比较。我需要进行10,800,000个URL才能找到我的第一个碰撞:
这个程序是用Python编写的,哈希值的计算方式如下:
def hash_short(self, url):
return hashlib.sha1(url).hexdigest()[:10]
我对使用如此短的哈希值存在碰撞问题感到担忧。我预计在大约一百万次哈希后会发生碰撞,但当我进行暴力破解时,我需要进行十万次哈希才发生了碰撞。
计算:
一个十六进制数字有16种可能的值,或者2^4。使用十个字符,我有2^40种可能性,或者40位熵。
要达到概率为1,我们需要查看2^40 + 1个URL(根据鸽巢原理),但我们预计会更早发生碰撞。
一个n位哈希的生日攻击(即暴力破解)将在2^(n/2)次尝试后找到碰撞。因此,我们预计在大约2^20个URL后会看到碰撞,即1,048,576个URL。
暴力破解:
我编写了一个简单的Python脚本,迭代了一个长列表的URL,并将每个哈希与之前看到的哈希进行比较。我需要进行10,800,000个URL才能找到我的第一个碰撞:
"http://c69025.r25.cf3.rackcdn.com/_image1/_Model/34897.jpg"
和"http://media.editd.com/assets/matrix/full/72f9a997b67c65c66f4adc769ee0a127d1db25eb.jpg"
都哈希为"ba2be44bd1"
。import hashlib
import json
def calculate_short_hash(url):
return hashlib.sha1(url).hexdigest()[:10]
def url_from_json(json_string):
return json.loads(json_string)['image_url']
if __name__ == '__main__':
short_hashes = set()
for i, line in enumerate(open('urls.all')):
short_hash = calculate_short_hash(url_from_json(line))
if short_hash in short_hashes:
print "Already seen: %s" % short_hash
break
else:
short_hashes.add(short_hash)
if i % 100000 == 0:
print "Processed %d lines" % (i,)
摘要
我的数学可能有误,也可能是我非常不幸。到底是哪一个?我有多么不幸?