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.

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.

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.

Want this built against your real numbers?
A 30-minute call to scope the workflow, agent, or automation you actually need.
More developer tools
All tools
.env Manager
Validate environment variable names and values before they reach production. Env Manager checks names against POSIX rules, flags values that different .env parsers read differently, and shows which entries are secrets that should not sit in a file.

.gitignore Generator
Build a .gitignore for your stack in seconds. Covers dependencies, build output, IDE files and the .env patterns that keep secrets out of a public repository.

API Mock Server
Create a live mock REST endpoint with your own path, method, status code, headers, delay and JSON body — so you can build and test a frontend or automation before the real API is ready.

API Request Tester
Send REST API requests from your browser with custom headers, auth and a JSON body, and inspect the status, headers and response. Includes a guide to reading status codes and diagnosing CORS.

Base64 Encoder
Convert text, JSON or files to Base64 in the browser, with nothing sent to a server. Covers the padding rules, the exact 33% size increase, and the non-canonical strings that decode to identical bytes.

Cron Expression Generator
Build cron expressions visually and get the correct string for crontab, GitHub Actions, EventBridge, Kubernetes, Make or n8n — with a field reference and the common gotchas explained.
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.