Encryption / Hash

File Hash

Compute MD5, SHA-256 and other hashes for files to verify downloads or compare files.

Algorithm:
Drag files here or click to choose files

What is File Hash Calculator?

File hash calculator computes cryptographic hashes of files to verify integrity and detect modifications.

Supported Algorithms

  • MD5
  • SHA-1
  • SHA-256
  • SHA-512

Use Cases

  • Download verification
  • File integrity checking
  • Duplicate detection

This tool reads a file from disk and prints its MD5, SHA-1, SHA-256, SHA-384 or SHA-512 digest in hex, computed entirely inside the browser tab. It is meant for checking a download against the publisher checksum, spotting byte-level differences between two copies, and recording a fingerprint of an artifact before you ship it.

A digest covers bytes, not the text you see

A file hash is computed over the bytes on disk. Saving the same sentence on Windows inserts 0x0D before every 0x0A, so a 12-byte line becomes 13 bytes; a UTF-8 BOM prepends three bytes; a text-mode FTP or mail transfer may rewrite line endings on the way. Each of those edits changes the input, and every digest avalanches: the SHA-256 of the CRLF copy keeps no visible prefix in common with the LF one. Repacking a folder into a ZIP or recompressing a JPEG changes bytes while the picture and the file list look identical. When two hashes disagree, compare byte counts first: equal size with different digests means content differs past the first block, while a one-byte difference usually is a line ending or a trailing newline.

Digest length identifies the algorithm

One hex character carries four bits, one byte of digest prints as two characters, so the length of the string names the algorithm: 32 characters is MD5 at 128 bits, 40 is SHA-1, 64 is SHA-256, 96 is SHA-384, 128 is SHA-512. That arithmetic is the fastest way to catch a mislabelled release page — a value advertised as SHA-256 but 40 characters long is SHA-1, and no 64-character value can be MD5. Checksum files add a second trap: sha256sum writes the digest, then a space or two plus *, then the file name, so copying the whole line drags in text that is not part of the digest. Case matters too when comparing strings, which is why this page has an uppercase switch.

Where the five algorithms come from

Web Crypto offers SHA-1, SHA-256, SHA-384 and SHA-512 through crypto.subtle.digest() but never MD5, so the MD5 path here is hand-written: append 0x80, zero-fill until eight bytes remain in the block, write the bit length as a 64-bit little-endian integer, then print the four state words low byte first. Those choices are why an MD5 digest has no structural resemblance to a SHA digest of the same file. The SHA paths use the browser primitive, which only exists in a secure context, so on plain HTTP those four checkboxes are disabled and MD5 alone keeps working. The file is read whole with file.arrayBuffer() before the first block is processed.

Worked example

The same sentence saved with LF and with CRLF

Input
Two files: hello world followed by 0x0A (12 bytes), and the identical text followed by 0x0D 0x0A (13 bytes).
Output
LF 12 B — MD5 6f5902ac237024bdd0c176cb93063dc4, SHA-256 a948904f2f0f479b8f8197694b30184b0d2ed1c1cd2a1ec0fb85d299a192a447. CRLF 13 B — MD5 a0f2a3c1dcd5b1cac71bf0c03f2ff1bd, SHA-256 572a95fee9c0f320030789e4883707affe12482fbb1ea04b3ea8267c87a890fb.

One extra byte (0x0D) rewrites 31 of the 32 MD5 characters and 62 of the 64 SHA-256 characters, so there is no prefix to eyeball; that is exactly why hashing detects edits. The empty file is the one input with a known digest: MD5 d41d8cd98f00b204e9800998ecf8427e and SHA-256 e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855.

Limits and pitfalls

  • The component sets no file-size cap, but it reads the entire file into memory with file.arrayBuffer() and holds every 32-bit MD5 word in an array, so a multi-gigabyte input can fail on memory instead of returning a digest.
  • SHA-1, SHA-256, SHA-384 and SHA-512 require crypto.subtle, available only in a secure context; served over plain HTTP the four boxes are disabled and only MD5 can be computed.
  • Ticking another algorithm or the uppercase switch after a file is listed does not re-hash it — rows that were never computed show — until the recalculate button is pressed on that card.
  • There is no expected-value field: the printed hex must be compared against the publisher string by hand, and the size label stops at megabytes, so a 4 GiB file reads as thousands of MB.

Related tools

When it goes wrong

A 2 GB image sits on "Calculating..." until the tab is killed, yet the same file finishes when only SHA-256 is ticked.

