1

I am trying to write a program that calculates hmac of a string. I am allowed to use hashlib library but not hmac. Here is my code:

from hashlib import sha256

def string_to_decimal(string):
    res = ''
    for char in string:
        res += hex(ord(char))[2:]
    return int(res, 16)

def decimal_to_string(number):
    hex_number = hex(number)[2:]
    hex_number = hex_number[::-1]
    res = ''
    for i in range(0, len(hex_number), 2):
        if i + 1 < len(hex_number):
            res += chr(int(hex_number[i + 1] + hex_number[i], 16))
        else:
            res += chr(int(hex_number[i], 16))

    return res[::-1]

def calculate_ipad_opad(block_size, ipad, opad):
    res_ipad = 0
    res_opad = 0
    for i in range(block_size // 8):
        res_ipad = (res_ipad * 256) + ipad
        res_opad = (res_opad * 256) + opad
    return res_ipad, res_opad

def integer_to_bytes(number):
    res = list()
    while number > 0:
        res.append(number % 256)
        number //= 256
    
    return bytes(res[::-1])

block_size = 512

msg = 'The quick brown fox jumps over the lazy dog'
key = 'key'

ipad = 54
opad = 92

block_ipad, block_opad = calculate_ipad_opad(block_size, ipad, opad)

key_decimal = string_to_decimal(key)
si = key_decimal ^ block_ipad
so = key_decimal ^ block_opad

a = sha256(integer_to_bytes(so) + sha256(integer_to_bytes(si) + msg.encode()).digest())

print(a.digest())

I know the key length is not more than the block size. I used Wikipedia to write the code. But it doesn't work properly. Could you please help me with that???

EDIT: I expected the output of the code to be f7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8. But the output is 3d6243123b984bcc17cb96eb61c2b47d27545c3a9119b623be7932e846bf0643.

8
  • 1
    @furas: I tried with freeformatter.com/hmac-generator.html hmac sha256 and got the expected value that OP posted. Commented May 11, 2021 at 19:29
  • 1
    @ssaf Best to look up or generate intermediate values for the various steps using a known good implementation. Commented May 11, 2021 at 19:29
  • 1
    Uh, I don't see that ipad and opad have the right values. These should be byte arrays of the given value, not a multiplication with the value. Commented May 11, 2021 at 19:33
  • 1
    your calculations doesn't fit me to description on Wikipedia. You don't pad key (key ← Pad(key, blockSize)) you don't create bytes list with repeated values 0x5c and 0x36 Commented May 11, 2021 at 19:51
  • 1
    Ugh. OK, don't know what is wrong with << and really you should do this byte-by-byte, but I guess this may work. Commented May 12, 2021 at 21:52

1 Answer 1

2

The key must be padded with 0x00 values on the right side up to the block size of the digest (if the key size is smaller than the block size, which is the case here). You can achieve this by e.g. adding in string_to_decimal() just before the return:

res = res.ljust(64 * 2, "0")

With this change, the expected result is provided.

For an implementation, it is better to use a more detailed specification of the algorithm, e.g. FIPS PUB 198-1 instead of the highly abbreviated description in Wikipedia. Furthermore, you are on the safe side if official test vectors are applied.


The conversion to decimal numbers is actually not necessary, i.e. it is possible to work directly with bytes like objects, which simplifies the implementation considerably:

from hashlib import sha256

msg = 'The quick brown fox jumps over the lazy dog'
key = 'key'

block_size_bytes = 64

block_opad_bytes = b'\x5c' * block_size_bytes
block_ipad_bytes = b'\x36' * block_size_bytes
key_bytes = key.encode().ljust(block_size_bytes, b'\0')

si_bytes = bytes([a ^ b for (a, b) in zip(block_ipad_bytes, key_bytes)]) 
so_bytes = bytes([a ^ b for (a, b) in zip(block_opad_bytes, key_bytes)]) 

a = sha256(so_bytes + sha256(si_bytes + msg.encode()).digest())

print(a.digest().hex()) # f7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.