Проблема с вычислением HMAC строки с помощью Python

Я пытаюсь написать программу, которая вычисляет hmac строки. Мне разрешено использовать библиотеку hashlib, но не hmac. Вот мой код:

      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())

Я знаю, что длина ключа не больше размера блока. Я использовал Википедию для написания кода. Но это не работает должным образом. Не могли бы вы помочь мне с этим ???

РЕДАКТИРОВАТЬ: я ожидал, что вывод кода будет f7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8. Но на выходе 3d6243123b984bcc17cb96eb61c2b47d27545c3a9119b623be7932e846bf0643.

1 ответ

Решение

Ключ должен быть дополнен значениями 0x00 с правой стороны до размера блока дайджеста (если размер ключа меньше размера блока, как здесь). Вы можете добиться этого, например, добавив string_to_decimal() прямо перед return:

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

Благодаря этому изменению обеспечивается ожидаемый результат.

Для реализации лучше использовать более подробную спецификацию алгоритма, например, FIPS PUB 198-1 вместо сильно сокращенного описания в Википедии. Кроме того, вы в безопасности, если применяете официальные тестовые векторы .


Преобразование в десятичные числа на самом деле не требуется, т. Е. Можно работать напрямую с байтами, как с объектами, что значительно упрощает реализацию:

      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
Другие вопросы по тегам