What is a Hash Function?

A hash function is a mathematical algorithm that takes input of any size and produces a fixed-length output (hash). It’s a β€œone-way function” - easy to compute forward, but practically impossible to reverse.

Basic Properties

1. Deterministic Same input always produces same output:

"hello" β†’ 5d41402abc4b2a76b9719d911017c592
"hello" β†’ 5d41402abc4b2a76b9719d911017c592  // Always the same

2. Fixed Length Regardless of input size, same output length:

MD5("hi")     β†’ 49f68a5c8493ec2c0bf489821c21fc3b  (32 hex chars)
MD5("hello")  β†’ 5d41402abc4b2a76b9719d911017c592  (32 hex chars)
MD5("very long text...") β†’ ... (32 hex chars)

3. Avalanche Effect Minimal change in input causes total change in output:

MD5("hello")  β†’ 5d41402abc4b2a76b9719d911017c592
MD5("hallo")  β†’ 4d186321c1a7f0f354b297e8914ab240  // Completely different!

4. Fast to Compute Hash functions are designed to be fast.

Hash Algorithms

MD5 (Message Digest 5)

Output: 128 bits (32 hex characters)

MD5("password") β†’ 5f4dcc3b5aa765d61d8327deb882cf99

Created: 1991 by Ronald Rivest

Status: ❌ BROKEN - Do NOT use for security

Why broken?

  • Collision attacks possible since 2004
  • Can generate two different inputs with same hash
  • Can be cracked in minutes with modern hardware

When can MD5 still be used?

// βœ… OK: Non-security checksums
const fileChecksum = md5(fileContent);

// βœ… OK: Cache keys
const cacheKey = md5(url + params);

// ❌ NEVER: Passwords or security-related
const passwordHash = md5(password); // DANGEROUS!

SHA-1 (Secure Hash Algorithm 1)

Output: 160 bits (40 hex characters)

SHA1("password") β†’ 5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8

Created: 1995 by NSA

Status: ❌ DEPRECATED - Phase out

Why deprecated?

  • Theoretical collision attacks 2005
  • Practical collisions demonstrated 2017 (SHAttered attack)
  • Git still uses SHA-1 but migrating to SHA-256

Usage today:

// ⚠️ Legacy system - phase out
if (isLegacySystem) {
  hash = sha1(data); // Plan migration to SHA-256
}

// ❌ New systems - do NOT use
const newHash = sha1(password); // Use SHA-256+ instead

SHA-256 (SHA-2 family)

Output: 256 bits (64 hex characters)

SHA256("password") β†’ 5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8

Created: 2001 by NSA

Status: βœ… SECURE - Recommended

Advantages:

  • No known practical attacks
  • Used in Bitcoin and blockchain
  • NIST standard
  • Balance between security and performance

Usage:

// βœ… File integrity
const fileHash = sha256(fileContent);

// βœ… Digital signatures
const signature = sign(sha256(message), privateKey);

// βœ… Blockchain
const blockHash = sha256(sha256(blockHeader)); // Bitcoin double-SHA256

// ⚠️ Passwords - use bcrypt/argon2 instead
const passwordHash = sha256(password); // OK but bcrypt is better

SHA-512 (SHA-2 family)

Output: 512 bits (128 hex characters)

SHA512("password") β†’ b109f3bbbc244eb82441917ed06d618b9008dd09b3befd1b5e07394c706a8bb980b1d7785e5976ec049b46df5f1326af5a2ea6d103fd07c95385ffab0cacbc86

Created: 2001 by NSA

Status: βœ… SECURE - Extra strong

Advantages:

  • Stronger security than SHA-256
  • Faster on 64-bit systems
  • Larger hash = less collision risk

Disadvantages:

  • Double the output length
  • Slower on 32-bit systems
  • Often overkill for most use cases

When to use SHA-512:

// βœ… Extra sensitive data
const topSecretHash = sha512(sensitiveData);

// βœ… Long-term archiving
const archiveHash = sha512(document);

// βœ… HMAC for tokens
const token = hmacSha512(data, secretKey);

