File Integrity & Hashing: Fingerprints, Checksums, and Tamper Detection
- Explain what a cryptographic hash is and why one changed bit flips the whole digest
- Compute a file's digest with sha256sum and read its output
- Choose SHA-256 over the broken MD5/SHA-1 for anything security-relevant
- Verify files against a published checksum and a SHA256SUMS manifest with sha256sum -c
A hash is a file's fingerprint
Build the mental model of a hash as a deterministic, one-way, fixed-size fingerprint.
You download an installer, copy a backup across the network, or hand a file to a teammate — and later you need to answer one question: is this the exact same file, byte for byte, that I expected? Comparing whole files is slow and usually impossible (you don't have the original handy). The practical answer is a hash.
A cryptographic hash function takes any input — one byte or ten gigabytes — and produces a fixed-size fingerprint called a digest (or checksum). Three properties make it useful:
- Deterministic — the same input always produces the same digest.
- Avalanche effect — change a single bit and the digest changes completely. There is no 'close'; it either matches or it doesn't.
- One-way — you can't work backwards from a digest to the original data.
So instead of shipping a whole file to prove it's unchanged, you ship its tiny digest. If two files share the same SHA-256 digest, they are — for all practical purposes — identical.
Check yourself
You change one byte in a 2 GB file and recompute its SHA-256. Roughly how much of the digest changes — a little, or a lot?
Computing a digest with sha256sum
Produce a file's digest and read the tool's output format.
The standard tools are named after their algorithms —
md5sum,sha1sum,sha256sum,sha512sum. Each prints the digest, two spaces, then the filename.Example — not runnable on your lab box
sha256sum report.pdf9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08 report.pdf
- report.pdf
- The file to fingerprint. Pass several files to get one line each.
The 64-hex-character digest is the fingerprint of report.pdf. Run it again on the same file and you get the exact same string — that repeatability is what lets you compare against a value someone published earlier. Example — not runnable on your lab box
sha256sum *.iso44e2... debian-12.iso 7b1a... ubuntu-24.iso
Hand it a glob and it prints one 'digest␠␠filename' line per file. That two-column shape is exactly the format of a checksum manifest — which is where this goes next. To grab just the digest (for scripting or to store in a variable), keep the first field:
sha256sum report.pdf | awk '{print $1}'.Pick the right algorithm: SHA-256, not MD5
Choose a secure hash and understand why MD5/SHA-1 no longer prove authenticity.
The algorithms differ in digest size and, crucially, in security:
- MD5 and SHA-1 are broken. Attackers can craft two different files with the same MD5 (or SHA-1) digest — a 'collision'. A matching MD5 therefore no longer proves a file is authentic. You'll still see MD5 used as a cheap non-adversarial change detector, but never trust it against a motivated attacker.
- SHA-256 (and SHA-512) are the current standard for integrity and authenticity. When a project publishes checksums for its releases, they're almost always SHA-256.
Rule of thumb: reach for `sha256sum` unless something explicitly requires otherwise.
Check yourself
A release page offers both an MD5 and a SHA-256 for the same file. Which do you use to be confident the file wasn't tampered with?
Verify against a published checksum and a manifest
Confirm a single download, then verify many files at once with sha256sum -c.
The most common real task: you downloaded a file and the project lists its SHA-256. Recompute locally and compare — if even one character differs, the file is not what the project released (corrupted, truncated, or tampered), so don't run it.
Example — not runnable on your lab box
sha256sum ubuntu-24.iso9b1c...e4 ubuntu-24.iso
Compare this digest against the one the project published. Equal means the file is intact (it matches that digest); any difference means stop and re-download. Whether it's also authentic depends on trusting where the digest came from — the next step covers that distinction. Doing that by eye across dozens of files is error-prone. Instead, save the digests to a manifest (conventionally
SHA256SUMS) and let the tool do the comparison.Example — not runnable on your lab box
sha256sum *.conf > SHA256SUMSWrites one 'digest␠␠filename' line per file into SHA256SUMS — a baseline snapshot you can re-verify later. (Manifest specific files, e.g. *.conf, so the manifest doesn't try to include itself.) Example — not runnable on your lab box
sha256sum -c SHA256SUMSapp.conf: OK db.conf: OK web.conf: FAILED sha256sum: WARNING: 1 computed checksum did NOT match
- -c
- Check mode: read the manifest and verify each file's current digest against it.
-c (check) recomputes each listed file and reports OK or FAILED, naming exactly which file drifted. That FAILED line is your tamper/corruption alarm; a missing file is reported too, so a manifest also catches deletions. Check yourself
You run
sha256sum -c SHA256SUMSand one line ends in FAILED. What does that tell you about that file?Integrity is not authenticity: checksums vs signatures
See the limit of a bare checksum and why real authenticity needs a signature.
Here's the subtlety that trips people up, and it's worth getting right. A checksum answers *"does this file match this digest?" — that's integrity. It reliably catches accidental corruption, and it catches tampering if you trust where the digest came from*.
But think about the attacker. If someone can replace the file on a download server, they can usually replace the checksum on the same page too — and make the two match. Your
sha256sum -cwould happily printOK, because the file really does match the (attacker-supplied) digest. So a checksum sitting next to the download proves integrity, not authenticity — it proves the bytes match a digest, not that the digest is genuinely the project's.Closing that gap needs a cryptographic signature. Projects sign their
SHA256SUMSfile with their private key; you verify it with their public key usinggpg --verify. That gives a chain of trust:- you trust the project's public key (obtained once, out-of-band), →
- the signature proves the
SHA256SUMSmanifest is genuinely theirs and unaltered, → - the manifest (via
sha256sum -c) proves each file matches.
A valid signature is what turns "these bytes match a number on a web page" into "these bytes are really what the project published."
The transcript below is the verification half. The GnuPG Essentials lesson (
gpg-essentials) picks up from here: you make a key, sign aSHA256SUMSof your own, verify it, and learn to read the four different verdicts gpg can give.Example — not runnable on your lab box
gpg --verify SHA256SUMS.gpg SHA256SUMSgpg: Signature made Tue 22 Jul 2026 10:14:02 UTC gpg: using RSA key 843938DF228D22F7B3742BC0D94AA3F0EFE21092 gpg: Good signature from "Ubuntu CD Image Automatic Signing Key"
Verify that the SHA256SUMS manifest was signed by the project's key. 'Good signature' means the manifest is authentic and unmodified — so the digests inside it can be trusted, and only THEN does sha256sum -c against it prove the files are genuine. Without this step, you're trusting whoever served the checksum. Check yourself
A download page lists a SHA-256 right next to the file, with no signature. Matching it proves the file is — intact, or authentic?
Try it in your live terminal
Run these safe commands on the real sandbox to see hashing and verification end to end.
You have a real shell. These commands create a throwaway file, fingerprint it, baseline a manifest, and prove verification catches a change — nothing here touches the rest of the system.
echo hello > /tmp/f.txt && sha256sum /tmp/f.txtCreates a file and prints its SHA-256. Note the digest, then run the same command again — it's identical, because the input is identical. Example — not runnable on your lab box
cd /tmp && sha256sum f.txt > SUMS && sha256sum -c SUMSBaselines f.txt into a manifest, then verifies it — you should see 'f.txt: OK'. Example — not runnable on your lab box
echo tampered >> /tmp/f.txt && sha256sum -c /tmp/SUMSAppends a line, then re-checks against the old manifest. Now it reports 'f.txt: FAILED' — you've just watched a tamper detector fire.
- A hash is a deterministic, one-way, fixed-size fingerprint; any change flips the whole digest (the avalanche effect).
- Compute with sha256sum <file>; prefer SHA-256 over the broken MD5/SHA-1 for anything security-relevant.
- Compare a recomputed digest to a published one to prove a download is intact (integrity); it's only authentic if you trust where the digest came from.
- Integrity ≠ authenticity: a checksum next to a download proves the bytes match a number; a GPG signature (gpg --verify) proves the number is really the project's. Security-relevant downloads want both.
- Build a SHA256SUMS manifest with sha256sum, and verify a whole set later with sha256sum -c — it names the exact files that FAILED or went missing.
| Command | Does | Watch for |
|---|---|---|
sha256sum <file> | Print a file's SHA-256 digest | The current, secure default |
md5sum / sha1sum | Older/faster digests | Broken for security — corruption check only |
sha256sum * > SHA256SUMS | Baseline files into a manifest | Manifest *.ext so it doesn't hash itself |
sha256sum -c SHA256SUMS | Verify files against a manifest | FAILED = changed; also flags missing files |
gpg --verify SHA256SUMS.gpg SHA256SUMS | Prove the manifest is the project's | Integrity vs authenticity — this adds authenticity |
... | awk '{print $1}' | Keep just the digest | Strips the two-space + filename |
