HMAC Generator — Python source
Generate a keyed-hash HMAC (SHA-1/256/384/512) for a message and secret. Runs entirely in your browser via Web Crypto, with a shareable link to your exact input.
This is the Python implementation — the same logic the interactive tool runs, in a shareable, citable form.
"""hmac-generator — Python polyglot showcase port
Language: Python
Ported from: src/lib/hmac.ts
Display source — part of CosmoDev's polyglot tool pages.
Keyed-hash HMAC via Python's standard-library ``hmac`` and ``hashlib`` modules
(both backed by OpenSSL). ``hmac`` implements RFC 2104; ``hashlib`` supplies
the vetted, constant-time hash constructors. No third-party packages required.
Behavior mirrors the TypeScript reference: UTF-8 inputs, lowercase hex output,
SHA-256 by default, and rejection of empty secrets and unknown algorithms.
"""
from __future__ import annotations
import hashlib
import hmac
from typing import Final
# Canonical algorithm names. The spellings match the TypeScript union so the
# same string works across every port. Each maps to a hashlib constructor.
SHA1: Final[str] = "SHA-1"
SHA256: Final[str] = "SHA-256" # default algorithm
SHA384: Final[str] = "SHA-384"
SHA512: Final[str] = "SHA-512"
DEFAULT_ALGORITHM: Final[str] = SHA256
# Dispatch table: canonical name -> hashlib constructor. Module-level so the
# supported set is visible in one place and easy to extend.
_HASH_CONSTRUCTORS = {
SHA1: hashlib.sha1,
SHA256: hashlib.sha256,
SHA384: hashlib.sha384,
SHA512: hashlib.sha512,
}
def _digest_for(algorithm: str):
"""Return the hashlib constructor for the canonical algorithm name.
Raises ValueError (not KeyError) so callers get a clear, domain-specific
message rather than a leaky lookup error.
"""
try:
return _HASH_CONSTRUCTORS[algorithm]
except KeyError:
raise ValueError(f"Unsupported HMAC algorithm: {algorithm}") from None
def hmac_hex(message: str, secret: str, algorithm: str = SHA256) -> str:
"""Compute HMAC(``message``, ``secret``) and return it as lowercase hex.
Both inputs are UTF-8 encoded before hashing. An empty ``algorithm``
selects SHA-256; an empty ``secret`` is rejected: ``hmac.new`` would accept
a zero-length key, but the TypeScript reference (SubtleCrypto) refuses one,
and matching that contract keeps the ports in parity.
Passing the constructor (rather than the algorithm name string) as
``digestmod`` makes an unknown algorithm fail fast here instead of deep
inside ``hmac.new``.
"""
if algorithm == "":
algorithm = DEFAULT_ALGORITHM
digestmod = _digest_for(algorithm)
if secret == "":
raise ValueError("HMAC secret must not be empty")
# key/message -> UTF-8 bytes; hexdigest() returns the lowercase hex string
# the TypeScript reference produces.
return hmac.new(
secret.encode("utf-8"),
message.encode("utf-8"),
digestmod,
).hexdigest()
Also available in 13 other languages
Every CosmoDev tool ships its pure logic in TypeScript (web) and Go (CLI), with authored implementations in a dozen-plus languages — the same contract, ported. Compare all languages side by side →