diff --git a/sha1.py b/sha1.py new file mode 100644 index 0000000000000000000000000000000000000000..74a8d870e470f6f90bd306dbc4762dd86bdf9461 --- /dev/null +++ b/sha1.py @@ -0,0 +1,90 @@ +import struct + +HASH_CONSTANTS = [0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0] + + + +def left_rotate(n, b): + return ((n << b) | (n >> (32 - b))) & 0xFFFFFFFF + + +def expand_chunk(chunk): + w = list(struct.unpack(">16L", chunk)) + [0] * 64 + for i in range(16, 80): + w[i] = left_rotate((w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]), 1) + return w + + +def sha1(message): + """ + Secure Hash Algorithm 1 (SHA1) implementation based on https://en.wikipedia.org/wiki/SHA-1#SHA-1_pseudocode + + >>> import binascii + >>> binascii.hexlify(sha1(b'The quick brown fox jumps over the lazy dog')) + b'2fd4e1c67a2d28fced849ee1bb76e7391b93eb12' + >>> binascii.hexlify(sha1(b'The quick brown fox jumps over the lazy cog')) + b'de9f2c7fd25e1b3afad3e85a0bd17d9b100db4b3' + >>> binascii.hexlify(sha1(b'')) + b'da39a3ee5e6b4b0d3255bfef95601890afd80709' + """ + + h = HASH_CONSTANTS + padded_message = message + b"\x80" + \ + (b"\x00" * (63 - (len(message) + 8) % 64)) + \ + struct.pack(">Q", 8 * len(message)) + chunks = [padded_message[i:i+64] + for i in range(0, len(padded_message), 64)] + + for chunk in chunks: + expanded_chunk = expand_chunk(chunk) + a, b, c, d, e = h + for i in range(0, 80): + if 0 <= i < 20: + f = (b & c) | ((~b) & d) + k = 0x5A827999 + elif 20 <= i < 40: + f = b ^ c ^ d + k = 0x6ED9EBA1 + elif 40 <= i < 60: + f = (b & c) | (b & d) | (c & d) + k = 0x8F1BBCDC + elif 60 <= i < 80: + f = b ^ c ^ d + k = 0xCA62C1D6 + a, b, c, d, e = ( + left_rotate(a, 5) + f + e + k + expanded_chunk[i] & 0xFFFFFFFF, + a, + left_rotate(b, 30), + c, + d, + ) + h = ( + h[0] + a & 0xFFFFFFFF, + h[1] + b & 0xFFFFFFFF, + h[2] + c & 0xFFFFFFFF, + h[3] + d & 0xFFFFFFFF, + h[4] + e & 0xFFFFFFFF, + ) + + return struct.pack(">5I", *h) + + +def hmac_sha1(key, message): + """ + Hash-based Message Authentication Code (HMAC) SHA1 implementation based on https://en.wikipedia.org/wiki/HMAC#Implementation + + >>> import binascii + >>> binascii.hexlify(hmac_sha1(b'secret', b'message')) + b'0caf649feee4953d87bf903ac1176c45e028df16' + >>> binascii.hexlify(hmac_sha1(b'secret', b'another message')) + b'cb15739d1cc17409a20afab28ba0964ef51fbe3b' + """ + + key_block = key + (b'\0' * (64 - len(key))) + key_inner = bytes((x ^ 0x36) for x in key_block) + key_outer = bytes((x ^ 0x5C) for x in key_block) + + inner_message = key_inner + message + outer_message = key_outer + sha1(inner_message) + + return sha1(outer_message)