MiServe DevTools

Your lid

Pin tools here. They are saved in this browser.

HMAC Generator

Sign a message with a secret key using HMAC-SHA256 or another hash, and check a signature you received.

HMAC (hex)
HMAC (Base64)

Runs in your browser with WebAssembly. Nothing you paste is uploaded.

About this tool

What an HMAC proves

HMAC (RFC 2104) mixes a message with a secret key through a hash function and returns a short tag. Whoever holds the same key can compute the tag again. If the two tags are equal, the message was not changed on the way (integrity) and it was produced by someone who knows the key (authenticity).

A plain hash cannot do this, because anyone who alters the message can also recompute its hash. An HMAC does not hide the message, so it is not encryption. And because both sides hold the same key, it cannot show which of the two wrote the message. That takes a digital signature with a private key.

Webhook signatures

A common place to meet HMAC is a webhook. The provider signs the request body with a secret it shares with you and sends the tag in a header, and your server computes the same HMAC before trusting the request. GitHub sends X-Hub-Signature-256: sha256=… as hex, Shopify sends X-Shopify-Hmac-SHA256 as Base64, and Stripe signs the timestamp, a dot and the body, then sends the result as v1=… inside Stripe-Signature.

Sign the raw bytes of the body exactly as they arrived. If a framework parses the JSON and you serialise it again, spacing and key order change and the HMAC no longer matches. When a signature fails here, look first at the key encoding (text, hex or Base64), then at a trailing newline in the message.

Why a server compares in constant time

An ordinary string comparison stops at the first character that differs. On a server, that makes the response a little faster when the first bytes of a forged signature are wrong and a little slower when they are right, and an attacker who can measure this can recover a valid tag byte by byte. A constant-time comparison reads every byte whatever the result. Use the function your platform provides: crypto.timingSafeEqual in Node.js, hmac.Equal in Go, hmac.compare_digest in Python, hash_equals in PHP.

The compare field on this page works the same way: it decodes both values to bytes and reads all of them. In a browser tab that already holds both values there is no timing to hide, so here it only tells you whether your own code produced the right tag.

How it runs

The tag is computed by Go's crypto/hmac package compiled to WebAssembly and run in a background thread of your browser. The message is taken as UTF-8, with nothing added or trimmed. One thing does change: a text box in a browser keeps every line break as a single line feed, so a message that arrived with CRLF line endings is signed here with LF. The key is taken as UTF-8 text, or decoded from hex or Base64 when you say so. Neither is sent anywhere. A production secret is still best kept out of web pages: use a test key when you can.

Questions

Why is my HMAC different from the one my server computes?

The usual causes are the key being read in the wrong encoding (a hex or Base64 key treated as plain text), a trailing newline or different line endings in the message, a body that was parsed and serialised again, or a different hash algorithm. Also check whether the other side prints hex or Base64.

Is HMAC the same as hashing the key followed by the message?

No. With SHA-256, SHA-512, SHA-1 or MD5, a hash of key plus message can be extended: someone who sees the hash can append data and compute a valid hash without knowing the key. HMAC hashes twice with two derived keys, which closes that hole.

How long should an HMAC key be?

Use a random key at least as long as the hash output: 32 bytes for SHA-256, 64 bytes for SHA-512. A longer key adds little, and a key longer than the hash's block size is hashed down first. A short or guessable key can be found by trying candidates against one known message and tag.

Are HMAC-SHA1 and HMAC-MD5 broken?

The collision attacks that broke SHA-1 and MD5 as plain hashes do not translate into a practical forgery of their HMACs. They are still found in older protocols, but for anything new choose HMAC-SHA256 or stronger.

More in Hashing