Skip to content

Create MD5 and SHA256 File Hashes on Windows, macOS, and Linux

A suspicious attachment, a memory dump, a .eml you just converted from a .msg export — before you do anything with a piece of evidence, you hash it. The hash pins the file's exact content to a moment in time: any later change, accidental or malicious, changes the hash. That gives you three things:

  • Integrity proof. Re-hash before analysis or handoff; if the value still matches the one recorded at acquisition, the evidence is untouched. This is the technical backbone of a chain of custody.
  • A universal identifier. Hashes are how the whole industry names samples — search a SHA256 on VirusTotal or in a threat-intel platform and you find every prior sighting without uploading anything.
  • Deduplication. Two files with the same hash have the same content, regardless of filename.

Hashing is trivially easy — which is exactly why it gets done sloppily. This article is the deliberately foolproof version for all three platforms.

Why Record Both MD5 and SHA256

SHA256 is your integrity proof. MD5 has been broken for collisions for years — someone can construct two different files with the same MD5 — so an MD5 alone must never be your only evidence that a file is unchanged.

MD5 is still a useful identifier. Threat-intel feeds, sandbox reports, and older IOC lists reference samples by MD5 everywhere. Recording it at acquisition costs nothing and saves you from re-hashing later when a report only gives you an MD5 to pivot on.

So the habit is: record both, trust SHA256.


Windows: Get-FileHash (PowerShell)

Get-FileHash is the built-in cmdlet (official reference). Its default algorithm is SHA256, so the plain call already does the right thing:

Get-FileHash C:\evidence\sample.zip
Algorithm       Hash                                                              Path
---------       ----                                                              ----
SHA256          3CBCFDDEC145E3382D592266BE193E5BE53443138EE6AB6CA09FF20DF609E268  C:\evidence\sample.zip

For the MD5, pass -Algorithm (accepted values: SHA1, SHA256, SHA384, SHA512, MD5):

Get-FileHash C:\evidence\sample.zip -Algorithm MD5

To compare against a known value — for example when re-verifying before handoff — let PowerShell do the comparison instead of eyeballing 64 characters. -eq on strings is case-insensitive, so the uppercase output matches a lowercase reference fine:

(Get-FileHash C:\evidence\sample.zip).Hash -eq '3cbcfddec145e3382d592266be193e5be53443138ee6ab6ca09ff20df609e268'
True

Anything other than True means the file is not the file you recorded.

Windows Fallback: certutil (cmd.exe)

On a system where PowerShell is restricted, certutil ships with every Windows and hashes files too (official reference), with the syntax certutil -hashfile InFile [HashAlgorithm]. Always name the algorithm explicitly rather than relying on a default:

certutil -hashfile C:\evidence\sample.zip SHA256
certutil -hashfile C:\evidence\sample.zip MD5

certutil prints the hash in lowercase and has no built-in compare — you copy the value into your notes and compare manually or in PowerShell later.

macOS: shasum and md5

macOS ships shasum (algorithm selected with -a) and a BSD-style md5 tool — note the differences from Linux before you script anything:

shasum -a 256 ~/evidence/sample.zip
md5 ~/evidence/sample.zip
8790bea2d44ca10c6667124c29021ef77f724a9d029fb69f052c715f46d425d7  /Users/analyst/evidence/sample.zip
MD5 (/Users/analyst/evidence/sample.zip) = aedc12a3e2db1d8375271235db2660cf

The BSD md5 output format (MD5 (file) = hash) breaks tools that expect Linux md5sum lines. md5 -r prints the Linux-style hash filename order instead. Current macOS versions additionally include md5sum and sha256sum themselves, so Linux-style commands work there too — but shasum and md5 are the ones you can rely on finding on any Mac.

To verify later, write the checksum line to a file at acquisition time and let shasum -c do the comparison:

shasum -a 256 ~/evidence/sample.zip > ~/hashes/sample.zip.sha256
shasum -a 256 -c ~/hashes/sample.zip.sha256
/Users/analyst/evidence/sample.zip: OK

Linux: sha256sum and md5sum

GNU coreutils provide one tool per algorithm:

sha256sum /evidence/sample.zip
md5sum /evidence/sample.zip

Output is hash, two spaces, filename — one line per file, which is exactly the format the -c verification mode reads back. The standard workflow:

sha256sum /evidence/sample.zip > /hashes/sample.zip.sha256
sha256sum -c /hashes/sample.zip.sha256
/evidence/sample.zip: OK

A modified file prints FAILED instead of OK and the command exits non-zero, so the check also works unattended in scripts (--quiet suppresses the OK lines, --status suppresses all output and leaves only the exit code). The same flags apply to md5sum -c.


The Habits That Make Hashes Worth Anything

A hash only proves integrity relative to the moment it was taken, so the process matters as much as the command:

  1. Hash immediately at acquisition — before opening, unzipping, converting, or scanning the file. Every tool that touches evidence is a chance to modify it; the hash must capture the state before all of that.
  2. Store hashes separately from the evidence — in your case notes or ticket, not as a text file sitting in the same folder. If an attacker (or a sync client) can alter the evidence, it must not be able to alter the recorded hash alongside it.
  3. Re-verify at every boundary — before you start analysis, and again before handing evidence to another analyst, team, or law enforcement. "Matches the acquisition hash" is a one-line note that settles integrity questions months later.
  4. Copy-paste, never retype. A transcribed hash with one wrong character is worse than no hash. Case differences are harmless (hex is case-insensitive — PowerShell prints uppercase, Unix tools lowercase), but use a tool comparison rather than reading two long strings by eye.

MD5 alone proves nothing

MD5 collisions are practical: distinct files with identical MD5 values can be crafted deliberately. Record MD5 as a lookup key for threat intel, but any integrity or chain-of-custody claim must rest on the SHA256.