Реализация HMAC-SHA1 в python - PullRequest
       35

Реализация HMAC-SHA1 в python

40 голосов
/ 01 декабря 2011

Я пытаюсь использовать OAuth веб-сайта, для которого требуется, чтобы метод подписи был только HMAC-SHA1.

Мне интересно, как реализовать это в Python?

Ответы [ 7 ]

72 голосов
/ 01 декабря 2011

Pseudocodish:

def sign_request():
    from hashlib import sha1
    import hmac

    # key = b"CONSUMER_SECRET&" #If you dont have a token yet
    key = b"CONSUMER_SECRET&TOKEN_SECRET" 


    # The Base String as specified here: 
    raw = b"BASE_STRING" # as specified by OAuth

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

    # The signature
    return hashed.digest().encode("base64").rstrip('\n')

Ошибки сигнатуры обычно находятся в базовой строке, убедитесь, что вы понимаете это (как указано здесь в спецификации OAuth1.0: http://tools.ietf.org/html/draft-hammer-oauth-10#section-3.4.1).

Следующие входы используются для генерации строки подписи:

  1. HTTP-метод (например, GET)
  2. Путь (например, http://photos.example.net/photos)
  3. Параметрыв алфавитном порядке, например (разрывы строк для удобочитаемости):

    file=vacation.jpg
    &oauth_consumer_key=dpf43f3p2l4k3l03
    &oauth_nonce=kllo9940pd9333jh
    &oauth_signature_method=HMAC-SHA1
    &oauth_timestamp=1191242096
    &oauth_token=nnch734d00sl2jdk
    &oauth_version=1.0
    &size=original
    

Конкатенация и URL кодируют каждую часть, и она заканчивается как:

GET&http%3A%2F%2Fphotos.example.net%2Fphotos&file%3Dvacation.jpg%26 oauth_consumer_key%3Ddpf43f3p2l4k3l03%26oauth_nonce%3Dkllo9940pd9333jh%26 oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1191242096%26 oauth_token%3Dnnch734d00sl2jdk%26oauth_version%3D1.0%26size%3Doriginal

13 голосов
/ 18 августа 2015

Ради Бога, если вы делаете НИЧЕГО с oauth, используйте библиотеку requests для Python! Я пытался реализовать HMAC-SHA1, используя библиотеку hmac в Python, и у меня было много головной боли, пытаясь создать правильную базовую строку oauth и тому подобное. Просто используйте запросы, и это так просто, как:

>>> import requests
>>> from requests_oauthlib import OAuth1

>>> url = 'https://api.twitter.com/1.1/account/verify_credentials.json'
>>> auth = OAuth1('YOUR_APP_KEY', 'YOUR_APP_SECRET', 'USER_OAUTH_TOKEN', 'USER_OAUTH_TOKEN_SECRET')

>>> requests.get(url, auth=auth)

Запрос аутентификации

Запросы Oauth Library

7 голосов
/ 01 декабря 2011
3 голосов
/ 14 сентября 2016

Наконец, вот реально работающее решение (протестированное с Python 3), использующее oauthlib .

Я использую первый шаг OAuth, приведенный в качестве примера в официальном RTF 1 :

Client Identifier: dpf43f3p2l4k3l03
Client Shared-Secret: kd94hf93k423kf44

POST /initiate HTTP/1.1
Host: photos.example.net
Authorization: OAuth realm="Photos",
    oauth_consumer_key="dpf43f3p2l4k3l03",
    oauth_signature_method="HMAC-SHA1",
    oauth_timestamp="137131200",
    oauth_nonce="wIjqoS",
    oauth_callback="http%3A%2F%2Fprinter.example.com%2Fready",
    oauth_signature="74KNZJeDHnMBp0EMJ9ZHt%2FXKycU%3D"

Значение для oauth_signature - это то, что мы хотели бы вычислить.

Следующее определяет, что мы хотим подписать:

# There is no query string present.
# In case of http://example.org/api?a=1&b=2 - the value
# would be "a=1&b=2".
uri_query=""

# The oauthlib function 'collect_parameters' automatically
# ignores irrelevant header items like 'Content-Type' or
# 'oauth_signature' in the 'Authorization' section.
headers={
    "Authorization": (
        'OAuth realm="Photos", '
        'oauth_nonce="wIjqoS", '
        'oauth_timestamp="137131200", '
        'oauth_consumer_key="dpf43f3p2l4k3l03", '
        'oauth_signature_method="HMAC-SHA1", '
        'oauth_callback="http://printer.example.com/ready"'
    )
}

# There's no POST data here - in case it was: x=1 and y=2,
# then the value would be '[("x","1"),("y","2")]'.
data=[]

# This is the above specified client secret which we need
# for calculating the signature.
client_secret="kd94hf93k423kf44"

Издесь мы идем:

import oauthlib.oauth1.rfc5849.signature as oauth

params = oauth.collect_parameters(
    uri_query="",
    body=data, 
    headers=headers,
    exclude_oauth_signature=True, 
    with_realm=False
)

norm_params = oauth.normalize_parameters(params)

base_string = oauth.construct_base_string(
    "POST", 
    "https://photos.example.net/initiate", 
    norm_params
)

sig = oauth.sign_hmac_sha1(
    base_string, 
    client_secret, 
    '' # resource_owner_secret - not used
)

from urllib.parse import quote_plus

print(sig)
# 74KNZJeDHnMBp0EMJ9ZHt/XKycU=

print(quote_plus(sig))
# 74KNZJeDHnMBp0EMJ9ZHt%2FXKycU%3D
1 голос
/ 29 июня 2017

Вы можете попробовать следующий метод.

def _hmac_sha1(input_str):
        raw = input_str.encode("utf-8")
        key = 'your_key'.encode('utf-8')
        hashed = hmac.new(key, raw, hashlib.sha1)
        return base64.encodebytes(hashed.digest()).decode('utf-8')
1 голос
/ 01 декабря 2011

Существует несколько библиотек python, доступных на веб-сайте oauth , но если вы просто заинтересованы в конкретной реализации, вы можете взглянуть на одну из них .

0 голосов
/ 25 ноября 2018

В Python 3.7 есть оптимизированный способ сделать это. HMAC (ключ, msg, digest) .digest () использует оптимизированную реализацию C или inline, которая быстрее для сообщений, помещающихся в память.

Возвращает дайджест сообщения для данного секретного ключа и дайджеста. Функция эквивалентно HMAC (ключ, msg, digest) .digest (), но использует оптимизированный C или встроенная реализация, которая быстрее для сообщений, которые вписываются в объем памяти. Ключ параметров, msg и digest имеют то же значение, что и в новом ().

Подробности реализации CPython, оптимизированная реализация C только используется, когда дайджест - это строка и имя алгоритма дайджеста, который поддерживается OpenSSL.

https://docs.python.org/3/library/hmac.html#hmac.digest

...