longchute

about

HMAC

09 May 2012

NOTE: I originally posted this on Snipplr.

To HMAC, pass a hash from Crypto.Hash in PyCrypto. Key should be a bytes object. Returns a bytearray.

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
def pad_key(a_hash, a_key):
    block_size = a_hash.digest_size

    if (len(a_key) > block_size):
        a_hasher = a_hash.new()
        a_hash.update(a_key)
        return a_hasher.digest()
    elif (len(a_key) < block_size): 
        return a_key + (b'\x00' * (block_size - len(a_key)))

    return a_key

def HMAC(a_hash, a_key, data):
    block_size  = a_hash.digest_size
    a_key       = pad_key(a_hash, a_key)
    block_range = bytearray([i for i in range(block_size)])
    xor_5c      = bytearray.maketrans(block_range, bytearray([i ^ 0x5c for i in range(block_size)]))
    xor_36      = bytearray.maketrans(block_range, bytearray([i ^ 0x36 for i in range(block_size)]))

    inner_hasher = a_hash.new()
    outer_hasher = inner_hasher.copy()
    final_hasher = inner_hasher.copy()

    inner_hasher.update(a_key.translate(xor_36) + data)
    outer_hasher.update(a_key.translate(xor_5c) + inner_hasher.digest())
    final_hasher.update(outer_hasher.digest())

    return bytearray(final_hasher.digest())