Кодирование хэш-значения Python HMAC в base64

Я пытаюсь выполнить аутентификацию в твиттере с помощью промежуточного программного обеспечения django, где я вычисляю подпись такого запроса (https://dev.twitter.com/oauth/overview/creating-signatures):

    key = b"MY_KEY&"
    raw_init = "POST" + "&" + quote("https://api.twitter.com/1.1/oauth/request_token", safe='')

    raw_params = <some_params>
    raw_params = quote(raw_params, safe='')

    #byte encoding for HMAC, otherwise it returns "expected bytes or bytearray, but got 'str'"
    raw_final = bytes(raw_init + "&" + raw_params, encoding='utf-8')

    hashed = hmac.new(key, raw_final, sha1)

    request.raw_final = hashed

    # here are my problems: I need a base64 encoded string, but get the error "'bytes' object has no attribute 'encode'"
    request.auth_header = hashed.digest().encode("base64").rstrip('\n')

Как видите, в base64 невозможно закодировать объект 'bytes'.

Предлагаемое решение было здесь: Реализация HMAC-SHA1 в python


person massive_dynamic    schedule 26.08.2016    source источник
comment
ты пробовал: base64.encodestring(str(raw_final)) ?   -  person Jean-François Fabre    schedule 26.08.2016
comment
@ Jean-FrançoisFabre, зачем мне кодировать raw_final? Мне нужен объект HMAC, преобразованный в строку base64... Все это согласно документации Twitter - dev.twitter.com/oauth/overview/creating-signatures в самом низу страницы   -  person massive_dynamic    schedule 26.08.2016


Ответы (2)


Хитрость заключается в том, чтобы использовать модуль base64 напрямую вместо кодировки str/byte, которая поддерживает двоичный код.

Вы можете подогнать его так (не проверено в вашем контексте, должно работать):

import base64
#byte encoding for HMAC, otherwise it returns "expected bytes or bytearray, but got 'str'"
raw_final = bytes(raw_init + "&" + raw_params, encoding='utf-8')

hashed = hmac.new(key, raw_final, sha1)

request.raw_final = hashed

# here directly use base64 module, and since it returns bytes, just decode it
request.auth_header = base64.b64encode(hashed.digest()).decode()

В целях тестирования найдите ниже автономный рабочий пример (совместимый с Python 3, пользователи Python 2.x должны удалить параметр ascii при создании строки bytes):

from hashlib import sha1
import hmac
import base64

# key = CONSUMER_SECRET& #If you dont have a token yet
key = bytes("CONSUMER_SECRET&TOKEN_SECRET","ascii")


# The Base String as specified here:
raw = bytes("BASE_STRING","ascii") # as specified by oauth

hashed = hmac.new(key, raw, sha1)

print(base64.b64encode(hashed.digest()).decode())

результат:

Rh3xUffks487KzXXTc3n7+Hna6o=

PS: ответ, на который вы ссылаетесь, больше не работает с Python 3. Это только Python 2.

person Jean-François Fabre    schedule 26.08.2016

Просто решил скорректировать ответ для Python3.

from hashlib import sha512
import hmac
import base64


key = b"KEY"
path = b"WHAT YOU WANT TO BE SIGNED"

hashed = hmac.new(key, path, sha512).digest()

print(base64.b64encode(hashed))
person Sahil    schedule 20.04.2021