HMAC Generator
Generate HMAC signatures with SHA-1, SHA-256, SHA-384 and SHA-512.
Reviewed by Aygul Dovletova · Last reviewed
Signing a Message with a Shared Secret
- Paste the message you want to authenticate into the message textarea. This is the bytes that will be signed; anything from a JSON webhook body to a Unicode string works.
- Enter the shared secret in the key input. In production this is typically a 32-byte random value from a CSPRNG encoded as hex or Base64; for testing any string is accepted.
- Pick the underlying hash: SHA-1 for legacy interop (AWS Signature v2, RFC 2104 test vectors), SHA-256 for almost everything modern (JWT HS256, Stripe webhooks, GitHub webhooks), SHA-384 for higher-security payloads, SHA-512 when you need the longer tag.
- Click "Generate HMAC". The tool imports the key via
crypto.subtle.importKeywith the matching algorithm name (HMACwithhash: 'SHA-256'), then callscrypto.subtle.signon your message bytes. - Copy the hex digest and paste it into the
X-Signatureheader (or wherever your API expects it). On the receiving side, the server recomputes HMAC on the same bytes with the same key and compares with a timing-safe equality check.
What HMAC Solves That a Bare Hash Cannot
HMAC (Hash-based Message Authentication Code) is specified in RFC 2104 and FIPS 198-1: HMAC(K, m) = H((K' XOR opad) || H((K' XOR ipad) || m)) where K' is the key padded to block size, ipad = 0x36 repeated and opad = 0x5C repeated. The double-hash with inner/outer padding defeats length-extension attacks on raw Merkle-Damgard SHA-1/SHA-256. Given bare SHA256(key || msg), an attacker who observes one valid tag can forge a tag for key || msg || padding || evil; HMAC prevents this. The Web Crypto API exposes HMAC through crypto.subtle.sign and crypto.subtle.verify, both implemented natively (BoringSSL for Chromium, NSS for Firefox). The verify path runs in constant time. This tool uses only sign; in production verification code, always use verify rather than comparing hex with ===.
Where HMAC Shows Up in Real Systems
- Webhook signature verification: GitHub signs webhook bodies with HMAC-SHA-256 in the
X-Hub-Signature-256header; Stripe usesStripe-Signaturewith HMAC-SHA-256; Slack uses a versioned HMAC-SHA-256 scheme. - JWT signing for HS256/HS384/HS512 algorithms (RFC 7518), used by Auth0, Clerk, and every library that supports symmetric JWTs.
- AWS Signature Version 4 for all REST API calls: a chain of HMAC-SHA-256 invocations derives per-request, per-region, per-service signing keys from your secret access key.
- TOTP and HOTP one-time password codes (RFC 6238, RFC 4226) compute HMAC-SHA-1 of a time counter and dynamically truncate to 6 digits.
- TLS 1.2 record layer uses HMAC for message integrity inside ciphersuites that are not AEAD (though TLS 1.3 moved entirely to AEAD).
- Signed URLs (S3 presigned URLs, CloudFront signed URLs, custom CDN token auth) embed an HMAC that the server verifies before serving the resource.
The Failure Modes That Actually Cause Outages
The top HMAC implementation bug is non-constant-time comparison. If you compare the received tag to the computed tag with === or ==, the early-exit on first byte mismatch leaks timing information. The fix is crypto.subtle.verify, crypto.timingSafeEqual in Node, hmac.compare_digest in Python. The second is key confusion across algorithms: if your server accepts both HS256 and HS384, an attacker can swap algorithm headers and sign with a longer key. Pin the algorithm server-side. Third, canonicalization: HMAC signs bytes, so sender and receiver must agree on exact bytes. GitHub and Stripe sign raw request bodies; if middleware re-serializes before verification, the tag will not match. Fourth, HMAC keys must be treated like any other secret - a shared key in source code is a plaintext password.
RFC 2104, FIPS 198-1, and Why HMAC Looks Weird
HMAC was designed by Bellare, Canetti, and Krawczyk in 1996 and standardized in RFC 2104 (1997) as the IETF\'s answer to the CBC-MAC pitfalls and the ad-hoc "secret prefix" schemes that preceded it. The inner-outer padding structure ensures HMAC remains a secure MAC even if the underlying hash function has some collision weaknesses: HMAC-MD5 was still secure long after MD5 collisions were found, because collision resistance is not the property HMAC needs from its hash. What HMAC needs is pseudo-random-function behavior, which SHA-1, SHA-256, and SHA-512 all provide. The output size equals the underlying hash output size: 20 bytes for HMAC-SHA-1, 32 bytes for HMAC-SHA-256, 64 bytes for HMAC-SHA-512. Truncation is allowed (RFC 2104 section 5) down to half the hash output - HMAC-SHA-256-128 truncates to 16 bytes and is still secure. The key can be any length; if it is longer than the hash block size (64 bytes for SHA-256, 128 for SHA-512) it is hashed first, so using a 1MB key gains nothing beyond the first block-size-hashed bytes.
HMAC vs Poly1305, KMAC, and Asymmetric Signatures
HMAC is the incumbent; Poly1305 (RFC 8439, ChaCha20-Poly1305 AEAD) is much faster than HMAC-SHA-256 on platforms without SHA-NI and is what TLS 1.3 mobile connections use. KMAC (NIST SP 800-185) is the SHA-3-based alternative, cleaner but not widely deployed. For asymmetric trust where only one party has the signing key, use Ed25519 (RFC 8032) or ECDSA - HMAC requires both parties share the secret. Practical guidance: webhook signatures, JWT HS-prefix, AWS signing, TOTP use HMAC-SHA-256. Tight inner loops use Poly1305. Multi-party trust uses Ed25519. The companion RSA and TOTP tools on this site cover those alternatives.
Frequently Asked Questions
What key length should I use for HMAC-SHA-256?
At least 32 bytes (256 bits) of random data from a CSPRNG. RFC 2104 allows any length, but shorter keys reduce the security margin - an 8-byte key gives only 64 bits of brute-force resistance. Longer than the hash block size (64 bytes for SHA-256) provides no additional security because HMAC hashes oversized keys down to block size. The sweet spot is exactly 32 bytes for HMAC-SHA-256 and 64 bytes for HMAC-SHA-512, generated once and stored in a secret manager.
Is my key or message sent to a server?
No. crypto.subtle.importKey and crypto.subtle.sign run in your browser's native crypto library. The key is wrapped in a non-extractable CryptoKey object that never leaves the crypto module, and the message bytes are processed locally. There is no fetch, no XHR, and no service-worker intercept. Open DevTools Network tab and confirm zero requests fire when you click Generate. This is important when you are signing webhook payloads during debugging and the payload contains production data.
Why does JWT HS256 use HMAC instead of a hash?
Because a JWT needs both integrity (the payload was not modified) and authenticity (the token was issued by someone who knows the secret). A bare SHA-256 over the JWT body would be modifiable by anyone who can recompute the hash; HMAC-SHA-256 requires the attacker to know the secret. RFC 7518 specifies HS256/HS384/HS512 with matching HMAC variants. For public-key JWTs (RS256, ES256, EdDSA), the verifier only needs the public key, which is the right choice when the verifier should not be able to issue new tokens.
How do I verify an HMAC in constant time?
Use crypto.subtle.verify in the browser, crypto.timingSafeEqual in Node.js, hmac.compare_digest in Python, or subtle.ConstantTimeCompare in Go. Never use === to compare HMAC tags - it returns early on first byte mismatch, leaking timing information. An attacker making repeated requests can extract the tag byte-by-byte from the timing side-channel. This attack was demonstrated against real systems (Xbox 360 secure boot, Java JJWT library) before constant-time comparison became standard practice.
Is HMAC-SHA-1 still safe to use?
Yes, for authentication. HMAC's security does not require collision resistance from the underlying hash, so SHAttered (2017) does not break HMAC-SHA-1. It is still used by TOTP (RFC 6238 default) and AWS Signature v2. New designs should use HMAC-SHA-256 for ecosystem consistency. If you are bound by FIPS 140-3, HMAC-SHA-1 is still approved for authentication but not for new designs.
Can I use the same secret key for encryption and HMAC?
No. Key reuse across primitives is a classic pitfall. The safe pattern is to derive two subkeys from a master key using HKDF (RFC 5869) with different info strings - one for encryption, one for MAC. If you need both confidentiality and authenticity, use an authenticated encryption mode (AES-GCM, ChaCha20-Poly1305) that handles both in one primitive.
Does HMAC defend against replay attacks?
Not by itself. HMAC proves the message was not modified and came from someone with the key; it does not prove the message is recent. A valid HMAC-tagged request can be replayed. The standard defenses are nonces (rejected after one use), timestamps with a narrow acceptance window (AWS Signature v4 rejects requests older than 15 minutes), or sequence numbers. Stripe rejects webhook payloads older than 5 minutes; GitHub gives you a Delivery ID but replay defense is up to you.
How does this tool compare to openssl dgst -hmac?
Cryptographically identical output. openssl dgst -sha256 -hmac "mykey" produces the same hex digest. The CLI advantage is streaming large files and scriptability; this tool wins for not requiring a shell, showing all four variants, and staying offline. For programmatic HMAC, use your language's stdlib (hmac in Python, crypto.createHmac in Node) rather than shelling out.
More Developer Tools
Base64 Encoder & Decoder
Encode UTF-8 text to Base64 online or decode Base64 back to UTF-8 and plain text. Runs in your browser with no upload.
Open toolBulk URL Encode / Decode
Encode or decode many URLs at once. Paste a newline-separated list and the tool processes each line in parallel, preserving order and blank lines.
Open toolCode Screenshot
Create beautiful code snippet images with customizable themes.
Open toolColor Converter
Convert colors between HEX, RGB, HSL and CMYK formats.
Open toolCron Expression Parser
Parse cron expressions into human-readable schedules with next run times.
Open toolCSS Formatter / Minifier
Format, beautify and minify CSS code.
Open tool