HMAC-SHA-256: Signing and Verifying Payloads Correctly
HMAC-SHA-256 is the default keyed authentication tag: 256 bits, 64 hex characters, defined by RFC 2104 over SHA-256. It is what a webhook signature or an API request signature should use, and it is the correct fix for a homemade hash(secret + body) scheme.
At a glance
- Tag size
- 256 bits
- Hex characters
- 64
- Inner hash block size
- 64 bytes. Keys longer than 64 bytes are hashed down first
- Standard
- RFC 2104 and FIPS 198-1, over SHA-256 from FIPS 180-4
- Recommended key length
- At least 32 random bytes, generated by a cryptographic random source, never a password
- Safe for password storage
- No. Use a memory-hard password hash such as Argon2id, scrypt or bcrypt
- Available in the generator
- Yes, once you fill in the secret field
In detail
The reason HMAC exists rather than hash(secret + message) is length extension. With SHA-256, an attacker who sees a digest of secret plus message and knows the secret's length can append arbitrary bytes and compute a valid digest for the longer message without ever learning the secret. HMAC's two keyed passes destroy that property, and it is the only construction you should use when the goal is proving a message came from someone holding the key.
It has become the default for machine to machine authentication. Payment and messaging platforms sign webhook bodies with it, AWS Signature Version 4 chains four HMAC-SHA-256 operations to derive a request specific signing key, and JSON Web Tokens using HS256 are exactly an HMAC-SHA-256 over the header and payload. Every one of those is verifying the same thing: this byte sequence has not changed and came from the key holder.
Verification goes wrong in predictable ways. Recompute the tag over the exact raw request body, not over a re-serialised object, because reordering keys or changing whitespace changes the bytes and therefore the tag. Compare in constant time. And a valid tag proves authenticity, not freshness, so include a timestamp inside the signed material and reject anything old, or the same signed request can be replayed forever.
The key is not a password. It should be at least 32 random bytes from a cryptographic random source, stored as a secret and rotated on a schedule. HMAC-SHA-256 with a key of 'changeme' is a brute forceable function, because an attacker who has one message and one tag can test candidate keys offline as fast as their hardware allows.
That last point is exactly why HMAC-SHA-256 is not password storage either. It is one fast pass over the input, so an offline attacker with a leaked table tests billions of guesses per second. Passwords need Argon2id, scrypt or bcrypt with a tuned cost and memory setting. ToolBox does not provide a password hashing tool and this generator is not a route to one.
Examples
key: "Jefe"
data: "what do ya want for nothing?"
HMAC-SHA-256
= 5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843Paste the key into the secret field and the data into the input to reproduce this exactly.
X-Signature: sha256=f7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8
That tag is HMAC-SHA-256 with:
key = "key"
data = "The quick brown fox jumps over the lazy dog"
Verify by recomputing over the raw body and comparing in
constant time. Never over a reparsed and re-serialised object.Things that catch people out
- Signing a parsed and re-serialised JSON body instead of the raw bytes is the single most common webhook verification bug. Key order, unicode escaping and whitespace all change the bytes.
- A correct tag says nothing about when the message was sent. Without a signed timestamp and a replay window, a captured request stays valid indefinitely.
- Encoding matters on both sides. The same tag can be written as 64 lowercase hex characters, 64 uppercase, or 44 Base64 characters. The generator offers hex or Base64 with an uppercase toggle for hex, so you can produce whichever form the other system expects.
- HMAC-SHA-256 is a shared secret scheme. Both parties can produce a valid tag, so it proves authenticity between them but gives no non-repudiation. If you need to prove to a third party who sent something, you need a signature, not a tag.
Try it: Hash Generator
Paste text or drop a file and get every digest at once, in hex or Base64, with a verify tab for comparing an expected value against what you actually have.
Hash Generator
LOCAL · Browser-OnlyGenerate MD5, SHA-1, SHA-256, SHA-384, SHA-512, SHA3-256, SHA3-512, Keccak-256, CRC32, and HMAC hashes from text or files
MD5 is cryptographically broken and should not be used for security purposes. Use SHA-256 or SHA-512 instead.
Related Hash algorithms
All hash algorithms →HMAC-SHA-1: Still Sound Even Though SHA-1 Collisions Are Not
HMAC-SHA-1 produces a 40 character tag and is not affected by the SHA-1 collision attacks. Why that is true, and where it is still deployed today.
HMAC-SHA-512: 512 Bit Tags, HS512 Tokens and Key Sizing
HMAC-SHA-512 produces a 128 character tag. How HS512 tokens use it, why key length is capped by the 128 byte block, and when the width is wasted.
SHA-256: The Default Choice and How It Is Used
SHA-256 gives a 64 character hex digest with no practical collision or preimage attack. Where it belongs, where it does not, and its length extension flaw.
MD5: 128 Bit Digests, Broken Collisions, and Remaining Uses
MD5 produces a 32 character hex digest. Collisions have been practical since 2004, preimages have not. What that distinction rules out, and what it does not.
HMAC-SHA-384: 384 Bit Tags and the 128 Byte Block Size
HMAC-SHA-384 gives a 96 character tag over a 128 byte block. Where JWT HS384 and TLS use it, and why the key length threshold is different.
CRC32: What a Checksum Detects and What It Cannot
CRC32 gives an 8 character checksum that catches accidental corruption and nothing else. Why it is trivially forgeable and never a security control.
Tools for this
- Hash Generator Free online hash generator - generate MD5, SHA-1, SHA-256 hashes from any input text
- Base64 Encoder/Decoder Base64 encode and decode online - convert text to Base64 or decode Base64 strings instantly, free
- AES Encryption Tool Free online AES encryption tool - encrypt and decrypt text using AES-256 encryption