BV
All tools
developer

Hash Generator

Generate MD5, SHA-1, SHA-256, SHA-512 and HMAC digests in the browser. Includes a reproducible webhook signature example and why re-serialised JSON never matches the sender's signature.

Muhammad Bilal
Muhammad Bilal Virk
7 min read
Live tool
Everything is hashed locally in your browser — nothing is uploaded.

A hash is a fixed-length fingerprint of an input: same input, same output, every time, and no way back. An HMAC is a hash with a secret key mixed in, which turns a fingerprint into a proof of origin. This tool computes both in your browser, which is the useful thing to have open while you are debugging a webhook signature that will not verify.

What this tool does and who it is for

Paste an input, get its MD5, SHA-1, SHA-256 and SHA-512 digests. Add a secret and get the HMAC. Everything runs in your browser, which matters when the thing you are hashing is a live webhook secret.

The realistic use is debugging. A webhook arrives, your handler rejects it, and you need to know whether the signature is wrong or your verification is wrong. Computing the expected digest by hand next to the one in the header settles it in about thirty seconds. Stripe, GitHub and Shopify all sign webhooks with HMAC-SHA256, so this covers most of what you will meet.

Hash Generator — illustration

How to read the output, with a worked example

GitHub publishes a test vector for exactly this purpose, which makes it a good thing to check your understanding against.

  • Secret: It's a Secret to Everybody
  • Payload: Hello, World!
  • HMAC-SHA256: 757107ea0eb2509fc211221cce984b8a37570b6d7586c22c46f4379c8b043e17

GitHub sends that as X-Hub-Signature-256: sha256=757107ea…. Put the same secret and payload into this tool and you should get the same 64 hex characters. If you do not, the difference is in your input, not in the algorithm.

Now change the payload's last character from ! to ?. The digest becomes 319468fd7ae6faec323482b683bcff145fe8b1fc66e17a0bc724cf6d0de2f22f. Not similar. Entirely different. Lowercase the I in the secret instead and you get 746fea593dc6557dda585a3e69f1169af0a38671728f3801c8cc13bc63c5f22a. That is the avalanche property, and it is the reason a signature either matches or tells you nothing about how close you were.

The trap that breaks most first attempts

Here is the failure that costs people an afternoon. Take a payload and sign it with the secret whsec_test:

  • {"id":"evt_1","amount":2000}e4fa49c7acd34f4d6deefba5191136d686795a209a60f8146444031c8e116422
  • {"amount":2000,"id":"evt_1"}852eec0b3694dd58e1b3d1a4d42580ab9b363cac4872620ff17d6bd4aed67909

Those are the same object. Same two fields, same two values, identical once parsed. Completely different signatures, because HMAC signs bytes, and JSON objects have no canonical byte order.

Almost every web framework parses the JSON body for you before your handler sees it. If you then re-serialise that parsed object to check the signature, your library will emit its own key order, its own spacing and its own number formatting, and the digest will never match. You must verify against the raw request body, exactly as it arrived. GitHub's documentation says the same thing from the other direction: make sure no proxy or load balancer modifies the payload before verification, and handle the body as UTF-8, because payloads can contain unicode.

That single rule accounts for most "the signature never matches" tickets.

The method: hash, then HMAC

A hash function takes input of any length and produces a fixed-length digest. It is deterministic, so the same input always gives the same output, and it is one-way, so the digest tells you nothing useful about the input. SHA-256 always returns 256 bits, written as 64 hexadecimal characters, whether you feed it one letter or a gigabyte.

That gets you integrity: if the digest matches, the bytes are unchanged. It does not get you authenticity, because anyone can compute a digest.

HMAC, specified in RFC 2104, fixes that by mixing a shared secret into the hash in a specific two-pass construction. Only someone holding the secret can produce a valid HMAC, so a matching HMAC proves both that the message is unaltered and that it came from someone who knows the key.

It is worth knowing why HMAC is a construction rather than just sha256(secret + message). The naive version is vulnerable to length-extension: SHA-256 exposes enough internal state in its output that an attacker who has one valid sha256(secret + message) can compute a valid digest for message + extra without ever learning the secret. HMAC's nested design closes that. This is a case where the obvious implementation is genuinely broken and the standard one is not, so use the library.

Which algorithm to use

