cipher.ink Write a message

Tools · Hashing and verification

Compare two hashes

Paste two checksums and see whether they match, even if one is uppercase, has colons in it, or is Base64 instead of hex.

Nothing you paste here leaves your browser.

This hash comparer tells you whether two checksums are the same value, and if they aren't, exactly which characters differ. Paste one in each box. It ignores case, colons, spaces and prefixes, and it reads hex and Base64 alike. It runs in your browser, and nothing you paste leaves it.

What it does

Capital letters in one box and lower case in the other don't matter. Neither do colons between the bytes, a 0x a web page added, or one digest in Base64 and the other in hex. The comparison is made on the bytes. When the two differ, every character that isn't the same is highlighted, so a typo and two unrelated values are easy to tell apart at a glance.

That second part is the point. Comparing two 64-character strings by eye is a job people think they can do and can't. The middle of a long hex string is invisible to a skimming reader, and a checksum that matches in the first eight and last eight characters feels the same as one that matches everywhere. The comparer counts the difference for you. About half of a hash's characters change when the input changes, so "35 of 64 characters differ" is the signature of two different inputs, and "1 of 64" is almost certainly a mistyped character.

What gets ignored before comparing

  • Leading and trailing spaces, quotes and new lines.
  • Upper or lower case in hex (ABCD and abcd are the same number).
  • Spaces, colons, commas and dashes between pairs of digits, as in ba:78:16:bf…, which is how many certificate viewers print fingerprints.
  • A 0x prefix, and a label such as sha256: or MD5 = in front.
  • Base64 and base64url, converted to hex, so ungWv48Bz+pBQUDeXa4iI7ADYaOWF3qctBD/YfIAFa0= equals ba7816bf…15ad. A Subresource Integrity string such as sha256-… is read the same way.

The page tells you which of these it applied, so nothing is hidden. If one box is hex and the other isn't, and they still come out different, check that both describe the same algorithm. A 32-character value can't be SHA-256.

What a match means, and what a mismatch means

Equal digests mean the inputs were identical, with one caveat. For MD5 and SHA-1, two different inputs can be built on purpose to collide (the hash generator page has the history). For SHA-256 and the algorithms after it, no collision has ever been found, and a match means the same bytes. Different digests mean the inputs differ by at least one bit. The usual causes, in order:

  1. You hashed different bytes. A text editor added a final newline, line endings changed from Windows to Unix, or the file was re-saved in another encoding.
  2. The download is damaged or incomplete. A truncated file gives a completely different digest.
  3. You used a different algorithm from the publisher's. Compare lengths first.
  4. The file isn't the one the publisher meant, which is the case a checksum exists to catch.

To hash a file and compare it with a published value in one step, use the file checksum verifier. If you don't know which algorithm a digest came from, try the hash identifier.

Why not just use == in code?

This page compares digests so you can read the answer. In a program, when the digests are secrets an attacker could guess byte by byte, such as a message authentication code or a session token, compare them in constant time (crypto.timingSafeEqual in Node, hmac.compare_digest in Python, hash_equals in PHP). An ordinary == can return as soon as it finds a different byte, and over a network a determined attacker can sometimes measure that. A public checksum like a download hash has nothing secret to leak, so it doesn't matter there. Our HMAC tool has a verify mode for the case where it does.

Common questions

Does it work with fingerprints from certificates and SSH keys?

Yes for hex fingerprints with colons, like the SHA-256 fingerprint a browser shows for a TLS certificate. OpenSSH prints SHA-256 fingerprints as Base64 with a SHA256: label, which this page also reads. It removes the label and decodes the Base64.

Why is a 64-character hex string "256 bits"?

Each hex character is four bits, so 64 characters are 256 bits, which is 32 bytes. The tool prints the size so you can spot a mismatch of algorithm.

Is there a limit on length?

No. It compares any two hex or Base64 strings, including the 128-character digests of SHA-512.

Are my digests sent anywhere?

No. The comparison runs in this page's own JavaScript, and the page makes no network requests.

Further reading

  1. RFC 4648: The Base16, Base32, and Base64 Data Encodings
  2. Python: hmac.compare_digest