DTTooleras

Understanding Hash Functions: MD5, SHA-256, and When to Use Each

A developer-friendly guide to cryptographic hash functions — how they work, the differences between MD5, SHA-1, SHA-256, and SHA-512, real-world use cases, and why you should never use MD5 for security.

DevToolsHub Team18 min read1,062 words

What is a Hash Function?

A hash function takes an input of any size and produces a fixed-size output (called a hash, digest, or checksum). The same input always produces the same output, but even a tiny change in the input produces a completely different hash.

Input: "Hello"        → SHA-256: 185f8db32271fe25f561a6fc938b2e264306ec304eda518007d1764826381969
Input: "Hello!"       → SHA-256: 334d016f755cd6dc58c53a86e183882f8ec14f52fb05345887c8a5edd42c87b7
Input: "hello"        → SHA-256: 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824

Notice how changing a single character (capitalization, adding "!") produces a completely different hash. This is called the avalanche effect.

Properties of Cryptographic Hash Functions

A good cryptographic hash function has these properties:

1. Deterministic

The same input always produces the same output. No randomness involved.

2. Fast to Compute

Generating a hash should be quick (though not too quick — see bcrypt below).

3. Pre-image Resistance

Given a hash, it should be computationally infeasible to find the original input. You can't "reverse" a hash.

4. Second Pre-image Resistance

Given an input, it should be infeasible to find a different input that produces the same hash.

5. Collision Resistance

It should be infeasible to find any two different inputs that produce the same hash.

6. Avalanche Effect

A small change in input should produce a drastically different hash.

Common Hash Algorithms

MD5 (Message Digest 5)

  • Output size: 128 bits (32 hex characters)
  • Speed: Very fast
  • Status: BROKEN for security purposes
  • Example: 5d41402abc4b2a76b9719d911017c592

MD5 was designed in 1991 and was widely used for decades. However, collision attacks were demonstrated in 2004, and practical attacks are now trivial. A collision can be generated in seconds on modern hardware.

Still acceptable for:

  • File integrity checks (non-security)
  • Cache keys
  • Deduplication
  • Checksums for data transfer

Never use for:

  • Password hashing
  • Digital signatures
  • Certificate verification
  • Any security-critical application

SHA-1 (Secure Hash Algorithm 1)

  • Output size: 160 bits (40 hex characters)
  • Speed: Fast
  • Status: DEPRECATED for security
  • Example: aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d

SHA-1 was the successor to MD5 and was widely used in SSL certificates and Git. Google demonstrated a practical collision attack (SHAttered) in 2017. Major browsers stopped accepting SHA-1 certificates in 2017.

Still used in:

  • Git (for commit hashes — not security-critical in this context)
  • Legacy systems being migrated

SHA-256 (SHA-2 family)

  • Output size: 256 bits (64 hex characters)
  • Speed: Fast
  • Status: SECURE — current standard
  • Example: 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824

SHA-256 is part of the SHA-2 family designed by the NSA. It's the most widely used secure hash function today, used in:

  • TLS/SSL certificates
  • Bitcoin mining
  • Digital signatures
  • HMAC authentication
  • File integrity verification

SHA-512

  • Output size: 512 bits (128 hex characters)
  • Speed: Slightly slower than SHA-256 on 32-bit systems, faster on 64-bit
  • Status: SECURE

SHA-512 provides a larger hash output. It's actually faster than SHA-256 on 64-bit processors because it operates on 64-bit words natively.

SHA-3 (Keccak)

  • Output sizes: 224, 256, 384, 512 bits
  • Speed: Comparable to SHA-2
  • Status: SECURE — newest standard

SHA-3 was selected through a public competition (2007-2012) and uses a completely different internal structure (sponge construction) than SHA-2. It provides a backup if SHA-2 is ever broken.

Comparison Table

AlgorithmOutput SizeSpeedSecurityUse Case
MD5128 bitsFastestBrokenChecksums only
SHA-1160 bitsFastDeprecatedLegacy only
SHA-256256 bitsFastSecureGeneral purpose
SHA-384384 bitsFastSecureHigher security
SHA-512512 bitsFastSecure64-bit optimized
SHA-3-256256 bitsFastSecureFuture-proof

Hashing in Practice

JavaScript (Browser)

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("");
}

// Usage
const hash = await sha256("Hello, World!");
console.log(hash);

Node.js

const crypto = require("crypto");

// SHA-256
const hash = crypto.createHash("sha256")
  .update("Hello, World!")
  .digest("hex");

// HMAC-SHA256
const hmac = crypto.createHmac("sha256", "secret-key")
  .update("Hello, World!")
  .digest("hex");

// Hash a file
const fs = require("fs");
const fileHash = crypto.createHash("sha256")
  .update(fs.readFileSync("file.txt"))
  .digest("hex");

Python

import hashlib

# SHA-256
hash_value = hashlib.sha256(b"Hello, World!").hexdigest()

# MD5 (non-security use only)
md5_value = hashlib.md5(b"Hello, World!").hexdigest()

# Hash a file
with open("file.txt", "rb") as f:
    file_hash = hashlib.sha256(f.read()).hexdigest()

# Hash a large file (streaming)
sha256 = hashlib.sha256()
with open("large_file.bin", "rb") as f:
    for chunk in iter(lambda: f.read(8192), b""):
        sha256.update(chunk)
print(sha256.hexdigest())

Command Line

# SHA-256
echo -n "Hello, World!" | sha256sum

# MD5
echo -n "Hello, World!" | md5sum

# Hash a file
sha256sum file.txt

Password Hashing: A Special Case

Never use MD5, SHA-1, or even SHA-256 directly for password hashing. General-purpose hash functions are too fast, making brute-force attacks feasible.

Instead, use purpose-built password hashing functions:

bcrypt

  • Includes a salt automatically
  • Has a configurable work factor (cost)
  • Deliberately slow to prevent brute-force attacks
const bcrypt = require("bcrypt");

// Hash a password
const hash = await bcrypt.hash("myPassword123", 12);

// Verify a password
const isValid = await bcrypt.compare("myPassword123", hash);

Argon2

  • Winner of the Password Hashing Competition (2015)
  • Configurable memory, time, and parallelism costs
  • Resistant to GPU and ASIC attacks

scrypt

  • Memory-hard function
  • Used by some cryptocurrency systems
  • Good alternative to bcrypt

Why not SHA-256 for passwords?

A modern GPU can compute billions of SHA-256 hashes per second. With a rainbow table or brute-force attack, most passwords can be cracked in minutes. bcrypt with a cost factor of 12 takes about 250ms per hash — making brute-force attacks impractical.

HMAC: Hash-Based Message Authentication

HMAC combines a hash function with a secret key to provide both integrity and authentication:

HMAC(key, message) = Hash((key XOR opad) || Hash((key XOR ipad) || message))

Common uses:

  • API authentication (webhook signatures)
  • JWT signing (HS256 = HMAC-SHA256)
  • Message integrity verification
// Verify a webhook signature
const crypto = require("crypto");

function verifyWebhook(payload, signature, secret) {
  const expected = crypto
    .createHmac("sha256", secret)
    .update(payload)
    .digest("hex");
  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expected)
  );
}

Generate hashes instantly with our Hash Generator tool.

hash functionmd5sha256sha512hashingpassword hashingbcrypthmaccryptography

Related articles

All articles

Practice with free tools

200+ free developer tools that run in your browser.

Browse all tools →