SHA-256 vs MD5: Hashing for Checksums, Not Passwords
MD5 is broken for collision resistance; SHA-256 is not, and on our test machine it was faster. Where each fits, how to verify downloads, and why passwords need bcrypt.
On this page
Use SHA-256, not MD5, whenever a hash must resist deliberate tampering: file checksums you publish, signatures, integrity checks and anything security-related. MD5 is broken for collision resistance. RFC 6151 says it "is no longer acceptable where collision resistance is required". It is still acceptable only for non-security jobs such as spotting accidental file corruption or deduplicating cache keys. Neither algorithm is suitable for storing passwords. Both are designed to be fast, so attackers can try enormous numbers of guesses. Passwords need a deliberately slow password-hashing function such as bcrypt or Argon2, which is what WordPress uses.
This post explains what a hash function does and how MD5 and SHA-256 compare. It covers where each still belongs, how to verify a download with a checksum and why passwords are a separate problem. We measured both algorithms on the same machine, along with bcrypt, and checked how WordPress 7.1.3 stores passwords. One result surprises people: on our test hardware, SHA-256 was not slower than MD5 at all.
What a hash function does
A cryptographic hash function turns any input, a word or a 4 GB file, into a fixed-length fingerprint. The same input always gives the same output, and the smallest change produces a completely different one:
SHA-256("hello") = 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824
MD5("hello") = 5d41402abc4b2a76b9719d911017c592
A good hash function has three properties:
- Pre-image resistance: given a hash, you cannot find an input that produces it.
- Second pre-image resistance: given an input, you cannot find a different input with the same hash.
- Collision resistance: you cannot find any two different inputs with the same hash.
MD5 fails the third. Practical collision attacks have been published for years, which means an attacker can create two different files with the same MD5 hash. That breaks any system that trusts an MD5 hash to prove a file has not been swapped.
<h2
MD5 and SHA-256 compared
Table: MD5 versus SHA-256
| MD5 | SHA-256 | |
|---|---|---|
| Output size | 128 bits (32 hex characters) | 256 bits (64 hex characters) |
| Collision resistance | Broken | No practical attack known |
| Status | RFC 6151: not acceptable where collision resistance is required; must not be used for digital signatures | Widely used standard (SHA-2 family) |
| Speed on our test machine (64 MB, Python) | About 534 MB/s | About 1,267 MB/s |
| Available in browsers' Web Crypto API | No | Yes |
| Fine for | Non-security checks: accidental corruption, cache keys | Checksums, signatures, integrity, HMAC |
| Fine for passwords? | No | No |
The speed result reflects hardware. Many modern processors have instructions that accelerate SHA-256, so the old argument that "MD5 is faster" often no longer holds. Even where MD5 is faster, the difference rarely matters, and SHA-256's security does.
Before you choose
- Ask what an attacker could gain by making two inputs collide. If anything, use SHA-256.
- Check what the other side expects. If you are verifying a vendor's checksum, use the algorithm they publish; prefer vendors that publish SHA-256.
- Separate passwords from everything else. Password storage has its own rules (below).
- Need a secret key too? Use HMAC-SHA256, which combines a key with the hash, rather than hashing a secret and data together yourself.

