-
Notifications
You must be signed in to change notification settings - Fork 43
Expand file tree
/
Copy pathchallenge52.py
More file actions
95 lines (77 loc) · 3.58 KB
/
challenge52.py
File metadata and controls
95 lines (77 loc) · 3.58 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
from Cryptodome.Cipher import Blowfish
import struct
import util
def MerkleDamgard(f, processIV, blockLength, padMessage):
def hashFn(m, iv, pad=True):
H = processIV(iv)
if pad:
m = padMessage(m, len(m))
elif len(m) % blockLength != 0:
raise Exception('message of length {0} not a multiple of block length {1}'.format(len(m), blockLength))
for block in (m[x:x+blockLength] for x in range(0, len(m), blockLength)):
H = f(block, H)
return H
return hashFn
badHashHashLength = 2
def badHashF(messageBlock, state):
cipher = Blowfish.new(b'00' + state, Blowfish.MODE_ECB)
newState = cipher.encrypt(messageBlock)[:badHashHashLength]
return newState
def badHashProcessIV(iv):
if len(iv) < badHashHashLength:
return iv + (b'\x00' * (badHashHashLength - len(iv)))
else:
return iv[:badHashHashLength]
badHashBlockLength = 8
def badHashPadMessage(m, l):
m += b'\x80'
m += b'\x00' * ((-4 - (len(m) % badHashBlockLength)) % badHashBlockLength)
m += struct.pack('>I', l)
return m
badHash = MerkleDamgard(badHashF, badHashProcessIV, badHashBlockLength, badHashPadMessage)
def findPrefixCollisionFromIter(hashFn, iv, inputIter):
hashToString = {}
for s in inputIter:
h = hashFn(s, iv, pad=False)
if h in hashToString:
return (h, s, hashToString[h])
else:
hashToString[h] = s
return None, None, None
def findPrefixCollision(hashFn, iv, blockLength, hashLength):
state, s1, s2 = findPrefixCollisionFromIter(hashFn, iv, (i.to_bytes(blockLength, byteorder='little') for i in range(2**(hashLength*8))))
if state is None:
raise Error('unexpected')
return state, s1, s2
def extendCollisions(hashFn, state, blockLength, hashLength, collisions):
state, s1, s2 = findPrefixCollision(hashFn, state, blockLength, hashLength)
return state, [x + s for x in collisions for s in [s1, s2]]
def generateCollisions(hashFn, iv, blockLength, hashLength, n):
state, s1, s2 = findPrefixCollision(hashFn, iv, blockLength, hashLength)
collisions = [s1, s2]
for i in range(n-1):
state, collisions = extendCollisions(hashFn, state, blockLength, hashLength, collisions)
return state, collisions
lessBadHashHashLength = 3
def lessBadHashF(messageBlock, state):
cipher = Blowfish.new(b'00' + state, Blowfish.MODE_ECB)
newState = cipher.encrypt(messageBlock)[:lessBadHashHashLength]
return newState
lessBadHashProcessIV = badHashProcessIV
lessBadHashBlockLength = badHashBlockLength
lessBadHashPadMessage = badHashPadMessage
lessBadHash = MerkleDamgard(lessBadHashF, lessBadHashProcessIV, lessBadHashBlockLength, lessBadHashPadMessage)
# hashFn is assumed to be the cheap one.
def findCollision2(hashFn, iv, blockLength, hashLength, hashFn2, iv2, blockLength2, hashLength2):
state, collisions = generateCollisions(hashFn, iv, blockLength, hashLength, hashLength2*4)
while True:
_, s1, s2 = findPrefixCollisionFromIter(hashFn2, iv2, collisions)
if s1 is not None:
return s1, s2
state, collisions = extendCollisions(hashFn, state, blockLength, hashLength, collisions)
if __name__ == '__main__':
_, collisions = generateCollisions(badHash, b'', badHashBlockLength, badHashHashLength, 5)
for s in collisions:
print(s, badHash(s, b''))
s1, s2 = findCollision2(badHash, b'', badHashBlockLength, badHashHashLength, lessBadHash, b'', lessBadHashBlockLength, lessBadHashHashLength)
print(s1, s2, badHash(s1, b''), badHash(s2, b''), lessBadHash(s1, b''), lessBadHash(s2, b''))