Algorithm Output Reach for it when Status
MD5 128-bit, 32 hex Non-adversarial checksums, cache keys, deduplication Broken for security; practical collisions exist
SHA-1 160-bit, 40 hex Legacy interop only, such as Git object IDs Deprecated; collisions demonstrated
SHA-256 256-bit, 64 hex Webhook signatures, API request signing, JWTs, integrity The sensible default
SHA-512 512-bit, 128 hex Long-lived document hashing; faster than SHA-256 on 64-bit hardware Fine
bcrypt / Argon2 / PBKDF2 Varies Storing passwords, and nothing else Correct choice for passwords

The bottom row is not a faster or slower version of the rows above it. It is a different category of thing.

Common mistakes

Hashing passwords with SHA-256. The whole point of SHA-256 is that it is fast, and speed is the attacker's advantage. On this machine a single SHA-256 took about five microseconds, while PBKDF2-SHA256 at 600,000 iterations took 0.106 seconds — roughly twenty thousand times slower, deliberately. Both numbers come from one unremarkable machine running Python, so a real cracking rig is far faster than either; the ratio is the point, not the absolute figures. Password hashing needs a deliberately slow, salted function. Everything else needs a fast one.

Comparing signatures with ==. GitHub's documentation is blunt about this: "Never use a plain == operator." A normal string comparison returns as soon as it finds a mismatched byte, so how long it takes leaks how many leading bytes were right, and that is enough to reconstruct a signature one byte at a time. Use hmac.compare_digest in Python, crypto.timingSafeEqual in Node, Rack::Utils.secure_compare in Ruby.

Verifying the parsed body. Covered above, and worth repeating because frameworks make it the default path. Capture the raw bytes before anything touches them.

Frequently Asked Questions

What is the difference between a hash and an HMAC?

A hash proves the data has not changed. An HMAC proves the data has not changed and came from someone holding the shared secret. HMAC is a hash function used inside a specific keyed construction, defined in RFC 2104, rather than a different algorithm.

Why does my webhook signature never match?

Nine times out of ten you are hashing a re-serialised version of the JSON rather than the raw request body. Key order and whitespace change the bytes and therefore the digest, even though the parsed object is identical. Capture the raw body before your framework parses it, and confirm no proxy is rewriting it in transit.

Is MD5 safe to use for anything?

For non-adversarial work, yes: cache keys, detecting whether a file changed, deduplicating rows. Practical collision attacks mean you must never use it where someone benefits from forging a match, which rules out signatures, passwords and integrity checks on anything downloaded.

Can a hash be reversed?

Not by inverting the function. It can be reversed by guessing, which is a real risk when the input space is small. Hashing a mobile number, a postcode or a date of birth gives very little protection, because an attacker can simply hash every possibility and compare.

Which hash should I use to store passwords?

None of the ones on the top four rows of the table above. Use bcrypt, Argon2 or PBKDF2 with a per-user salt and a deliberately high work factor, and let a maintained library choose the parameters.

Is my input sent to a server?

No. The digests are computed in your browser.

Where this tool stops

It computes a digest. Deciding what to sign, when to check it and what to do when a check fails is the part that determines whether an integration is actually secure, and none of that is visible in a hex string.

A verification layer worth having captures the raw body before parsing, compares in constant time, rejects anything older than a short tolerance window, stores delivery IDs so a replay is recognised, returns quickly enough that the sender does not retry, and logs failures in a way that distinguishes a wrong secret from a tampered payload from a misconfigured proxy. That last one matters more than it sounds: the failure modes look identical from the outside, and without decent logging you are guessing.

That is the work I take on: n8n and Make.com workflows, FastAPI services that sit between two systems and handle the signing, retry and idempotency properly, and small browser-side utilities like this one where the alternative is pasting a client's secret into someone else's site. If you have a webhook you cannot get verifying, or an integration that works in testing and drops events in production, that is a good message to send. I am on Upwork and Fiverr, or at iam.mbilalvirk@gmail.com.

Both the FastAPI webhook guide and the n8n webhook tutorial walk through the HMAC verification step in code, and the JWT decoder is the tool to reach for when the signature you are checking is on a token rather than a payload.

Muhammad Bilal
Muhammad Bilal Virk
AI automation engineer — building agents, workflows, and RPA that remove repetitive work.
Share
Newsletter

One email, when I ship something worth reading.

No cadence, no filler. Unsubscribe any time.

Free consultation

Want this built against your real numbers?

A 30-minute call to scope the workflow, agent, or automation you actually need.

Book a free consultation

More developer tools

All tools
Next step

Have a workflow that's burning hours every week?

Bring me one real bottleneck. I'll tell you whether it's worth automating, and what it would take.

Book 30 Minutes Call