it-swarm.com.de

Implementierung HMAC-SHA1 in Python

Ich versuche, die OAuth einer Website zu verwenden, die erfordert, dass die Signaturmethode nur "HMAC-SHA1" ist.

Ich frage mich, wie man das in Python umsetzt.

39
xiaohan2012

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

Signaturfehler befinden sich normalerweise in der Basiszeichenfolge. Vergewissern Sie sich, dass Sie dies verstehen (wie von der OAuth1.0-Spezifikation hier angegeben: http://tools.ietf.org/html/draft-hammer-oauth-10#section- 3.4.1 ).

Die folgenden Eingaben werden zum Generieren der Signatur-Basiszeichenfolge verwendet:

  1. HTTP-Methode (zum Beispiel GET)
  2. Pfad (zum Beispiel http://photos.example.net/photos )
  3. Parameter, alphabetisch wie (Zeilenumbrüche zur besseren Lesbarkeit): 

    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
    

Verketten und URL-Kodierung jedes Teils und es endet als:

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

70
Jon Nylander

Für die Liebe Gottes, wenn Sie ALLES mit oauth tun, verwenden Sie die requests-Bibliothek für Python! Ich habe versucht, HMAC-SHA1 mit der hmac-Bibliothek in Python zu implementieren, und es ist eine Menge Kopfschmerzen, bei dem versucht wurde, die richtige oauth-Basiszeichenfolge und so zu erstellen. Verwenden Sie einfach Anfragen und es ist so einfach wie:

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

fordert Authentifizierung an

Requests Oauth-Bibliothek

11
Blairg23
7
Andrey Atapin

Schließlich ist hier eine tatsächlich funktionierende Lösung (getestet mit Python 3) unter Verwendung von oauthlib .

Ich verwende den ersten OAuth-Schritt, der als Beispiel im offiziellen RTF 1 angegeben ist:

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"

Der Wert für oauth_signature möchten wir berechnen.

Folgendes definiert, was wir unterschreiben wollen:

# 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"

Und es geht los:

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
3
Raffael

Es gibt mehrere Python-Bibliotheken unter der oauth-Website , aber wenn Sie nur an einer bestimmten Implementierung interessiert sind, können Sie einen Blick auf eine davon werfen.

1
Till

In Python 3.7 gibt es einen optimierten Weg, dies zu tun. HMAC (key, msg, digest) .digest () verwendet eine optimierte C- oder Inline-Implementierung, die für Nachrichten, die in den Speicher passen, schneller ist.

Gibt den Digest of msg für den angegebenen geheimen Schlüssel und Digest zurück. Die Funktion lautet entspricht HMAC (key, msg, digest) .digest (), verwendet jedoch ein optimiertes C oder Inline-Implementierung, die schneller für Nachrichten ist, die in .__ passen. Erinnerung. Die Parameter key, msg und digest haben dieselbe Bedeutung wie in neu ().

CPython-Implementierungsdetails, die optimierte C-Implementierung besteht nur aus Wird verwendet, wenn Digest eine Zeichenfolge und der Name eines Digest-Algorithmus ist. Dies ist unterstützt von OpenSSL.

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

0
SuperNova

Sie können folgende Methode ausprobieren.

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')
0
Qy Zuo