Independent software, built & maintained by PRBLEM.
28 releases 21 free · 7 professional STORE / 2.41.0
PRBLEMindependent software
Home Field Notes Release Engineering
Release Engineering FIELD NOTE

SHA-256 Isn’t Just for Security: How to Verify the File You Actually Shipped

A checksum is a small piece of release infrastructure that can answer one very important question with byte-level precision.

PRBLEM — XenForo add-ons, WordPress plugins and software tools FIELD NOTE // 9002

A ZIP file has a name, a version number and a download URL. None of
those prove what bytes are inside it.

A checksum does.

More precisely, a cryptographic hash such as SHA-256 gives you a
compact fingerprint of a file. If one byte changes, the resulting digest
is expected to change dramatically.

That makes SHA-256 useful far beyond security headlines. It is useful
for release engineering, support, deployment verification, cache
debugging and ordinary operational confidence.

What SHA-256 does

Given an input file, SHA-256 produces a 256-bit digest, normally
displayed as 64 hexadecimal characters.

For example:

27c20067624586e8c816690f92bfcf3dd1f85ea6ab0f28329237a16483be0da1

The important property for release work is determinism:

  • same bytes -> same digest;
  • different bytes -> overwhelmingly likely to produce a different
    digest.

On Linux:

sha256sum prblem-cron-status-v1.0.1.zip

On Windows PowerShell:

Get-FileHash .\prblem-cron-status-v1.0.1.zip -Algorithm SHA256

In PHP:

$hash = hash_file('sha256', '/path/to/package.zip');

That is enough to build several useful release checks.

Hashing is not encryption

A checksum does not hide the file.

SHA-256 is a one-way hash function, not encryption. There is no
decryption key. You are not supposed to recover the original ZIP from
its digest.

It is also not a password storage tutorial. Password hashing has
different requirements, including salts and intentionally expensive
password-hashing functions.

For release artifacts, the job is simpler: fingerprint a file so two
parties can compare whether they have the same bytes.

Hashing is not a digital
signature

This distinction matters.

Suppose an attacker can replace both:

  • plugin.zip; and
  • the SHA-256 string displayed next to it.

The checksum will still match the malicious file.

A checksum proves integrity relative to the checksum you trust. It
does not by itself prove publisher identity.

A digital signature adds that identity/authenticity layer by signing
data with a private key that an attacker should not possess.

In simplified terms:

Checksum:
"Is this the same file?"

Signature:
"Was this data signed by the holder of this key?"

Both can be useful. They solve different problems.

Why checksums are
valuable for normal support

Imagine a customer reports that version 1.0.1 crashes, but the same
release works everywhere else.

Without artifact verification, you now have several
possibilities:

  • corrupted download;
  • stale CDN object;
  • browser/proxy cache issue;
  • manually modified ZIP;
  • wrong file uploaded under the correct filename;
  • partial deployment;
  • actual software bug.

A checksum removes several branches from that diagnostic tree.

Ask the user to calculate the SHA-256 digest of the package. Compare
it with the digest of the artifact you intended to ship.

If they match, you know you are investigating the same bytes.

That sounds basic, but eliminating ambiguity early makes support much
faster.

The common
release mistake: hashing the wrong copy

A surprisingly easy mistake is to calculate a checksum during the
build and then modify, re-compress or replace the file later.

For example:

build/package.zip
      |
      | SHA-256 generated here
      v
upload/package.zip
      |
      | CDN processing / manual replacement
      v
customer download

If the website displays the hash from the build machine while serving
a different file, the verification system is stale by design.

The strongest checksum source is the artifact actually being
served.

If your download lives on the same server, you can calculate the hash
from that local file path:

$real = realpath($file);
if ($real && is_readable($real)) {
    $sha256 = hash_file('sha256', $real);
}

Do not blindly convert arbitrary URLs into filesystem paths. Validate
that the path is inside the directory you expect and that it points to
an allowed file type.

Avoid
downloading your own file just to hash it

If the ZIP is already on the same server, making an HTTP request back
to your own site is unnecessary.

Local hashing is usually better:

  • fewer moving parts;
  • no HTTP timeout;
  • no DNS dependency;
  • no CDN ambiguity;
  • no bandwidth waste;
  • hashes the stored artifact directly.

For a public download directory such as:

/free-tools/xenforo/plugin.zip

a safe implementation can map only same-origin download URLs to files
under an allowed local root, then call hash_file().

If the mapping fails, fall back to a stored checksum rather than
fetching arbitrary remote content.

Checksum automation needs
boundaries

Automatic verification sounds harmless, but URL-to-path logic
deserves the same care as any filesystem feature.

At minimum:

  1. Require the same host as the site.
  2. Require an expected extension such as .zip.
  3. Resolve the real filesystem path.
  4. Confirm the resolved path stays under the allowed web root or
    download root.
  5. Require a regular readable file.
  6. Never concatenate unsanitized ../ path segments and
    trust the result.

The security goal is simple: a product record should never be able to
trick the application into hashing /etc/passwd, private
keys or unrelated files.

Checksums help deployments
too

The same concept applies after upload.

Suppose a release contains 200 files. Your deployment system can
record a manifest:

{
  "src/Service.php": "...sha256...",
  "src/Controller.php": "...sha256...",
  "assets/app.js": "...sha256..."
}

Later, an integrity check can compare expected and current
hashes.

This is useful for detecting:

  • accidental edits;
  • incomplete uploads;
  • files replaced by an older release;
  • unexpected post-deployment mutation.

But remember the interpretation:

Different means different. It does not automatically mean
compromised.

A human still needs context.

ZIP reproducibility
is a separate challenge

Two ZIP archives can contain identical logical files and still have
different hashes.

Why?

ZIP metadata can include timestamps, file ordering, permissions or
compression differences. Rebuilding the package on another machine may
change those bytes.

If reproducible release artifacts matter, the build process must
normalize those variables.

This is why a checksum is best understood as a fingerprint of one
exact artifact, not an abstract fingerprint of “version 1.0.1 as a
concept.”

A practical release pattern

A small software publisher can get substantial value from a simple
process:

  1. Build the final ZIP.
  2. Do not modify it after finalization.
  3. Upload it to the exact public download location.
  4. Calculate SHA-256 from the uploaded local file where possible.
  5. Display the digest on the product page.
  6. Include the same digest in the release log.
  7. Keep previous release checksums with the changelog.

For paid software delivered through another platform, calculate and
retain the final artifact checksum even if the checkout provider handles
delivery.

What users should do
with the checksum

A checksum is only valuable if comparison is easy.

Provide a copy button and short instructions:

Linux/macOS:

shasum -a 256 downloaded-file.zip

or on systems with GNU coreutils:

sha256sum downloaded-file.zip

Windows:

Get-FileHash .\downloaded-file.zip -Algorithm SHA256

Compare the entire 64-character value, not the first few
characters.

The bigger lesson

Good release engineering often consists of small mechanisms that
remove uncertainty.

A SHA-256 digest does not make a release secure by itself. It does
not replace signatures, access control, backups or a disciplined build
process.

What it does is answer one narrow question extremely well:

Are these exact bytes the same bytes I expected?

For downloads, deployments and support, that is a very useful
question to be able to answer automatically.