2016-09-16 19:29:34 +00:00
|
|
|
import math
|
|
|
|
|
2019-08-06 11:16:30 +00:00
|
|
|
|
2022-10-12 22:54:20 +00:00
|
|
|
def rearrange(bit_string_32):
|
2019-08-06 11:16:30 +00:00
|
|
|
"""[summary]
|
|
|
|
Regroups the given binary string.
|
|
|
|
|
|
|
|
Arguments:
|
|
|
|
bitString32 {[string]} -- [32 bit binary]
|
|
|
|
|
|
|
|
Raises:
|
|
|
|
ValueError -- [if the given string not are 32 bit binary string]
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
[string] -- [32 bit binary string]
|
|
|
|
>>> rearrange('1234567890abcdfghijklmnopqrstuvw')
|
|
|
|
'pqrstuvwhijklmno90abcdfg12345678'
|
|
|
|
"""
|
|
|
|
|
2022-10-12 22:54:20 +00:00
|
|
|
if len(bit_string_32) != 32:
|
2019-08-06 11:16:30 +00:00
|
|
|
raise ValueError("Need length 32")
|
2022-10-12 22:54:20 +00:00
|
|
|
new_string = ""
|
2019-10-05 05:14:13 +00:00
|
|
|
for i in [3, 2, 1, 0]:
|
2022-10-12 22:54:20 +00:00
|
|
|
new_string += bit_string_32[8 * i : 8 * i + 8]
|
|
|
|
return new_string
|
2019-08-06 11:16:30 +00:00
|
|
|
|
2016-09-16 19:29:34 +00:00
|
|
|
|
2022-10-12 22:54:20 +00:00
|
|
|
def reformat_hex(i):
|
2019-08-06 11:16:30 +00:00
|
|
|
"""[summary]
|
|
|
|
Converts the given integer into 8-digit hex number.
|
2018-04-16 12:13:49 +00:00
|
|
|
|
2019-08-06 11:16:30 +00:00
|
|
|
Arguments:
|
|
|
|
i {[int]} -- [integer]
|
2022-10-12 22:54:20 +00:00
|
|
|
>>> reformat_hex(666)
|
2019-08-06 11:16:30 +00:00
|
|
|
'9a020000'
|
|
|
|
"""
|
|
|
|
|
2019-10-05 05:14:13 +00:00
|
|
|
hexrep = format(i, "08x")
|
2019-08-06 11:16:30 +00:00
|
|
|
thing = ""
|
2019-10-05 05:14:13 +00:00
|
|
|
for i in [3, 2, 1, 0]:
|
|
|
|
thing += hexrep[2 * i : 2 * i + 2]
|
2019-08-06 11:16:30 +00:00
|
|
|
return thing
|
2018-04-16 12:13:49 +00:00
|
|
|
|
2016-09-16 19:29:34 +00:00
|
|
|
|
2022-10-12 22:54:20 +00:00
|
|
|
def pad(bit_string):
|
2019-08-06 11:16:30 +00:00
|
|
|
"""[summary]
|
|
|
|
Fills up the binary string to a 512 bit binary string
|
|
|
|
|
|
|
|
Arguments:
|
|
|
|
bitString {[string]} -- [binary string]
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
[string] -- [binary string]
|
|
|
|
"""
|
2022-10-12 22:54:20 +00:00
|
|
|
start_length = len(bit_string)
|
|
|
|
bit_string += "1"
|
|
|
|
while len(bit_string) % 512 != 448:
|
|
|
|
bit_string += "0"
|
|
|
|
last_part = format(start_length, "064b")
|
|
|
|
bit_string += rearrange(last_part[32:]) + rearrange(last_part[:32])
|
|
|
|
return bit_string
|
2019-08-06 11:16:30 +00:00
|
|
|
|
2016-09-16 19:29:34 +00:00
|
|
|
|
2022-10-12 22:54:20 +00:00
|
|
|
def get_block(bit_string):
|
2019-08-06 11:16:30 +00:00
|
|
|
"""[summary]
|
|
|
|
Iterator:
|
|
|
|
Returns by each call a list of length 16 with the 32 bit
|
2019-08-19 13:37:49 +00:00
|
|
|
integer blocks.
|
2018-04-16 12:13:49 +00:00
|
|
|
|
2019-08-06 11:16:30 +00:00
|
|
|
Arguments:
|
2022-10-12 22:54:20 +00:00
|
|
|
bit_string {[string]} -- [binary string >= 512]
|
2019-08-06 11:16:30 +00:00
|
|
|
"""
|
2016-09-16 19:29:34 +00:00
|
|
|
|
2022-10-12 22:54:20 +00:00
|
|
|
curr_pos = 0
|
|
|
|
while curr_pos < len(bit_string):
|
|
|
|
curr_part = bit_string[curr_pos : curr_pos + 512]
|
|
|
|
my_splits = []
|
2019-08-06 11:16:30 +00:00
|
|
|
for i in range(16):
|
2022-10-12 22:54:20 +00:00
|
|
|
my_splits.append(int(rearrange(curr_part[32 * i : 32 * i + 32]), 2))
|
|
|
|
yield my_splits
|
|
|
|
curr_pos += 512
|
2019-08-06 11:16:30 +00:00
|
|
|
|
|
|
|
|
|
|
|
def not32(i):
|
2019-10-05 05:14:13 +00:00
|
|
|
"""
|
2019-08-06 11:16:30 +00:00
|
|
|
>>> not32(34)
|
|
|
|
4294967261
|
2019-10-05 05:14:13 +00:00
|
|
|
"""
|
|
|
|
i_str = format(i, "032b")
|
|
|
|
new_str = ""
|
2019-08-06 11:16:30 +00:00
|
|
|
for c in i_str:
|
2019-10-05 05:14:13 +00:00
|
|
|
new_str += "1" if c == "0" else "0"
|
2019-08-06 11:16:30 +00:00
|
|
|
return int(new_str, 2)
|
|
|
|
|
2019-10-05 05:14:13 +00:00
|
|
|
|
2019-08-06 11:16:30 +00:00
|
|
|
def sum32(a, b):
|
2022-01-30 19:29:54 +00:00
|
|
|
return (a + b) % 2**32
|
2019-08-19 13:37:49 +00:00
|
|
|
|
2019-08-06 11:16:30 +00:00
|
|
|
|
|
|
|
def leftrot32(i, s):
|
2019-10-05 05:14:13 +00:00
|
|
|
return (i << s) ^ (i >> (32 - s))
|
2016-09-16 19:29:34 +00:00
|
|
|
|
|
|
|
|
2022-10-12 22:54:20 +00:00
|
|
|
def md5me(test_string):
|
2019-08-06 11:16:30 +00:00
|
|
|
"""[summary]
|
|
|
|
Returns a 32-bit hash code of the string 'testString'
|
|
|
|
|
|
|
|
Arguments:
|
|
|
|
testString {[string]} -- [message]
|
|
|
|
"""
|
|
|
|
|
2019-10-05 05:14:13 +00:00
|
|
|
bs = ""
|
2022-10-12 22:54:20 +00:00
|
|
|
for i in test_string:
|
2019-10-05 05:14:13 +00:00
|
|
|
bs += format(ord(i), "08b")
|
2019-08-06 11:16:30 +00:00
|
|
|
bs = pad(bs)
|
|
|
|
|
2022-01-30 19:29:54 +00:00
|
|
|
tvals = [int(2**32 * abs(math.sin(i + 1))) for i in range(64)]
|
2019-08-06 11:16:30 +00:00
|
|
|
|
|
|
|
a0 = 0x67452301
|
2019-10-05 05:14:13 +00:00
|
|
|
b0 = 0xEFCDAB89
|
|
|
|
c0 = 0x98BADCFE
|
2019-08-06 11:16:30 +00:00
|
|
|
d0 = 0x10325476
|
|
|
|
|
2019-10-05 05:14:13 +00:00
|
|
|
s = [
|
|
|
|
7,
|
|
|
|
12,
|
|
|
|
17,
|
|
|
|
22,
|
|
|
|
7,
|
|
|
|
12,
|
|
|
|
17,
|
|
|
|
22,
|
|
|
|
7,
|
|
|
|
12,
|
|
|
|
17,
|
|
|
|
22,
|
|
|
|
7,
|
|
|
|
12,
|
|
|
|
17,
|
|
|
|
22,
|
|
|
|
5,
|
|
|
|
9,
|
|
|
|
14,
|
|
|
|
20,
|
|
|
|
5,
|
|
|
|
9,
|
|
|
|
14,
|
|
|
|
20,
|
|
|
|
5,
|
|
|
|
9,
|
|
|
|
14,
|
|
|
|
20,
|
|
|
|
5,
|
|
|
|
9,
|
|
|
|
14,
|
|
|
|
20,
|
|
|
|
4,
|
|
|
|
11,
|
|
|
|
16,
|
|
|
|
23,
|
|
|
|
4,
|
|
|
|
11,
|
|
|
|
16,
|
|
|
|
23,
|
|
|
|
4,
|
|
|
|
11,
|
|
|
|
16,
|
|
|
|
23,
|
|
|
|
4,
|
|
|
|
11,
|
|
|
|
16,
|
|
|
|
23,
|
|
|
|
6,
|
|
|
|
10,
|
|
|
|
15,
|
|
|
|
21,
|
|
|
|
6,
|
|
|
|
10,
|
|
|
|
15,
|
|
|
|
21,
|
|
|
|
6,
|
|
|
|
10,
|
|
|
|
15,
|
|
|
|
21,
|
|
|
|
6,
|
|
|
|
10,
|
|
|
|
15,
|
|
|
|
21,
|
|
|
|
]
|
2019-08-06 11:16:30 +00:00
|
|
|
|
2022-10-12 22:54:20 +00:00
|
|
|
for m in get_block(bs):
|
|
|
|
a = a0
|
|
|
|
b = b0
|
|
|
|
c = c0
|
|
|
|
d = d0
|
2019-08-06 11:16:30 +00:00
|
|
|
for i in range(64):
|
|
|
|
if i <= 15:
|
2019-10-05 05:14:13 +00:00
|
|
|
# f = (B & C) | (not32(B) & D)
|
2022-10-12 22:54:20 +00:00
|
|
|
f = d ^ (b & (c ^ d))
|
2019-08-06 11:16:30 +00:00
|
|
|
g = i
|
|
|
|
elif i <= 31:
|
2019-10-05 05:14:13 +00:00
|
|
|
# f = (D & B) | (not32(D) & C)
|
2022-10-12 22:54:20 +00:00
|
|
|
f = c ^ (d & (b ^ c))
|
2019-10-05 05:14:13 +00:00
|
|
|
g = (5 * i + 1) % 16
|
2019-08-06 11:16:30 +00:00
|
|
|
elif i <= 47:
|
2022-10-12 22:54:20 +00:00
|
|
|
f = b ^ c ^ d
|
2019-10-05 05:14:13 +00:00
|
|
|
g = (3 * i + 5) % 16
|
2019-08-06 11:16:30 +00:00
|
|
|
else:
|
2022-10-12 22:54:20 +00:00
|
|
|
f = c ^ (b | not32(d))
|
2019-10-05 05:14:13 +00:00
|
|
|
g = (7 * i) % 16
|
2022-10-12 22:54:20 +00:00
|
|
|
dtemp = d
|
|
|
|
d = c
|
|
|
|
c = b
|
|
|
|
b = sum32(b, leftrot32((a + f + tvals[i] + m[g]) % 2**32, s[i]))
|
|
|
|
a = dtemp
|
|
|
|
a0 = sum32(a0, a)
|
|
|
|
b0 = sum32(b0, b)
|
|
|
|
c0 = sum32(c0, c)
|
|
|
|
d0 = sum32(d0, d)
|
|
|
|
|
|
|
|
digest = reformat_hex(a0) + reformat_hex(b0) + reformat_hex(c0) + reformat_hex(d0)
|
2019-08-06 11:16:30 +00:00
|
|
|
return digest
|
|
|
|
|
2016-09-16 19:29:34 +00:00
|
|
|
|
|
|
|
def test():
|
2019-08-06 11:16:30 +00:00
|
|
|
assert md5me("") == "d41d8cd98f00b204e9800998ecf8427e"
|
2019-10-05 05:14:13 +00:00
|
|
|
assert (
|
|
|
|
md5me("The quick brown fox jumps over the lazy dog")
|
|
|
|
== "9e107d9d372bb6826bd81d3542a419d6"
|
|
|
|
)
|
2019-08-06 11:16:30 +00:00
|
|
|
print("Success.")
|
2016-09-16 19:29:34 +00:00
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
2019-08-06 11:16:30 +00:00
|
|
|
test()
|
|
|
|
import doctest
|
2019-10-05 05:14:13 +00:00
|
|
|
|
2019-08-06 11:16:30 +00:00
|
|
|
doctest.testmod()
|