DEV Community

toolzip
toolzip

Posted on

Hash Functions Explained — MD5 vs SHA-256 vs SHA-512 (With Code)

Hash functions are everywhere in software — password storage, file integrity checks, digital signatures, blockchain, caching, data deduplication. Understanding them well means knowing not just what they do, but why different algorithms exist and when to use each one.

What Is a Hash Function?

A cryptographic hash function takes an input of any size and produces a fixed-size output. The same input always produces the same output. Different inputs should produce different outputs (though this isn't guaranteed — see collision resistance below).

"hello" → SHA-256 → 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824
"Hello" → SHA-256 → 185f8db32921bd46d35cc2a9f69cd2f13da77b9e76e6b8a7c15d01e9e0e29c38
Enter fullscreen mode Exit fullscreen mode

Notice that changing just one character (h to H) completely changes the output. This is called the avalanche effect — small input changes produce dramatically different outputs.

Core Properties

Deterministic: Same input → same output, always. No randomness.

One-way (preimage resistance): Given a hash, you can't reconstruct the input. The function is designed to be computationally irreversible.

Collision resistant: It should be computationally infeasible to find two different inputs that produce the same hash.

Avalanche effect: Small input changes produce completely different outputs. No part of the output correlates predictably with any part of the input.

Fixed output size: Regardless of whether the input is 1 byte or 1 gigabyte, the output is always the same length for a given algorithm.

The Major Algorithms

MD5 (1991)

Output: 128 bits (32 hex characters)
Status: Cryptographically broken

// Node.js
const crypto = require('crypto');
const hash = crypto.createHash('md5').update('hello').digest('hex');
// → 5d41402abc4b2a76b9719d911017c592
Enter fullscreen mode Exit fullscreen mode

MD5 was the dominant hash function of the 1990s. Flaws were found in 1996; practical collision attacks were demonstrated in 2004. Today, researchers can generate MD5 collisions in seconds.

Collisions in practice: Two different inputs can produce the same MD5 hash. This has been exploited in real attacks, including the 2012 Flame malware, which used forged MD5 certificates to appear signed by Microsoft.

Still useful for: Non-security purposes where speed matters and collisions don't matter. Checksums where you're only checking for accidental corruption (not malicious tampering). Cache keys. Deduplication lookups.

Never use for: Passwords, digital signatures, TLS certificates, or anything where collision resistance is a security requirement.

SHA-1 (1995)

Output: 160 bits (40 hex characters)
Status: Broken for security purposes

SHA-1 held up longer than MD5 but followed a similar trajectory. Theoretical weaknesses were identified in 2005. In 2017, Google's Project Zero produced the first practical SHA-1 collision ("SHAttered"), generating two different PDF files with identical SHA-1 hashes.

All major browsers stopped accepting SHA-1 TLS certificates in 2017.

SHA-256 (2001)

Output: 256 bits (64 hex characters)
Status: Current standard

// Browser (Web Crypto API)
async function sha256(message) {
  const encoder = new TextEncoder();
  const data = encoder.encode(message);
  const hashBuffer = await crypto.subtle.digest('SHA-256', data);
  const hashArray = Array.from(new Uint8Array(hashBuffer));
  return hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
}

// Node.js
const hash = crypto.createHash('sha256').update('hello').digest('hex');
// → 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824
Enter fullscreen mode Exit fullscreen mode

SHA-256 is part of the SHA-2 family, which also includes SHA-224, SHA-384, and SHA-512. It's the current standard for most security applications.

Used in:

  • TLS/HTTPS certificates
  • Bitcoin block hashing
  • Code signing
  • JWT signatures (HMAC-SHA256)
  • File integrity verification
  • Software package managers

No practical attacks are known. The best known theoretical attacks don't approach practical exploitation.

SHA-512 (2001)

Output: 512 bits (128 hex characters)
Status: Current standard, higher security margin

const hash = crypto.createHash('sha512').update('hello').digest('hex');
Enter fullscreen mode Exit fullscreen mode

SHA-512 provides a larger security margin than SHA-256. Interestingly, on 64-bit processors, SHA-512 is often faster than SHA-256 because it processes data in 64-bit blocks rather than 32-bit blocks.

Use SHA-512 when you need a larger security margin — for example, signing very long-lived certificates, or for cryptographic protocols that require extra caution.

SHA-3 (2015)

Output: 224, 256, 384, or 512 bits
Status: NIST standard

SHA-3 uses a completely different internal structure from SHA-1 and SHA-2 (both of which use the Merkle–Damgård construction). This diversity is intentional: if a fundamental weakness is found in the Merkle–Damgård construction, SHA-3 would remain secure.

Ethereum uses Keccak-256, a variant of SHA-3.

Why Hashes Are Bad for Password Storage

This is the most important practical lesson. Even a secure hash like SHA-256 is wrong for storing passwords.

The problem: hash functions are designed to be fast. Modern GPUs can compute billions of SHA-256 hashes per second. Given a leaked database of SHA-256 hashed passwords, an attacker can try billions of candidate passwords per second until they find matches.

The rainbow table problem: Precomputed tables of common password hashes are widely available. Any common password hashed with a standard algorithm is likely already in a rainbow table.

The solution: Use a password hashing function designed specifically for this purpose. These functions are intentionally slow:

// Using bcrypt (Node.js)
const bcrypt = require('bcrypt');

// Hash (during registration)
const saltRounds = 12; // Cost factor — higher = slower = more secure
const hash = await bcrypt.hash(password, saltRounds);

// Verify (during login)
const match = await bcrypt.compare(candidatePassword, hash);
Enter fullscreen mode Exit fullscreen mode

Or Argon2, which is the current recommendation from the Password Hashing Competition:

const argon2 = require('argon2');

// Hash
const hash = await argon2.hash(password);

// Verify
const match = await argon2.verify(hash, candidatePassword);
Enter fullscreen mode Exit fullscreen mode

These functions are slow by design. Bcrypt with saltRounds=12 takes about 300ms on modern hardware. That's acceptable for one login attempt. It makes brute-force attacks prohibitively expensive.

File Integrity Verification

The most common user-facing application of hash functions is file verification. When you download software, the official site often provides a SHA-256 checksum:

toolzip-1.0.0.zip
SHA-256: a3f5b2c91d8e4f762390ad5b8e3c2f41...
Enter fullscreen mode Exit fullscreen mode
# macOS/Linux
shasum -a 256 toolzip-1.0.0.zip

# Windows PowerShell
Get-FileHash toolzip-1.0.0.zip -Algorithm SHA256
Enter fullscreen mode Exit fullscreen mode

If the hashes match, the file is identical to what was published. If they differ, either the file was corrupted in transit or — more concerning — it was replaced with a modified version.

Algorithm Selection Guide

Use case Algorithm Why
Passwords bcrypt, Argon2, scrypt Slow by design
File integrity SHA-256 Standard, unbroken
TLS certificates SHA-256 Industry standard
Digital signatures SHA-256, SHA-3 Unbroken
Non-security checksums MD5, SHA-1 Speed
Bitcoin SHA-256 Protocol standard
Ethereum Keccak-256 Protocol standard
JWT signatures HMAC-SHA256 JWT standard

Try It

ToolZip's hash generator computes MD5, SHA-1, SHA-256, SHA-384, and SHA-512 for both text input and file uploads — entirely in the browser using the Web Crypto API.

toolzip.app/tools/hash-generator


ToolZip — 48 free browser-based tools. Everything runs client-side.

Top comments (0)