forked from atoponce/scripts
/
md5crypt.py
63 lines (51 loc) · 1.56 KB
/
md5crypt.py
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
from hashlib import md5
from random import SystemRandom
pw = "kpdCE8aSt2gaqKKcU"
r = SystemRandom()
pwlen = len(pw)
itoa64 = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
salt = "".join(r.choice(itoa64) for i in range(8))
p = pw
pp = pw+pw
ps = pw+salt
psp = pw+salt+pw
sp = salt+pw
spp = salt+pw+pw
permutations = [
(p , psp), (spp, pp), (spp, psp), (pp, ps ), (spp, pp), (spp, psp),
(pp, psp), (sp , pp), (spp, psp), (pp, psp), (spp, p ), (spp, psp),
(pp, psp), (spp, pp), (sp , psp), (pp, psp), (spp, pp), (spp, ps ),
(pp, psp), (spp, pp), (spp, psp)
]
# Start digest "a"
da = md5(pw + "$1$" + salt)
# Create digest "b"
db = md5(psp).digest()
# Update digest "a" by repeating digest "b", providing "pwlen" bytes:
for i in range(pwlen, 0, -16):
da.update(db if i > 16 else db[:i])
# Upate digest "a" by adding either a NULL or the first char from "pw"
i = pwlen
while i:
da.update(b"\x00" if i & 1 else pw[0])
i >>= 1
da = da.digest()
# Optimize!
for r in range(23):
for i, j in permutations:
da = md5(j + md5(da + i).digest()).digest()
for i, j in permutations[:17]:
da = md5(j + md5(da + i).digest()).digest()
# convert 3 8-bit words to 4 6-bit words while mixing
final = ''
for x, y, z in ((0, 6, 12), (1, 7, 13), (2, 8, 14), (3, 9, 15), (4, 10, 5)):
v = ord(da[x]) << 16 | ord(da[y]) << 8 | ord(da[z])
for i in range(4):
final += itoa64[v & 63]
v >>= 6
v = ord(da[11])
for i in range(2):
final += itoa64[v & 63]
v >>= 6
# output the result
print "$1${0}${1}".format(salt, final)