CauseMD5 is a hand-written JavaScript path, not a browser primitive. md5FromBuffer() first allocates a zero-filled copy of the whole file rounded up to a 64-byte boundary, then fills a plain number[] with one element per 4 input bytes — 8 bytes each in V8. For a 2 GB file that is 2 GB of original buffer plus 2 GB of padding plus roughly 4 GB of word array, about four times the file size in live memory before the first block is processed.

FixUntick MD5 and keep SHA-256: the SHA paths hand the same buffer to crypto.subtle.digest() without copying it, so peak memory stays near the file size. If an MD5 value is genuinely required, run md5sum <file> or certutil -hashfile <file> MD5 locally; nothing about that check needs a browser.

Dropping eight files at once makes the result cards appear one by one, and the last file seems to hang on "Calculating..." for a long time.

CauseThe drop handler is "push a card, await that file's digest, then push the next". File i+1 is not added to results until file i finishes, so a queued file never renders and no card shows a position in the queue. The algorithm selection is snapshotted once when the batch starts, so a checkbox change made mid-run applies to the next drop, not to files already inside the loop.

FixTreat it as a strictly serial queue: drop files in batches of a few, put the slowest one last, and keep the tab in the foreground. For real concurrency use sha256sum in a shell, where the OS does the reading and several processes can overlap.

With the uppercase switch on, the copied digest is rejected by the service that stores it, although it looks identical to the publisher value.

CauseThe switch only calls toUpperCase() on the hex string after the digest is complete; the underlying bytes and the lowercase spelling are unchanged, and clicking a row copies whatever case is on screen. Any field validating ^[a-f0-9]{64}$, any case-sensitive unique index, and any server that re-hashes the string it received treat A–F as a different value.

FixKeep the switch off when the digest goes into a database, a JSON payload or a signature, and turn it on only to compare against a printed label by eye. If an uppercase copy has already been sent, lowercase it before storing — the digest bytes are identical, only the spelling differs.

Four digests copied into a ticket are later impossible to map back to the four files they came from.

CauseA row click copies r.hashes[alg] and nothing else: no file name, no algorithm label, no separator. Four files hashed with the two default algorithms therefore leave eight bare hex strings, mixed across two lengths, with no field saying which is which.

FixCopy the name from the card header along with the digest, or generate labelled lines locally with sha256sum *, whose output is already digest-then-filename per line. Keep one algorithm per comparison column so 32- and 64-character strings never share a column.

The digest computed here does not match the one Windows printed for the same untouched file.

Causecertutil -hashfile prints the hex with a space between every byte pair and follows it with a "CertUtil: -hashfile command completed successfully." line, so copying the block drags in separators and prose that are not part of the digest. PowerShell adds a second trap: Get-FileHash defaults to SHA-256 and prints the hash in uppercase.

FixStrip the spaces, take only the hash line, and use the uppercase switch to align the spelling. Settle the algorithm before comparing: a 32-character certutil value will never equal the 64 characters from Get-FileHash, however the formatting is cleaned up.

One concrete scenario

Three release assets, one drop, and a 32-character string nobody needs

A release ships an installer of 251,658,240 bytes, a source archive of 62,914,560 bytes and a 1,184-byte checksums file, which the size label renders as 240.00 MB, 60.00 MB and 1.16 KB. Drop all three with the default ticks and each card prints MD5 plus SHA-256: six strings, 3 × (32 + 64) = 288 hex characters, of which only the three 64-character SHA-256 values belong in the release notes. Untick MD5 before dropping rather than picking the right line by length afterwards — one missing row is one fewer chance to paste a 32-character value into a SHA-256 field. If a mirror still publishes only MD5, keep it ticked for that mirror, but never let a matching MD5 stand in for the SHA-256 result.

Frequently Asked Questions

Why verify downloads with a hash instead of file size?
Equal size does not mean equal content. The publisher’s SHA-256 value confirms the file byte-for-byte — the standard defense against tampered installers (supply-chain attacks). Workflow: read the hash from the official page, compute locally, compare — same algorithm on both sides.
Will hashing a large file freeze the browser?
The computation runs locally in chunks via the Web Crypto API inside your tab, with no upload. Files of a few hundred MB take seconds; multi-GB files may hit memory limits — split them first. You can switch tabs; the result waits for you.
If two files share an MD5, are they identical?
In practice yes, but MD5 collisions are constructible. Prefer SHA-256 for verification; and when the source is untrusted, a matching MD5 is not reassurance — it can be a deliberately engineered collision.

Content reviewed: