Created
June 6, 2021 15:07
-
-
Save craigderington/9cb3ffaf4279af95bebcc0470212f788 to your computer and use it in GitHub Desktop.
Digital Signature Verification with Python and hmac
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import os | |
import hashlib | |
import uuid | |
import hmac | |
from datetime import datetime, timedelta | |
my_api_key = os.urandom(64) | |
def verify(api_key, token, timestamp, signature): | |
hmac_digest = hmac.new(key=api_key, | |
msg="{}{}".format(timestamp, token).encode('utf-8'), | |
digestmod=hashlib.sha1).hexdigest() | |
return hmac.compare_digest(signature, hmac_digest) | |
def main(): | |
token = uuid.uuid4() | |
timestamp = datetime.now().strftime("%Y-%m-%D %H:%M:%S") | |
msg = "{}{}".format(timestamp, token).encode("utf-8") | |
hmac_digest = hmac.new( | |
key=my_api_key, | |
msg=msg, | |
digestmod=hashlib.sha1).hexdigest() | |
# show the message vars | |
print(token, timestamp, hmac_digest) | |
# verify the hash | |
print(verify(my_api_key, token, timestamp, hmac_digest)) | |
if __name__ == "__main__": | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hi There. Sure, happy to help...
To help understand the benefits of Hashed Messaging Authentication (HMAC), let us assume you need to accept a remote webhook POST containing data that you need to verify and then act upon in your backend. The first thing we need to do is make sure the webhook request is from a valid source. We don't want to accept data if we can not verify its origin.
The secret API Key is known to both parties.
The data from the remote webhook (like MailGun) contains a json object consisting of a token, a timestamp and the data. With hmac, we can very simply verify the data is from a valid source by comparing the digital signatures which are created from hashing (SHA1) the concatenated token and timestamp. If the digital signatures match, the request is valid and you can proceed to accept the data in the json and process it in your backend.
Alternatively, your application can encode and send data with hashed messaging by using the exact same method. You just don't need to verify. Use hmac.new() to create the signature to include in your POST request.
Hope that helps explain the code above.
In a real project, I would have a conditional block like:
if verify(api_key, token, timestamp, signature):
# data verified, execute this code...
else:
# data from unknown source, return False and exit
Take a look at this Flask project to see how I use hmac to accept and process webhooks from a 3rd party API.
https://github.com/craigderington/flask-rest-mailgun-webhooks
Good luck!