Every time you download a Linux ISO, install a package from npm, or pull a Docker image, you are trusting that the bytes you receive are exactly the bytes the publisher sent. That trust is enforced by checksums and hashes — compact fingerprints that uniquely identify a file. This article explains how they work, where they fail, and how to verify them correctly.

Checksums, Hashes, MACs: Pick the Right Tool

Three related concepts get conflated. They are not interchangeable.

  • Checksum is the loose term: any short value computed over a file. A simple byte-sum checksum (like the one in TCP) catches transmission errors but not malicious tampering.
  • Cryptographic hash (MD5, SHA-256) is a one-way fingerprint with strong collision resistance. Anyone with the file can compute the hash; given only the hash, you cannot recover the file.
  • Message Authentication Code (MAC) is a hash that requires a shared secret key. Both the sender and receiver know the key; an attacker who modifies the file cannot produce a valid MAC without it.

A plain hash proves that a file has not been corrupted (assuming the hash itself is authentic). It does not prove the file has not been tampered with, because an attacker who replaces both the file and the published hash can convince you that the bogus file is legitimate. To prove authenticity, you need either a MAC (with a shared secret) or a digital signature (with a public key).

How Checksums Work in Practice

Consider the workflow of downloading Ubuntu. The Ubuntu project publishes a SHA-256 checksum alongside every ISO on its download page. The recommended verification flow is:

  1. Download the ISO and the SHA256SUMS file from the Ubuntu site (over HTTPS).
  2. Compute the SHA-256 of the downloaded ISO locally.
  3. Compare it against the value in SHA256SUMS.

The HTTPS connection protects the integrity of the download page. The SHA-256 then protects the integrity of the actual file. If a single bit of the ISO was corrupted in transit — disk error, network glitch, mirror cache issue — the computed hash will differ from the published one, and you know not to trust the file.

This workflow catches accidental corruption well. It does not protect against a malicious mirror — an attacker who controls the mirror could also replace the SHA256SUMS file with a consistent lie. Against that threat, you need to verify the signature on the SHA256SUMS file itself (Ubuntu uses GPG signatures for this).

Subresource Integrity: Hashes for the Web

Modern web applications often load JavaScript from CDNs. If the CDN is compromised, the attacker can inject malicious code into every site that loads the script. The Subresource Integrity (SRI) standard prevents this by letting you pin the script to a specific hash:

<script src="https://cdn.example.com/lib.js"
        integrity="sha384-abc123..."
        crossorigin="anonymous"></script>

The browser fetches the script, computes its SHA-384 hash, and only executes it if the hash matches the value in the integrity attribute. If a CDN compromise substitutes the script, the hash will differ and the browser will refuse to run it. SRI is enabled by default on major CDNs and is one of the most underused security features on the open web.

HMAC: Hashing with a Secret Key

HMAC (Hash-based Message Authentication Code) combines a cryptographic hash with a secret key to produce a value that only the key holder can generate. The construction is standardized in RFC 2104:

HMAC(K, M) = H((K' xor opad) || H((K' xor ipad) || M))

Where K' is the key padded to the hash block size, opad and ipad are fixed constants, and H is the hash function (typically SHA-256). The double-hashing structure provides a security proof that holds even if the underlying hash has weaknesses in its internal compression function.

HMAC is used in:

  • JWT (JSON Web Tokens): the signature portion of a JWT is an HMAC of the header and payload.
  • API request signing: AWS Signature v4, GitHub webhooks, Stripe webhooks all use HMAC to verify that a request came from the claimed sender.
  • Cookie integrity: signing cookies with HMAC prevents attackers from forging session tokens.
  • File integrity in transit: syncing tools like rsync and many backup systems use HMAC to verify chunks as they are transmitted.

Digital Signatures: Hashes with Public Keys

When the publisher and verifier do not share a secret (as is the case for Ubuntu downloads), the answer is a digital signature. The flow:

  1. Publisher computes the SHA-256 of the file.
  2. Publisher signs the hash with their private key (using RSA, ECDSA, or Ed25519).
  3. Publisher attaches the signature alongside the file.
  4. Verifier downloads the file and the signature.
  5. Verifier checks the signature against the publisher’s public key (which they obtained through a trusted channel, like the publisher’s HTTPS website).

A digital signature proves two things: the file came from the holder of the private key, and the file has not been modified since signing. The signature is a few hundred bytes regardless of the file size, because it is over the hash, not the file contents.

This is the model used by GPG-signed software releases, by HTTPS certificates (signed by a CA), and by code-signing on every major platform.

