HMAC generator & signature checker

Computes HMAC-SHA-1, SHA-256, SHA-384 and SHA-512 from a message and a key, and identifies which one a given signature came from.

Message
HMAC-SHA-1
HMAC-SHA-256
HMAC-SHA-384
HMAC-SHA-512

Enter a key to compute the signatures.

What this tool does

HMAC turns a message and a shared secret into a short signature. Anyone holding the same secret can recompute it and see whether the message arrived unchanged and came from someone who also knows the secret. This tool computes all four common variants at once, and — given a signature you were sent — tells you which one produced it.

That second direction is usually the reason people arrive. A webhook is failing verification, and the question is not really "is this signature valid" but "which of the several plausible things am I doing differently from the sender".

The key is where this goes wrong

HMAC signs bytes with bytes. The message is usually obvious — the raw request body — but the key almost never is, because a secret arrives as a string and a string is not bytes until you decide how to read it:

a3f2   as text     4 bytes   61 33 66 32
a3f2   as hex      2 bytes   a3 f2

Both readings are legitimate, both produce a perfectly well-formed signature, and the two signatures have nothing in common. Nothing warns you: there is no error, no length complaint, just a value that does not match the one the sender computed. That is why the key encoding here is a visible choice rather than a guess — when a signature does not match, this is the first thing to flip.

As a rough guide: a secret with a prefix like whsec_ or a run of mixed-case letters and digits is normally meant as text; a string of exactly 32 or 64 characters using only 0-9 and a-f is usually hex; and one ending in = is almost certainly Base64. But check the sender’s documentation rather than the shape, because the shape is not proof.

The message has to be the exact bytes

The other half of a mismatch is the message. HMAC is defined over bytes, so anything that changes the bytes changes the signature completely — there is no partial credit and no near miss.

  • Re-serialising JSON. Parsing a body and stringifying it again may reorder keys, change spacing, or normalise numbers. Sign and verify the raw body you received, never a round-tripped copy of it.
  • A trailing newline. Some tools add one when you save the body to a file; it is a byte, and it changes everything.
  • Character encoding. A body containing non-ASCII text has to be read as the same encoding both sides use — UTF-8 in practice.
  • Compression or middleware. If something in front of your handler decompresses or rewrites the body, verify before that happens, not after.

Many providers also do not sign the body alone. Stripe signs a timestamp and the body joined with a dot; AWS signs a canonical request built from method, path, headers and a hash of the payload. If verification fails against the plain body, the signed string is probably not the plain body — that is documented on the sender’s side and worth reading before debugging further.

Why SHA-1 is offered here and not in the hash tool

The hash tool marks SHA-1 as broken. This one lists HMAC-SHA-1 without a warning, and that is deliberate rather than an oversight.

SHA-1 is unusable for signatures and certificates because collisions can be constructed: two different documents can be made to share a digest. HMAC does not depend on that property. Its security rests on the secret key, and the construction — hashing the message twice, with the key mixed in both times — holds up even when the underlying hash is collision-weak. HMAC-SHA-1 remains sound and is still what OAuth 1.0a and older AWS signing use, so a tool that refused to compute it would simply be less useful without being safer.

For anything new, SHA-256 is the sensible default. Longer digests are not meaningfully stronger here — the security ceiling is the key, not the digest length — so SHA-384 and SHA-512 are worth choosing only when something you must interoperate with asks for them.

Comparing signatures safely

This page compares with an ordinary string comparison, which is fine here: you are holding the key yourself, so there is nothing to leak. In a server verifying an incoming request, it is not fine. An ordinary comparison stops at the first differing byte, so the time it takes reveals how much of a guess was correct, and an attacker who can send many requests can recover a valid signature one byte at a time.

Use the constant-time comparison your platform provides — crypto.timingSafeEqual in Node, hmac.compare_digest in Python, hash_equals in PHP — on the raw bytes rather than on hex strings. Along with it, compare against a signature you computed yourself rather than trusting an algorithm named in the request, and reject a message whose timestamp is far from now so an old valid signature cannot be replayed.

HMAC is not a hash, and not a signature

Three things get confused here, and the difference matters for what you can claim afterwards:

  • A hash takes a message and produces a digest. Anyone can compute it, so it proves the message has not changed accidentally — not that it came from anyone in particular.
  • An HMAC takes a message and a shared secret. Both parties hold the same key, so it proves the sender knew the secret. It cannot prove which party sent it, because either could have produced it.
  • A signature uses a private key that only the sender holds, and a public key anyone can verify with. That is what gives non-repudiation: the sender cannot later deny it.

So HMAC is the right tool between two systems that already share a secret — webhooks, internal APIs, session tokens — and the wrong one when you need to prove to a third party who sent something. Also note it authenticates but does not conceal: the message travels in the clear, and HMAC says nothing about confidentiality.

Frequently asked questions

My signature does not match. What do I check first?
The key encoding, then the message bytes. A secret that looks like hex is often meant as hex rather than as text, and the two produce completely different signatures with no error either way. After that, make sure you are signing the raw body exactly as received rather than a re-serialised copy of it.
Why is SHA-1 offered here when the hash tool says it is broken?
Because HMAC does not rely on collision resistance, which is the property SHA-1 lost. Its security comes from the key. HMAC-SHA-1 is still sound and still in use by OAuth 1.0a and older AWS signing, though SHA-256 is the right default for anything new.
Is a longer digest more secure?
Not meaningfully. The strength of an HMAC is bounded by the secret, not by the digest length, so SHA-512 is not four times better than SHA-256. Pick the one the other side expects.
What is the difference between HMAC and a digital signature?
HMAC uses one secret that both sides know, so it proves the sender knew the secret but not which side sent it. A digital signature uses a private key only the sender holds, so a third party can verify it and the sender cannot deny it. If you need that last property, HMAC is the wrong tool.
Should I compare signatures with ===?
Not in a server. An ordinary comparison returns as soon as bytes differ, and that timing leaks how much of a guessed signature was right. Use your platform’s constant-time comparison on the raw bytes. On this page it does not matter, because you already hold the key.
Is my key sent anywhere?
No. Everything is computed in your browser with the Web Crypto API; the message and the key never leave your device.