HMAC Generator

Share:

Generate HMAC signatures with SHA-1, SHA-256, SHA-384 or SHA-512. Output as hex, base64 or base64url. All computation in your browser.

RT-CW3-001 · Crypto & Web3
Your browser is too old for this tool’s interactive features. Please update to Safari 13.1, Chrome or Edge 80, Firefox 74 or newer.

HMAC Generator Tool

Privacy: All HMAC computation happens inside your browser using the native SubtleCrypto API. Your secret key and message never leave this page. We do not log or proxy any inputs.
Advertisement
After results · AD-W1 Responsive · Post-tool — peak engagement

How to use the HMAC generator

Paste your secret key

This is the shared secret between you and whoever you're signing data for — typically the value the API or webhook provider issued you.

Paste the message

The exact bytes you want to sign — a webhook payload, an HTTP request body, the canonical request string for AWS signature v4, etc.

Pick the algorithm

SHA-256 is the usual choice today. Use whatever the provider's documentation names: GitHub and Slack, for example, both sign with HMAC-SHA256. SHA-1 is offered for older systems that still require it.

Copy the signature

The signature is shown three ways: hex, base64 and base64url. GitHub and Slack both send hex, with a prefix (sha256= and v0= respectively); JSON Web Tokens use base64url. Copy the encoding your destination expects.

Advertisement
After how-to · AD-W2 Responsive

HMAC — what it is, why APIs use it

HMAC (hash-based message authentication code) combines a secret key with a message to produce a short tag. Anyone who holds the same key can recompute the tag and check that the message has not been changed; without the key it cannot be forged. It was specified by Hugo Krawczyk, Mihir Bellare and Ran Canetti in RFC 2104, published in February 1997, and works with any hash function. This page computes it with the browser's built-in Web Crypto API.

Where you will meet it

Webhook signatures are the commonest use. GitHub signs each delivery with an HMAC hex digest of the payload and sends it in the X-Hub-Signature-256 header, prefixed sha256=. Slack builds a string from a version number, a timestamp and the request body, separated by colons, takes its HMAC-SHA256 hex digest and prefixes v0=. AWS Signature Version 4 uses HMAC-SHA256 as the final step of signing a request. JSON Web Tokens signed with HS256 are HMAC-SHA256 too.

"As of today, there is no indication that attacks on SHA-1 can be extended to HMAC-SHA-1." RFC 6194 (2011)

HMAC versus a plain hash

Hashing the secret and the message together, as in SHA-256(secret + message), is not a safe substitute. With hash functions like SHA-256, an attacker who sees one such tag can extend the message and compute a valid tag for the longer version without knowing the secret. HMAC's nested construction, with the key mixed in twice, was designed to avoid this.

Key length

RFC 2104 allows keys of any length, but says that keys shorter than the hash output "is strongly discouraged as it would decrease the security strength of the function", while longer keys are acceptable but add little. In practice that means at least 32 random bytes for HMAC-SHA256 and 64 for HMAC-SHA512.

Verifying a signature

Recompute the HMAC over the exact bytes you received, before any JSON parsing changes them, and compare it with the signature using a constant-time comparison such as hash_equals in PHP, crypto.timingSafeEqual in Node.js or hmac.compare_digest in Python. An ordinary string comparison stops at the first difference, and the time it takes can leak how much of a forged signature was right. To check this page's output yourself, RFC 4231 publishes test vectors: key "Jefe" and message "what do ya want for nothing?" should give an HMAC-SHA256 beginning 5bdcc146.

RFC 2104, the providers that use it, and why HMAC-SHA1 still holds

01

HMAC was specified in RFC 2104 in February 1997 by Krawczyk, Bellare and Canetti.

02

RFC 2104 says keys shorter than the hash output are strongly discouraged; longer keys add little strength.

03

RFC 6194 (2011) found no indication that attacks on SHA-1 extend to HMAC-SHA-1.

04