Verifying a Download: A Practical Example

Suppose you want to download a Node.js LTS release. The download page offers three files: the binary, a SHA256SUMS text file, and a SHA256SUMS.sig GPG signature. The recommended flow is:

# 1. Download all three files over HTTPS.
# 2. Verify the SHA256SUMS file with GPG:
gpg --verify SHA256SUMS.sig SHA256SUMS

# 3. Compute the SHA-256 of the binary:
sha256sum node-v22-linux-x64.tar.xz

# 4. Compare against the value in SHA256SUMS:
grep node-v22-linux-x64.tar.xz SHA256SUMS

Step 2 proves that the SHA256SUMS file was signed by the Node.js release key. Step 3 proves the integrity of the binary. Step 4 ties them together. Skipping step 2 means you trust the mirror to give you a consistent checksum file; for a high-value download, that trust is not warranted.

What Hashes Cannot Do

A hash is a fingerprint, not a witness. Three things hashes do not provide:

  • Authenticity by themselves: an attacker who can replace both the file and the hash can fool any check. Authentication requires a separate channel (HTTPS, GPG signature, MAC with a shared key).
  • Confidentiality: the hash reveals nothing about the file contents, but it also does not protect them. Anyone with the file can compute the hash. For confidentiality, encryption is required.
  • Non-repudiation in a symmetric scheme: if two parties share a MAC key, the receiver cannot prove to a third party which party produced the message. Digital signatures (asymmetric) do provide non-repudiation.

Choosing the Right Algorithm for Integrity Checks

For practical file integrity in 2026:

  • Casual verification (downloading a binary, syncing files): SHA-256. Fast, ubiquitous, supported by every OS.
  • Public software distribution (signing a release): SHA-256 plus Ed25519 or ECDSA signature. Modern algorithms with short signatures and strong security.
  • API authentication (verifying webhook origins): HMAC-SHA256. The shared secret model fits the trust model.
  • Long-term archival (digital signatures that must remain valid for 20+ years): SHA-384 or SHA-512 with a conservative signature algorithm. Migration to SHA-3 is also worth considering.

Common Mistakes

Real-world download verification suffers from a few recurring problems:

  • Skipping the verification step. Most users do not verify checksums. That is the primary attack surface for supply-chain attacks on open-source software.
  • Trusting the hash on the same page as the download. If the page is compromised, the hash is also compromised. The hash must be obtained through a different channel (the publisher’s signed release announcement, a separate trusted mirror) for the verification to mean anything.
  • Using MD5 for signed software. MD5 collisions are easy to produce. Software signed with MD5 should be treated as unsigned.
  • Not enforcing SRI on third-party scripts. Every <script src> on a site handling user data should carry an integrity attribute. It is a four-line change with a major security impact.

The Bottom Line

Hashes are the foundation of file integrity. Use SHA-256 for casual verification, HMAC-SHA256 when both parties share a secret, and SHA-256 plus a digital signature for public distribution. Verify the verification itself: hashes on the same page as the download are only as trustworthy as the page. For high-stakes downloads, always run the local hash and compare against a value obtained through a second channel.

Further Reading

  • RFC 2104 — HMAC: Keyed-Hashing for Message Authentication.
  • W3C Subresource Integrity specification — the browser-side mechanism for hashing CDN scripts.
  • Ubuntu SHA256SUMS verification guide — a worked example of the full GPG + SHA-256 flow.
  • Have I Been Pwned — the canonical service for checking whether a credential appears in a public breach.

Frequently Asked Questions

Is SHA-256 enough for file integrity? Yes. No practical collision has been produced against SHA-256, and the algorithm is supported by every operating system. For most use cases, SHA-256 is the right choice.

Should I still use MD5 for legacy checksums? Yes, when verifying against a published MD5 sum (for example, an old Linux distro that did not move to SHA-256). MD5 still detects accidental corruption. Just do not use MD5 for new security applications.

What is the difference between a checksum and a hash? A checksum is a loose term for any short value computed over a file. A cryptographic hash is a checksum with strong collision resistance and one-way properties. The CRC32 used in ZIP files is a checksum but not a hash; SHA-256 is both.

Can I use hashes to detect malware? Not by themselves. Hashes only detect changes; they cannot identify malicious content. Use antivirus engines (which use pattern matching, behavior analysis, and machine learning) for malware detection. Hashes are useful for whitelisting — only allow files whose hashes match a known-good list — but not for blacklisting.