// ❌ When size matters (URLs, databases)
const shortHash = sha256(data); // Better choice

SHA-3 (Keccak)

Output: Variable (224, 256, 384, 512 bits)

Created: 2015 (NIST competition winner)

Status: βœ… SECURE - New standard

Differences from SHA-2:

  • Completely different internal structure (sponge construction)
  • Not based on Merkle-DamgΓ₯rd
  • Theoretically more resistant to certain attacks

Usage:

// βœ… When SHA-2 is not enough
const futureProofHash = sha3_256(data);

// βœ… Ethereum uses Keccak256
const ethereumHash = keccak256(data);

Why not more popular?

  • SHA-256 is still secure
  • SHA-3 is slower in many implementations
  • Less ecosystem support

Comparison

AlgorithmOutput SizeSpeedSecurityUse Case
MD5128 bit⚑⚑⚑ Fastest❌ BrokenChecksums (non-security)
SHA-1160 bit⚑⚑ Fast⚠️ DeprecatedLegacy, Git
SHA-256256 bit⚑ Mediumβœ… SecureRecommended standard
SHA-512512 bit⚑ Mediumβœ… Very secureExtra security
SHA-3Variable🐌 Slowerβœ… Future-proofNew systems

Practical Examples

1. File Integrity Check

// Download file and verify integrity
async function downloadAndVerify(url, expectedHash) {
  const response = await fetch(url);
  const buffer = await response.arrayBuffer();

  const hash = await crypto.subtle.digest("SHA-256", buffer);
  const hashHex = Array.from(new Uint8Array(hash))
    .map((b) => b.toString(16).padStart(2, "0"))
    .join("");

  if (hashHex !== expectedHash) {
    throw new Error("File integrity check failed!");
  }

  return buffer;
}

// Usage
await downloadAndVerify(
  "https://example.com/file.zip",
  "abc123..." // SHA-256 hash from source
);

2. Git Commit Hash

# Git uses SHA-1 (migrating to SHA-256)
git log --oneline
# a1b2c3d Fix bug in login
# e4f5g6h Add new feature

# Commit hash is SHA-1 of:
# - Tree hash
# - Parent commit hash
# - Author info
# - Commit message
# - Timestamp

3. Bitcoin Mining

// Bitcoin mining = find hash starting with zeros
function mine(blockHeader, difficulty) {
  let nonce = 0;
  const target = "0".repeat(difficulty);

  while (true) {
    const hash = sha256(sha256(blockHeader + nonce));

    if (hash.startsWith(target)) {
      return { nonce, hash };
    }

    nonce++;
  }
}

// Find hash starting with 4 zeros
const result = mine("Block data...", 4);
// { nonce: 182394, hash: "0000abc123..." }

4. Password Verification (BAD METHOD)

// ❌ NEVER use SHA for passwords directly!
function badPasswordHash(password) {
  return sha256(password);
}

// Problems:
// 1. Too fast - 1 billion attempts per second
// 2. Rainbow tables
// 3. No salt

// βœ… Use bcrypt/argon2 instead
import bcrypt from "bcrypt";

async function goodPasswordHash(password) {
  const salt = await bcrypt.genSalt(12);
  return await bcrypt.hash(password, salt);
}

5. Cache Keys

// βœ… Good use of SHA-256 for cache
function getCacheKey(url, params) {
  const data = JSON.stringify({ url, params });
  return sha256(data);
}

const cacheKey = getCacheKey("/api/users", { page: 1, limit: 10 });
// "a1b2c3d4..."

cache.get(cacheKey);

Hash vs Encryption

HashEncryption
One-wayTwo-way
Fix output sizeVariable output
FastSlower
DeterministicUses keys
Integrity checkConfidentiality

Hash:

const hash = sha256("secret");
// "2bb80..."
// Cannot be recovered to "secret"

Encryption:

const encrypted = encrypt("secret", key);
// "x7j9k..."
const decrypted = decrypt(encrypted, key);
// "secret"  βœ… Can be decrypted

HMAC (Hash-based Message Authentication Code)

Combines hash with a secret key:

function hmac(message, secretKey) {
  const hash1 = sha256(
    (secretKey ^ opad) + sha256((secretKey ^ ipad) + message)
  );
  return hash1;
}

// Verifies both integrity AND authenticity
const signature = hmac("message", "secret-key");

Usage:

  • JWT tokens
  • API signatures (AWS, etc.)
  • Webhook verification
// Verify webhook from GitHub
const signature = req.headers["x-hub-signature-256"];
const payload = req.body;
const secret = process.env.WEBHOOK_SECRET;

const expectedSignature =
  "sha256=" +
  crypto
    .createHmac("sha256", secret)
    .update(JSON.stringify(payload))
    .digest("hex");

if (signature !== expectedSignature) {
  throw new Error("Invalid signature");
}

Rainbow Tables & Salt

Problem:

// Same password = same hash
sha256("password123") β†’ "ef92b..."
sha256("password123") β†’ "ef92b..." // Same!

// Rainbow table: pre-computed hashes
// "password123" β†’ "ef92b..."
// "123456"      β†’ "8d969..."
// ...millions more...

Solution: Salt

// Add random data before hash
const salt = generateRandomBytes(16);
const hash = sha256(password + salt);

// Save both salt and hash
db.save({
  salt: salt,
  hash: hash,
});

// Now same password has different hash
sha256("password123" + "abc") β†’ "123..."
sha256("password123" + "xyz") β†’ "789..." // Different!

That’s why: Use bcrypt which does this automatically!

Choosing the Right Algorithm

For File Integrity

βœ… SHA-256; // Best balance
βœ… SHA-512; // Extra paranoid
❌ MD5; // Only for non-security

For Passwords

βœ… bcrypt; // Recommended
βœ… argon2; // More modern, stronger
βœ… scrypt; // Also good
❌ SHA-256; // Too fast, no salt management
❌ MD5; // NEVER!

For Digital Signatures

βœ… SHA-256; // Standard
βœ… SHA-512; // Extra security
βœ… SHA-3; // Future-proof

For Git/Blockchain

βœ… SHA-256; // Bitcoin, modern Git
⚠️ SHA-1; // Legacy Git (migrating)

For Cache Keys

βœ… SHA-256; // Good balance
βœ… MD5; // OK for cache
βœ… SHA-1; // OK for cache

Performance

Benchmark (1 billion operations):

MD5:     ~2 seconds   ⚑⚑⚑
SHA-1:   ~3 seconds   ⚑⚑
SHA-256: ~4 seconds   ⚑
SHA-512: ~3 seconds   ⚑ (on 64-bit)
SHA-3:   ~6 seconds   🐌

For most applications, speed doesn’t matter!

Security Best Practices

1. Use the Right Tool

// ❌ Wrong tool
const passwordHash = md5(password);

// βœ… Right tool
const passwordHash = await bcrypt.hash(password, 12);

2. Stay Updated

// ⚠️ Being phased out
if (usingLegacySHA1) {
  planMigrationToSHA256();
}

3. Combine with Salt

// ❌ Without salt
const hash = sha256(password);

// βœ… With salt
const salt = crypto.randomBytes(16);
const hash = sha256(password + salt);

4. Iterate for Passwords

// ❌ One iteration
const hash = sha256(password);

// βœ… Many iterations (bcrypt does this)
let hash = password;
for (let i = 0; i < 10000; i++) {
  hash = sha256(hash);
}

Tools

Test different hash algorithms:

Conclusion

For new projects:

  • βœ… SHA-256 - Standard for file integrity, signatures
  • βœ… bcrypt/argon2 - ALWAYS for passwords
  • βœ… HMAC-SHA256 - For authentication tokens

Avoid:

  • ❌ MD5 - Only non-security use cases
  • ❌ SHA-1 - Being phased out, plan migration
  • ❌ SHA-256 for passwords - Use bcrypt instead

Remember: Hash β‰  Encryption β‰  Encoding

Choose the right tool for the job!