Hash Generator

MD5, SHA and CRC of text or a whole file. HMAC too, and a checksum to compare against

Digests

Hex, Base64 or decimal. A sha256sum line or a sha256: prefix is fine as it stands.

A hash takes any amount of input and returns a fixed number of bytes. There is exactly one thing you can do with the result: compare it to another one.

SHA-256("hello")   2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824
SHA-256("Hello")   185f8db32271fe25f561a6fc938b2e264306ec304eda518007d1764826381969

One bit of input changed. Nothing about the output survived it.

That is the property everything else rests on. Change one bit anywhere in a four gigabyte file and roughly half the bits of the digest change, with no pattern connecting the two. It is why a digest can stand in for a file, and why comparing digests is a meaningful way of comparing files.

"hello"   MD5       5d41402abc4b2a76b9719d911017c592
"hello"   SHA-1     aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d
"hello"   SHA-256   2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824
"hello"   CRC-32    3610a686

""        MD5       d41d8cd98f00b204e9800998ecf8427e
""        SHA-256   e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855

Note the last two lines. The empty input has a digest, and it is always the same one. d41d8cd98f00b204e9800998ecf8427e ande3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855are worth recognising on sight: both mean "this hashed nothing", which is almost always a file that failed to load, and not one that was meant to be empty on purpose.

Broken means collisions, not reversal

There is no such thing as decrypting an MD5. The function threw information away and no amount of cleverness puts it back. Every site offering to reverse one is running a lookup table of digests it has already computed, which works beautifully on password123 and not at all on anything with more than about forty bits of entropy in it.

What "broken" means is different and worse: given one input, an attacker can construct a second, different input with the same digest. For MD5 that takes seconds on a laptop. For SHA-1 it was demonstrated publicly in 2017 and has become cheap since. So:

None of these is a password hash

Every algorithm here is designed to be fast, and modern hardware runs SHA-256 at billions of guesses a second. Storing a password assha256(password), salted or not, means an attacker with your database is running a dictionary through it before you have finished reading the incident report.

Password hashing wants the opposite property: deliberate slowness, tunable upwards as hardware improves, and memory-hardness so that a graphics card is no faster than a CPU. That is bcrypt, scrypt and Argon2, and nothing on this page substitutes for them.

Gluing the key on does not work, and HMAC is the reason why

Not this:   SHA-256(secret + message)
                Anyone can append to the message and produce
                a valid digest for the longer one, without
                ever learning the secret.

This:       HMAC-SHA-256(secret, message)

MD5, SHA-1 and the SHA-2 family are Merkle-Damgård constructions: they process the message in blocks and carry a running state, and the digestis that state. Which means somebody who has a digest can restore the state, carry on hashing, and produce a valid digest forsecret + message + padding + anything they like. They never need the secret.

HMAC hashes twice, with two different pads derived from the key, and that closes it. Turn the key on above and every SHA row becomes an HMAC. MD5 gets one too, worked out by hand on this page, because HMAC-MD5 is still all over old APIs and no browser will touch it.

SHA-384 is the exception in the family: it is SHA-512 with a different starting state and the output cut in half, and because the digest is only part of the internal state there is nothing to continue from.

A checksum answers a different question

CRC-32 and Adler-32 are not on this page as weak hashes. They are not hashes at all. They were designed to notice that a wire flipped a bit, they are cheap enough to run on every Ethernet frame, and anybody who wants a different message with the same value can construct one by hand.

Where you meet itWhich one
zip, gzipCRC-32 of the uncompressed data, stored in the trailer
PNGCRC-32 over every chunk, so a truncated PNG fails loudly
zlib streamsAdler-32, chosen for speed over CRC-32
EthernetCRC-32, in hardware, on every frame

If a tool tells you a CRC matched, it means the file arrived intact. It does not mean the file is the one you asked for.

The same digest, twice, looking nothing alike

SHA-256("hello")

hex       2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824
Base64    LPJNul+wow4m6DsqxbninhsWHlwfp0JecwQzYpOLmCQ=

The same 32 bytes. Two strings with nothing in common to look at.

A surprising share of "the checksums do not match" is one side printing hex and the other printing Base64. Docker digests are hex with ansha256: prefix. Subresource integrity attributes are Base64 with an sha256- prefix. Both refer to the same 32 bytes.

The comparison box above takes any of them: hex in either case, with or without colons or spaces, Base64 with or without padding, asha256sum line with the filename still attached, or a decimal CRC. If it matches something, the row says so. If it matches nothing, the length alone narrows down what produced it.

Digest lengths, and what they rule out

Hex charactersBitsWhat it could be
832CRC-32, Adler-32
32128MD5, MD4, a UUID with the hyphens taken out
40160SHA-1, RIPEMD-160, a git object id
56224SHA-224, SHA3-224
64256SHA-256, SHA3-256, BLAKE2s
96384SHA-384, SHA3-384
128512SHA-512, SHA3-512, Whirlpool, BLAKE2b

Length narrows it down and never settles it. SHA-256 and SHA3-256 are different functions producing different values at the same length, and the only way to tell which one you are holding is to compute both.

Comparing two digests is not ===

In a browser, checking a digest with a normal string comparison is fine. On a server checking a signature, it is not: string comparison stops at the first byte that differs, so the time it takes leaks how much of the value was correct, and an attacker with enough attempts recovers the digest one byte at a time.

Every language has a constant-time comparison for this:crypto.timingSafeEqual in Node, hmac.compare_digestin Python, subtle.ConstantTimeCompare in Go. Use it anywhere the value being compared is a secret.