GitHub signs webhooks with an HMAC hex digest in the X-Hub-Signature-256 header, prefixed sha256=.

05

Slack signs v0:timestamp:body with HMAC-SHA256 and sends the hex digest prefixed v0=.

06

AWS Signature Version 4 computes its final signature with HMAC-SHA256.

07

JSON Web Tokens signed with HS256 carry an HMAC-SHA256 tag, base64url-encoded.

08

RFC 4231 test vector: key "Jefe" and "what do ya want for nothing?" give an HMAC-SHA256 starting 5bdcc146.

09

Compare signatures with a constant-time function, not ==, so timing does not leak the answer.

10

This page uses the browser's Web Crypto API; the key and message never leave your device.

Frequently asked questions

]; @endphp
A plain hash such as SHA-256 is a fingerprint anyone can compute and check. HMAC mixes in a secret key, so only someone with the key can produce or verify the tag. Webhooks and API signatures use HMAC; file checksums use plain hashes.
RFC 6194 (2011) found "no indication that attacks on SHA-1 can be extended to HMAC-SHA-1", because HMAC does not depend on the collision resistance that SHA-1 has lost. Use SHA-256 for anything new, and HMAC-SHA1 only where an existing system requires it.
Take the request body exactly as received, before any parsing. Compute the HMAC with the shared secret and the algorithm the provider names, encode it the way the provider does (GitHub and Slack use hex with a prefix), and compare it with the received signature using a constant-time comparison. A match means the request came from someone holding the secret.
An ordinary comparison stops at the first byte that differs, so it returns slightly faster the less of a guess is right. An attacker who can measure that can work towards a valid signature. Use a constant-time comparison: hash_equals in PHP, crypto.timingSafeEqual in Node.js or hmac.compare_digest in Python.
HMAC is deterministic: the same key, message and hash always give the same tag, which is what makes verification possible. Providers that need each signature to differ include a timestamp in the signed string, as Slack does.
Stripe sends a Stripe-Signature header that looks like t=xxx,v1=yyy, with a timestamp and one or more signatures. Use Stripe's own documentation or library to verify it, because the exact string it signs is defined there.
GitHub uses an HMAC hex digest of the payload, sent in the X-Hub-Signature-256 header and always starting sha256=. Compute HMAC-SHA256 over the raw body with your webhook secret, choose hex output here, and compare it with the part after sha256=.
No. HMAC is fast by design, which is wrong for passwords. Use a password-hashing function such as Argon2id, scrypt or bcrypt, which are deliberately slow and salted.
Standard base64 (RFC 4648) uses + and / and pads with =. Those characters have special meanings in URLs, so base64url uses - and _ instead and usually drops the padding. JSON Web Tokens use base64url.
Yes, with the browser's Web Crypto API. Your key and message are not sent anywhere. For real production secrets, compute signatures on your own systems rather than in any web page.

Method & sources

How it computes

HMAC via the browser's Web Crypto API (importKey raw, sign) with SHA-1, SHA-256, SHA-384 or SHA-512 over the UTF-8 message, output as hex, base64 and base64url. An empty message is accepted and only the latest keystroke's result is shown.

What this tool implements

  • The page returned nothing for an empty message (a valid HMAC input), and an earlier, slower sign() could overwrite a newer result while typing. Both fixed. Output checked against RFC 4231 test case 2 (key 'Jefe' → 5bdcc146…).
  • RFC 2104 is dated February 1997; the page said 1996. RFC 2104 on key length and RFC 6194 on HMAC-SHA-1 are quoted. Slack signs with a hex digest (v0=), not base64 as the page said twice; GitHub's hex sha256= header and AWS SigV4's final HMAC-SHA256 are from their docs.
  • Removed as unsourced: Razorpay, Xendit and NETS signing claims, Shopify's '24-hour overlap', 'timing attacks demonstrated in the wild', and the exact Stripe signed-payload format.

Sources

Advertisement
Pre-footer · AD-W3 728 × 90