-
Notifications
You must be signed in to change notification settings - Fork 0
/
S04C28.py
102 lines (79 loc) · 2.89 KB
/
S04C28.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
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
96
97
98
99
100
101
102
# Imports
import os
import struct
import hashlib
from lib import *
def left_rotate(value: int, shift: int) -> int:
"""
Returns value left-rotated by shift bits. In other words, performs a circular shift to the left.
"""
return ((value << shift) & 0xffffffff) | (value >> (32 - shift))
def sha1(message: bytes, ml=None, h0=0x67452301, h1=0xEFCDAB89, h2=0x98BADCFE, h3=0x10325476, h4=0xC3D2E1F0) -> bytes:
"""
Returns a string containing the SHA1 hash of the input message. This is a pure python 3 SHA1
implementation, written starting from the SHA1 pseudo-code on Wikipedia.
The parameters ml, h0, ..., h5 are for the next challenge.
"""
# Pre-processing:
if ml is None:
ml = len(message) * 8
message += b'\x80'
while (len(message) * 8) % 512 != 448:
message += b'\x00'
message += struct.pack('>Q', ml)
# Process the message in successive 512-bit chunks:
for i in range(0, len(message), 64):
# Break chunk into sixteen 32-bit big-endian integers w[i]
w = [0] * 80
for j in range(16):
w[j] = struct.unpack('>I', message[i + j * 4:i + j * 4 + 4])[0]
# Extend the sixteen 32-bit integers into eighty 32-bit integers:
for j in range(16, 80):
w[j] = left_rotate(w[j - 3] ^ w[j - 8] ^ w[j - 14] ^ w[j - 16], 1)
# Initialize hash value for this chunk:
a = h0
b = h1
c = h2
d = h3
e = h4
# Main loop
for j in range(80):
if j <= 19:
f = d ^ (b & (c ^ d))
k = 0x5A827999
elif 20 <= j <= 39:
f = b ^ c ^ d
k = 0x6ED9EBA1
elif 40 <= j <= 59:
f = (b & c) | (d & (b | c))
k = 0x8F1BBCDC
else:
f = b ^ c ^ d
k = 0xCA62C1D6
temp = left_rotate(a, 5) + f + e + k + w[j] & 0xffffffff
e = d
d = c
c = left_rotate(b, 30)
b = a
a = temp
# Add this chunk's hash to result so far:
h0 = (h0 + a) & 0xffffffff
h1 = (h1 + b) & 0xffffffff
h2 = (h2 + c) & 0xffffffff
h3 = (h3 + d) & 0xffffffff
h4 = (h4 + e) & 0xffffffff
# Produce the final hash value (big-endian) as a 160 bit number, hex formatted:
return "%08x%08x%08x%08x%08x" % (h0, h1, h2, h3, h4)
def sha1_mac(key: bytes, message: bytes) -> bytes:
return sha1(key + message)
def main():
keysize = 16
random_key = os.urandom(keysize)
message = "This is a message to test that our implementation of the SHA1 MAC works properly."
hashed = sha1_mac(random_key, message.encode())
# Verify that I implemented SHA1 correctly
h = hashlib.sha1(random_key + message.encode())
assert hashed == h.hexdigest()
return
if __name__=="__main__":
main()