Where each still belongs
Table: Choosing a hash by task
| Task | Use |
|---|---|
| Publishing a checksum for a download | SHA-256 |
| Verifying a file has not been tampered with | SHA-256 |
| Signing data, certificates or tokens | SHA-256 (or stronger) inside a signature or HMAC scheme |
| Spotting accidental corruption in a backup you control | MD5 is acceptable; SHA-256 is better and rarely slower |
| Cache keys, ETags, deduplication with no attacker involved | Either; many systems use MD5 for legacy reasons |
| Storing user passwords | Neither: bcrypt, Argon2 or scrypt |
Step by step: verify a download with SHA-256
- Download the file and copy the SHA-256 checksum the publisher lists on their website.
- Calculate the file's hash. On macOS or Linux, run
shasum -a 256 file.ziporsha256sum file.zip. On Windows, runcertutil -hashfile file.zip SHA256in Command Prompt. - Compare the two values character by character, or paste both into a text search. They must match exactly.
- If they differ, do not open the file. Download it again from the official source.
To hash a file or text without the command line, the SHA-256 hash generator works in your browser, supports files up to 200 MB and also offers SHA-384, SHA-512 and SHA-1 (marked legacy). It does not offer MD5, because browsers' built-in crypto does not provide it.
A checksum only helps if it comes from a trusted source. If an attacker can change both the download and the checksum on the same page, a matching hash proves nothing. Signed releases solve that problem.
Why neither is right for passwords
Fast hashes are good for checksums and bad for passwords. If a database of hashed passwords leaks, attackers try billions of guesses and compare hashes. The faster the hash, the faster they can guess. We measured on the same machine:
Table: Hashing speed for a short password (our test machine)
| Method | Speed or time |
|---|---|
| MD5 (Python, one core) | About 1.1 million hashes per second |
| SHA-256 (Python, one core) | About 1.1 million hashes per second |
bcrypt, cost 10 (PHP password_hash) |
About 72 ms per hash (roughly 14 per second) |
| bcrypt, cost 12 | About 272 ms per hash (roughly 4 per second) |
Those single-core figures understate attackers, who use graphics cards and run many guesses in parallel. The gap is the point: bcrypt is tens of thousands of times slower per guess, by design, and its cost can be raised as hardware improves. Password hashing functions also add a random salt to each password, so identical passwords produce different hashes.
What WordPress does
On our WordPress 7.1.3 test site, the administrator's stored password began with $wp$2y$, which marks bcrypt. WordPress core's source code shows that wp_hash_password() uses PHP's password_hash() with bcrypt by default, after pre-hashing the password with HMAC-SHA-384. Older sites may still have older-format hashes, which WordPress upgrades when users log in. If you write your own code, use wp_hash_password() and wp_check_password(), or PHP's password_hash() and password_verify(). Never call md5() or hash( 'sha256', ... ) on passwords.
WordPress's security keys and salts in wp-config.php are a different thing: secrets used to sign login cookies, not to hash passwords. Our guide to wp-config.php settings explains them, and the WordPress salt generator creates new ones.
Worked example: replacing MD5 in a plugin
An illustrative WordPress plugin offers a downloadable report and shows an MD5 hash so users can confirm the file. It also signs download links with md5( $secret . $file_id ).
- Checksums: switch to
hash_file( 'sha256', $path )and label the value "SHA-256". - Signed links: replace the home-made MD5 signature with
hash_hmac( 'sha256', $file_id . '|' . $expires, $secret ), include an expiry time, and compare withhash_equals()to avoid timing leaks. - Old links: accept both formats for a short transition period, then retire MD5.
- Test: confirm valid links work, tampered or expired links fail, and the published checksum matches the file.
Verify your use of hashes
- Search your code for
md5(andsha1(and note what each is used for. - Replace any security use with SHA-256 or HMAC-SHA256.
- Confirm passwords go through a password-hashing function only.
- Compare secret values with constant-time functions such as
hash_equals(). - Publish SHA-256 checksums on the same trusted page as your downloads, and prefer signed releases.
Common mistakes
- Storing passwords as MD5 or SHA-256 hashes, with or without a salt.
- Trusting MD5 checksums to detect deliberate tampering.
- Building "signatures" by hashing a secret plus data instead of using HMAC.
- Comparing hashes with
==instead of a constant-time comparison. - Assuming SHA-256 is too slow to use everywhere.
- Confusing hashing with encryption; hashes cannot be reversed to get the input back.
Troubleshooting
Table: Hash problems and fixes
| Symptom | Likely cause | Fix |
|---|---|---|
| Checksum does not match | Incomplete or altered download, or the wrong algorithm | Check you used SHA-256 if that is what was published; download again from the official source |
| Same text gives different hashes in two tools | Different encoding, trailing newline or whitespace | Hash the exact bytes; watch for line endings and UTF-8 |
| Hash generator offers no MD5 | Browser crypto APIs do not provide MD5 | Use SHA-256, or a command-line tool if you must check a legacy MD5 |
| Users cannot log in after a password migration | Old hashes compared with a new function | Use a check that accepts the old format and rehashes on login |
| Signed links can be forged | Home-made MD5 signature | Switch to HMAC-SHA256 with an expiry |
Frequently asked questions
Is MD5 still safe to use?
Not for anything security-related. RFC 6151 says it is not acceptable where collision resistance is required. It is acceptable for spotting accidental corruption or as a non-security cache key.
Is SHA-256 better than MD5?
Yes. It has a longer output and no known practical collision attack, and on modern hardware it is often no slower. In our test it was faster.
Can I use SHA-256 for passwords?
No. It is too fast, which helps attackers guess. Use bcrypt, Argon2 or scrypt, for example through PHP's password_hash().
How does WordPress store passwords?
Current WordPress uses bcrypt through password_hash(), with an HMAC-SHA-384 pre-hash. Stored hashes start with $wp$2y$, as we saw on our WordPress 7.1.3 test site.
Can a hash be reversed?
No. Hashing is one-way. Weak passwords can still be guessed by hashing candidates and comparing, which is why password storage needs slow hashes.
What is a checksum?
A hash of a file that you compare with a published value to confirm the file is complete and unchanged.
What is HMAC?
A way of combining a secret key with a hash function to sign data. HMAC-SHA256 is a common, safe choice for signed links and API requests.
Why is MD5 still used so widely?
Legacy compatibility. Many systems use it for non-security purposes, such as cache keys and ETags, where collisions do not create an attack.
What about SHA-1?
SHA-1 also has practical collision attacks and should not be used for new security purposes. Treat it as legacy, like MD5.
How long is a SHA-256 hash?
256 bits, shown as 64 hexadecimal characters. An MD5 hash is 128 bits, or 32 hex characters.
Next step
Hash a file you download regularly with the SHA-256 hash generator and compare it with the publisher's checksum. If you maintain custom code, search it for md5( and replace any security use. Strong passwords for your own accounts can come from the password generator. More developer explainers are in our developer guides.
Related free tools for this topic
SHA-256 Hash Generator
Generate SHA-256, SHA-512, SHA-384 and SHA-1 hashes of text or files to verify downloads and compare data. Everything…
Merge PDF Files Online (Free, No Uploads)
Combine multiple PDF documents into a single file directly in your browser. Reorder pages, keep your files private,…
Images to PDF Converter (JPG, PNG, WebP to PDF)
Turn screenshots, mockups, and loose images into one organized, properly sized PDF. Choose A4, US Letter, or fit…
Organise PDF: Reorder, Rotate & Extract Pages (Free)
Rearrange, rotate, delete or extract specific pages from any PDF document in your browser. Use visual page controls…
PDF to Images (JPG & PNG Converter)
Convert PDF pages into crisp PNG or JPEG images in your browser. Choose resolution scale (1× to 3×)…
SVG Optimiser for Web & Elementor (Clean viewBox & currentColor)
Shrink SVG icons, preserve the viewBox, remove fixed dimensions, and make vectors adapt to Elementor colours using currentColor.…
Related resources
SaaS hero with dashboard preview
Two-column hero: headline, supporting text, two buttons and a trust line beside a visual panel. Stacks to one…
Centred SaaS hero with product window
Centred hero with a large headline, supporting text and two buttons, with optional highlights and a product window…
Dark studio hero with service highlights
Centred hero with a large headline, supporting text and two buttons, with optional highlights and a product window…
Related articles
Unix Timestamps: Seconds, Milliseconds and Time Zones
What a Unix timestamp is, why seconds and milliseconds get mixed up, how to convert correctly in JavaScript, PHP, Python and WordPress,…
UUID v4 Explained: Uniqueness, Formats and Use Cases
The UUID v4 format, collision odds calculated, generation and validation tested in Node.js, Python and WordPress, and an SQLite test of random…
Minifying CSS: What It Saves and When Your Build Should Do It
We minified WordPress core stylesheets with five tools and compressed the results: what minification saves on top of gzip and Brotli, and…
Related guides
How Long Should a Meta Title Be? Pixels vs Characters Explained
"Keep it under 60 characters" is only half right. Google cuts titles by pixel width, not character count. Learn how to write…
The Default WordPress .htaccess File (and Safe Additions)
The exact .htaccess rules WordPress needs for pretty permalinks, what each line does, tested additions for HTTPS and file protection, and a…
Fluid Typography in Elementor with clamp()
Setting a heading to 56 px on desktop, 44 px on tablet and 32 px on mobile works, but text jumps between…
Comments