Generate an HMAC for your input data directly in your browser and download the result instantly.
HMAC will appear here once you enter a message and secret.
HMAC (Hash-based Message Authentication Code) lets two parties who share a secret key prove that a message wasn't tampered with and that it came from someone who knows the key. It's defined in RFC 2104 and is the backbone of most modern API authentication. Unlike a plain hash(secret + message), HMAC uses a nested construction H((K ⊕ opad) ‖ H((K ⊕ ipad) ‖ M)) that is provably resistant to length-extension attacks on Merkle–Damgård hashes like SHA-1, SHA-256, and SHA-512.
{timestamp}.{raw_body} with HMAC-SHA256 using your endpoint secret and ships the result as v1=... in the Stripe-Signature header. GitHub uses X-Hub-Signature-256: sha256=.... Always compute the HMAC against the raw request body — re-serialised JSON will not match.base64url(header).base64url(payload). Inspect the result with our JWT Decoder.signed cookies), Express cookie-session, and Django signing attach an HMAC tag so the server can verify a cookie hasn't been edited client-side without a database lookup.HMAC(session_id, server_secret) as the CSRF token; the server can validate without storing per-session state.Need a plain digest instead of a keyed MAC? Use our Hash Generator for SHA-256, SHA-512, MD5, and other one-shot hashes.
| Algorithm | Output size | Block size | Security strength* | Recommended use |
|---|---|---|---|---|
| HMAC-SHA-1 | 160 bits (20 bytes) | 64 bytes | ~128 bits for HMAC use | Legacy compatibility only (AWS SigV2, older TOTP, OAuth 1.0a) — no known practical break against HMAC-SHA-1, but NIST recommends SHA-2/3 for new code per SP 800-107 |
| HMAC-SHA-256 | 256 bits (32 bytes) | 64 bytes | 256 bits | Default for new designs — AWS SigV4, Stripe, GitHub, Shopify, JWT HS256 |
| HMAC-SHA-384 | 384 bits (48 bytes) | 128 bytes | 384 bits | Higher-assurance APIs; immune to length-extension even in raw form |
| HMAC-SHA-512 | 512 bits (64 bytes) | 128 bytes | 512 bits | High-security signing, large keys, JWT HS512 — faster than SHA-256 on 64-bit CPUs |
*Per NIST SP 800-107 Rev. 1, the effective HMAC strength is min(strength_of_key, 2 × L) where L is the output length; truncating output below ~96 bits is discouraged for general use.
| Use case | Algorithm | Where the MAC lives | Notes |
|---|---|---|---|
| AWS S3 / IAM request signing | HMAC-SHA-256 | Authorization: AWS4-HMAC-SHA256 ... header |
Four-step key derivation per request |
| Stripe webhook events | HMAC-SHA-256 | Stripe-Signature: t=...,v1=... header |
Signs timestamp.body |
| GitHub webhook events | HMAC-SHA-256 | X-Hub-Signature-256: sha256=... header |
Signs the raw request body |
| Shopify webhooks | HMAC-SHA-256 (Base64) | X-Shopify-Hmac-Sha256 header |
Base64-encoded, not hex |
| JWT (HS256/HS384/HS512) | HMAC-SHA-256/384/512 | Third dot-separated segment | Base64url; signs header.payload |
| TOTP / Google Authenticator | HMAC-SHA-1 (per RFC 6238) | 6-digit code derivation | SHA-1 still standard for TOTP interop |
Concatenations like SHA-256(secret ‖ message) or MD5(secret ‖ message) are vulnerable to length-extension attacks because MD5, SHA-1, and the SHA-2 family (except SHA-384 and SHA-512/256) use the Merkle–Damgård construction. An attacker who has a valid hash(secret ‖ message) and knows the length of the secret can compute hash(secret ‖ message ‖ padding ‖ attacker_data) without ever learning the secret — they just resume the hash's internal state. HMAC's nested H((K ⊕ opad) ‖ H((K ⊕ ipad) ‖ M)) construction breaks that property because the outer hash takes a fixed-length input (the inner hash's digest), so there's no internal state for an attacker to extend. This is why every modern API signing scheme uses HMAC and not raw H(secret ‖ message).
For HMAC purposes specifically, yes — but only for existing systems. The 2017 SHAttered collision and 2020 chosen-prefix collision attacks against raw SHA-1 do not transfer to HMAC-SHA-1 because HMAC's security relies on the hash's PRF properties rather than collision resistance. There is no published practical attack on HMAC-SHA-1. However, NIST SP 800-107 Rev. 1 and the broader NIST deprecation timeline for SHA-1 (effective end of 2030 per NIST's December 2022 announcement) mean new designs should use HMAC-SHA-256 or stronger. TOTP and legacy AWS SigV2 are exceptions where SHA-1 remains the documented standard for interop reasons.
Per RFC 2104 §3, the key can be any length, but two thresholds matter. Keys shorter than the hash output (32 bytes for SHA-256, 64 for SHA-512) reduce the effective security strength to the key's entropy — a 16-byte SHA-256 key gives you 128-bit HMAC strength, not 256-bit. Keys longer than the hash block size (64 bytes for SHA-256, 128 bytes for SHA-512) get pre-hashed before use, which is fine but offers no additional security beyond the hash output size. The practical recommendation: generate a random key exactly equal to the hash output size — 32 bytes for SHA-256, 48 for SHA-384, 64 for SHA-512.
Always use a constant-time comparison — never ===, ==, strcmp, or Buffer.compare. A naive byte-by-byte loop returns early on the first mismatch, leaking via timing how many leading bytes were correct; an attacker on the same network can iteratively guess each byte. Use the language's documented primitive: Node.js crypto.timingSafeEqual(a, b) (both must be equal-length Buffers), Python hmac.compare_digest(a, b), Go hmac.Equal(macA, macB), Ruby OpenSSL.fixed_length_secure_compare, PHP hash_equals($known, $user). Browser code can use subtle.timingSafeEqual where supported, or implement the loop with XOR-OR accumulation manually.
Almost always one of: (1) trailing newline or whitespace in the message (Stripe and GitHub sign the raw request body byte-for-byte — re-parsed JSON will not round-trip identically because of key order, whitespace, and Unicode escaping); (2) hex vs Base64 encoding mismatch on the output; (3) key passed as a hex string instead of decoded bytes (a 64-character hex string is 64 bytes when used as text, 32 bytes when decoded); (4) UTF-8 vs UTF-16 encoding of the message in environments that default to UTF-16 (older .NET); (5) line endings flipped from \n to \r\n by Git or an editor. Diff the input bytes — not the rendered strings — to find the discrepancy.
Use a "multi-key acceptance" window. (1) Generate a new secret and start signing outbound webhooks with it. (2) On the receiver, accept either the old or the new HMAC during a transition window (24–72 hours is typical). Stripe, GitHub, and Shopify all support this — Stripe lets you have two active endpoint secrets per endpoint for exactly this purpose. (3) After the window, retire the old secret. Never rotate by hard-cutting on a deploy — in-flight retries signed with the old secret will fail verification.
HMAC is symmetric: signer and verifier share the same secret, so anyone who can verify can also forge. RSA/ECDSA signatures are asymmetric: the signer holds a private key, verifiers hold the public key, and verifiers cannot forge. Pick HMAC when you control both ends of the channel (your server signs, your webhook receiver verifies — same trust boundary), when you want simplicity and speed (HMAC-SHA-256 is roughly 10–100× faster than RSA-2048 and produces a 32-byte tag vs RSA's 256 bytes), and when key distribution is solved (you can deliver the secret over a secure channel once). Pick RSA/ECDSA when third parties need to verify but should not be able to issue tokens (public JWTs signed RS256/ES256), when you need non-repudiation in a legal/audit sense, or when distributing a shared secret to many verifiers is unacceptable. JWT supports both — HS256 is HMAC; RS256 and ES256 are RSA and ECDSA.
No. The generator uses the browser's Web Crypto API (crypto.subtle.sign('HMAC', key, data)) to compute the MAC entirely in your tab. Nothing is uploaded, logged, or persisted — you can verify by opening DevTools → Network and confirming zero outbound requests when you click Generate. Safe to paste production webhook secrets and signing keys during debugging.