Skip to content

A small python package to easily create and verify HMAC signatures.

Notifications You must be signed in to change notification settings

garrethcain/easy-hmac

Repository files navigation

HMAC Authentication (easy-hmac)

A pure python package with no dependencies to easily handle the generation and verification of HMAC signatures.

Installation

This package is hosted at https://pypi.org/project/easy-hmac/

User

If you don't need to customise this package, just install the package from here.

Ie. pip install easy-hmac

Developer

  1. Clone this repository
  2. Build the package in your local environment.
pipenv shell
pipenv install build
python -m build easy-hmac
  1. Install the easy-hmac package in editing mode by running:
pip install -e easy-hmac
  1. If you want to make sure everything went well, try running the tests from test_easy-hmac
python easy_hmac/test/test_easy-hmac.py

Usage

easy-hmac provides two helper functions for HMAC authentication:

  • generate_hmac_sha256 - generates a SHA256 HMAC from two strings (a secret key and a http message)
  • verify_hmac - given an HMAC and a message, verifies if the HMAC generated by the message is equal to the one passed as argument

Step 1

Import the package. python import datetime from easy_hmac import core import hmac import hashlib from base64 import b64encode from typing import Dict, Any

Step 2

Create some vars we can use to generate and verify the HMAC.

# fake identifier used to retrieve the secret from a db.
secret = "79721503-d1ef-46b7-b4ca-fec39ece902f"
body = '{"event": "lifecycle_updated", "payload": {"uuid": "cb8c79cd-8d79-4698-90a2-662eeab8da98", "timestamp": "2021-12-10T00:16:08.048401Z", "status": "PROCESSING"}}'
method = "POST"
timestamp = datetime.datetime.now(datetime.UTC).strftime("%a, %d %b %Y %H:%M:%S GMT")
path = "/api/v1/my/path"

# vars required for verifying the HMAC.
# This step is a little long because we need to fake some parameters we'd usually already have.
identifier = "2e42a19593f047e080285e49864b0fb6"
hash = hashlib.md5(body.encode())
content_type = "application/json"
content_md5 = b64encode(hash.digest()).decode('utf-8')
message = "\n".join([method, content_md5, content_type, timestamp, path])
signature = hmac.new(bytes(secret, "latin-1"), bytes(message, "latin-1"), digestmod=hashlib.sha256)
hmac_base64 = b64encode(signature.digest()).decode("utf-8")

headers = {
    "Date": timestamp,
    "Content-MD5": content_md5,
    "Content-Type": content_type,
    "Authorization": "HMAC {}:{}".format(identifier, hmac_base64),
}
request = {"method": method, "body": body, "path": path, "headers": headers}

Step 3

Create and verify the signature.

result_digest = core.generate_hmac_sha256(secret, method, body, path, timestamp)
actual_signature = b64encode(result_digest).decode()
expected_signature = "d8laojz+oDCPizTL1a401mHq5IpR1A9f9QK3+RQ/6hA="

core.verify_hmac(secret, hmac_base64, headers["Content-MD5"], body.encode(), headers["Date"], headers["Content-Type"], path, method)

You can raise an exception that the request has expired by changing the timestamp to; timestamp = "Fri, 10 Dec 2021 00:16:57 GMT" and then rerunning the second set of vars above to generate an incoming request that is too old and verifying the signature again.

About

A small python package to easily create and verify HMAC signatures.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages