Skip to content
    universaldevtools.in
    Back to Blog
    Security
    11 min readJan 10, 2025

    Cryptographic Hash Functions: MD5, SHA-256, and Beyond

    Hash functions are everywhere—from password storage to blockchain to Git commits. But which algorithm should you use? MD5? SHA-256? Bcrypt? The answer depends on what you're protecting. Here's your complete guide to choosing the right hash.

    What Hash Functions Actually Do

    A hash function takes input of any size and produces a fixed-size output called a "digest" or "hash." The same input always produces the same output, but even a tiny change in input produces a completely different hash. This makes them perfect for verification without exposing the original data.

    Input: "Hello, World!"

    MD5: fc3ff98e8c6a0d3087d515c0473f8677

    SHA-256: dffd6021bb2bd5b0af676290809ec3a53191dd81c7f70a4b28688a362182986f

    Input: "Hello, World." (just added a period)

    MD5: 08f7ae5dd5df036d92e65b5c9e5c4c24

    SHA-256: 9f8de6d1cc2b0e8e8c8c4e4e4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f

    Key Properties of Cryptographic Hashes

    • Deterministic: Same input → same output, always
    • One-way: Can't reverse-engineer input from output
    • Collision-resistant: Hard to find two inputs with the same hash
    • Avalanche effect: Small input change → completely different output

    The Hash Algorithm Comparison

    AlgorithmOutput SizeSpeedSecurityUse For
    MD5128 bits⚡ Very fast❌ BrokenChecksums only
    SHA-1160 bits⚡ Fast⚠️ WeakLegacy systems
    SHA-256256 bits⚡ Fast✅ StrongSignatures, integrity
    SHA-512512 bits⚡ Fast✅ StrongExtra security margin
    Bcrypt184 bits🐢 Slow (intentional)✅ StrongPasswords
    Argon2Variable🐢 Slow (intentional)✅ BestPasswords (modern)

    Practical Code Examples

    Generating Hashes in JavaScript

    // SHA-256 in the browser using 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('');
    }
    
    // Usage
    const hash = await sha256('Hello, World!');
    console.log(hash);
    // "dffd6021bb2bd5b0af676290809ec3a53191dd81c7f70a4b28688a362182986f"
    
    // Verifying file integrity
    async function verifyFileHash(file, expectedHash) {
      const buffer = await file.arrayBuffer();
      const hashBuffer = await crypto.subtle.digest('SHA-256', buffer);
      const hashArray = Array.from(new Uint8Array(hashBuffer));
      const actualHash = hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
      return actualHash === expectedHash;
    }

    Password Hashing with Bcrypt (Node.js)

    import bcrypt from 'bcrypt';
    
    // Hashing a password (during registration)
    async function hashPassword(plainPassword) {
      const saltRounds = 12; // Higher = slower = more secure
      const hash = await bcrypt.hash(plainPassword, saltRounds);
      return hash; // "$2b$12$LQv3c1yqBWVHxkd0LHAkCOYz6TtxMQJqhN8/X4c.4/4c.4/4c.4/4"
    }
    
    // Verifying a password (during login)
    async function verifyPassword(plainPassword, storedHash) {
      const isMatch = await bcrypt.compare(plainPassword, storedHash);
      return isMatch; // true or false
    }
    
    // ❌ WRONG: Don't do this!
    const badHash = await sha256(password); // Fast hash = easily cracked
    
    // ✅ CORRECT: Use slow password hashes
    const goodHash = await bcrypt.hash(password, 12);

    When to Use Which Hash

    File Integrity Verification → SHA-256

    Verify downloaded files match the expected hash. Fast and secure for non-secret data.

    Password Storage → Bcrypt or Argon2

    Slow hashes resist brute-force attacks. Argon2 is newer and recommended; bcrypt is widely supported.

    Digital Signatures → SHA-256 or SHA-512

    Sign documents and verify authenticity. Combined with asymmetric encryption (RSA, ECDSA).

    Cache Keys / Deduplication → SHA-256 (or even MD5)

    When security isn't a concern, any fast hash works for content-based identifiers.

    API Request Signing (HMAC) → SHA-256

    HMAC combines a hash with a secret key to authenticate API requests.

    Common Hash Security Mistakes

    Using Fast Hashes for Passwords

    SHA-256 can compute billions of hashes per second on GPUs. That means an attacker can try billions of password guesses per second. Always use bcrypt, Argon2, or scrypt for passwords—they're intentionally slow.

    Not Salting Password Hashes

    Without a unique salt per password, identical passwords produce identical hashes. Attackers use "rainbow tables" of precomputed hashes. Bcrypt and Argon2 handle salting automatically—don't roll your own.

    Trusting MD5 or SHA-1 for Security

    MD5 and SHA-1 have known collision attacks—attackers can create different files with the same hash. For any security-critical application, use SHA-256 or stronger.

    Comparing Hashes Insecurely

    String comparison like hash1 === hash2 can leak timing information. Use constant-time comparison functions when verifying hashes in security contexts.

    Frequently Asked Questions

    Is MD5 safe to use for anything?

    MD5 is broken for security purposes—don't use it for passwords or digital signatures. However, it's still acceptable for non-security uses like generating cache keys, detecting accidental file corruption, or creating content-based identifiers where attacks aren't a concern.

    What's the difference between hashing and encryption?

    Hashing is one-way: you can't recover the original data from a hash. Encryption is two-way: with the right key, you can decrypt and recover the original data. Use hashing for passwords and data verification; use encryption when you need to retrieve the original data later.

    Why do password hashes need to be slow?

    Fast hashes let attackers try billions of password guesses per second. Slow hashes like bcrypt or Argon2 are intentionally designed to take ~100-500ms each, making brute-force attacks impractical. A hash that takes 0.1 seconds to compute makes attacking a password list take months instead of minutes.

    Wrapping Up

    Hash functions are fundamental to modern security, but using the wrong one can leave you vulnerable. For passwords, always use slow hashes like bcrypt or Argon2. For integrity verification and signatures, SHA-256 is your go-to. And remember: hashing is one-way—it's not encryption.

    Next steps: Generate hashes of test data using our tools to understand how different algorithms behave, then review your application's password storage implementation.

    Related Resources