All articles
169 articles · updated weekly See our Tools
All articles
Tips

Hashing for Those Who Never Read the RFC: MD5, SHA-1, SHA-256

Each algorithm, its historical flaws, and when it still makes sense to use — without the heavy math.

Hashing for Those Who Never Read the RFC: MD5, SHA-1, SHA-256
COVER · Tips

I was reviewing a legacy API codebase and found passwords being stored with MD5. In 2024. The original dev probably thought it was "encrypted" — and here's the problem: MD5 doesn't encrypt anything, and even for hashing non-sensitive data, the choice of algorithm matters much more than most people imagine.

This post is what you need to know about the three most common algorithms, without going into finite group theory.

What hashing really is

A hash function is a one-way function: given an input, it always produces the same fixed-size output. You can't reverse the output to get back to the original input — at least not directly.

What differentiates one hash algorithm from another is basically: speed, output size, and collision resistance (two different inputs generating the same output).

MD5

Output: 128 bits (32 hex chars).

Created in 1992. Broken by collision in 2004. In 2008, researchers generated a fake CA certificate exploiting MD5 collisions. In 2012, the Flame malware used the same technique.

Never use MD5 for:

  • Password hashing (it's too fast — makes brute-force easy)
  • Security integrity verification (collisions are computationally feasible)
  • Digital signatures

Still makes sense for:

  • File checksums in contexts where speed matters and security isn't critical
  • Content deduplication IDs (checking if a file already exists in cache)
  • Non-cryptographic fingerprinting
echo -n "hello" | md5sum
# 5d41402abc4b2a76b9719d911017c592

SHA-1

Output: 160 bits (40 hex chars).

Developed by the NSA, published in 1995. Practical collision demonstrated by Google in 2017 (the SHAttered attack). Browsers stopped accepting TLS certificates with SHA-1 in 2017.

Never use SHA-1 for:

  • TLS/SSL certificates
  • Code signing
  • Any modern security context

Still appears in:

  • Git (uses SHA-1 to identify commits — migrating to SHA-256)
  • Some legacy systems for non-critical integrity verification

Git uses SHA-1 as an identifier, not as a security guarantee. Collision resistance matters less when the adversary doesn't control the content of commits.

SHA-256

Output: 256 bits (64 hex chars). Part of the SHA-2 family.

Published in 2001. No known collision. Widely used in TLS, HTTPS, Bitcoin, JWT (HS256 algorithm), and software integrity verification.

Use SHA-256 for:

  • Critical file integrity verification
  • HMACs (message signatures with a secret key)
  • Security checksums in general

Don't use SHA-256 for:

  • Password hashing — it's still too fast. Use bcrypt, scrypt, or Argon2 for passwords
const hash = await crypto.subtle.digest(
  'SHA-256',
  new TextEncoder().encode('hello')
);
// ArrayBuffer → hex string
const hex = [...new Uint8Array(hash)].map(b => b.toString(16).padStart(2, '0')).join('');

For passwords: none of the three

MD5, SHA-1, and SHA-256 are algorithms that are fast by design. For passwords, you want the opposite: a deliberately slow algorithm that makes brute-force computationally expensive.

Use bcrypt (cost factor >= 12), scrypt (N >= 16384), or Argon2id (the most modern). These algorithms are tunable — you increase the computational cost as hardware gets cheaper.

Testing in practice

To generate and compare hashes of any text with MD5, SHA-1, SHA-256, and others, the Hash Generator processes everything in the browser — without sending anything to a server.

How to choose the right hash

The most important question isn't which algorithm is most famous, but which problem you want to solve. For file integrity, SHA-256 is usually a safe and widely supported choice. For fast checksums without a security objective, algorithms like CRC may be sufficient. For passwords, generic hashing isn't enough: use algorithms with configurable cost, like Argon2, bcrypt, or scrypt.

Never use MD5 or SHA-1 for security. They still appear in legacy systems and can serve to identify duplicates without critical risk, but they should not protect authentication, signing, or integrity against an active attacker.

Checklist before publishing

Confirm whether the hash needs a salt, whether it needs to be reproducible in another system, and whether the output format should be hex or Base64. Also document the input encoding. The string action may generate different results if one system uses UTF-8 and another handles bytes differently.

Use the Hash Generator to compare algorithms, test known inputs, and record examples in the README or API documentation. Real examples prevent regressions when another language or library enters the flow.

HT
Author
Hugo Tanaka
Second-generation Japanese-Brazilian who grew up watching his father debug logistics spreadsheets in BASIC. Full-stack developer focused on tooling and DX — the role that finally brought code, writing and an obsession with productivity into one place. Writes for people who already know how to code and need to solve a problem now.
View profile