Skip to content

Instantly share code, notes, and snippets.

@craigderington
Created June 6, 2021 15:07
Show Gist options
  • Save craigderington/9cb3ffaf4279af95bebcc0470212f788 to your computer and use it in GitHub Desktop.
Save craigderington/9cb3ffaf4279af95bebcc0470212f788 to your computer and use it in GitHub Desktop.
Digital Signature Verification with Python and hmac
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()
@flashfinisher7
Copy link

flashfinisher7 commented Sep 22, 2022

Hi, i am a newly working on HMAC and i was refering to your code it really super can you explain the code a bit.
it will really helpfull.
thank you

@craigderington
Copy link
Author

craigderington commented Sep 22, 2022

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!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment