GO KALI FREE
IntermediateSecurity

Password Hashes Explained: How Passwords Are Stored Securely

Learn how password hashing works, the difference between hashing and encryption, common algorithms, and best practices for secure password storage.

#Password Hashing#Cryptography#Password Security#bcrypt#Hash Functions

The Breach That Exposed 6.5 Million Unprotected Passwords

In 2012, LinkedIn suffered a data breach that leaked 6.5 million password hashes. The company had stored them using unsalted SHA-1 — a fast hash with no random salt added. Within days, most passwords were cracked. The same password that protected a LinkedIn account could unlock banking, email, and corporate systems across the internet. This breach became a textbook case for why password hashing done wrong is almost as bad as storing passwords in plaintext.

Password hashing is the process of converting a password into a fixed-length string of characters using a one-way mathematical function. Unlike encryption, hashing is irreversible — you cannot derive the original password from its hash.

Prerequisites

Before studying password hashes, you should understand:

  • **Password Security Guide** — Password fundamentals
  • **Cryptography Basics** — One-way functions, salt concepts
  • **Linux Commands Explained** — Command line usage
  • **Data Structures** — String and binary data concepts
  • Hashing vs Encryption

    Hashing (One-Way)

    Password -> Hash Function -> Hash Value
    Hash Value -> Hash Function -> Cannot reverse
    

    Encryption (Two-Way)

    Password -> Encryption -> Ciphertext
    Ciphertext -> Decryption -> Password (with key)
    

    Common Hashing Algorithms

    MD5 (Message Digest 5)

    # Generate MD5 hash
    echo -n "password123" | md5sum
    # Result: 482c811da5d5b4bc6d497ffa98491e38
    

    MD5 produces 128-bit (32 character) hashes. It is cryptographically broken and should never be used for passwords.

    SHA-1 (Secure Hash Algorithm 1)

    # Generate SHA-1 hash
    echo -n "password123" | sha1sum
    # Result: cbfdac6008f9cab4083784cbd1874f76618d2a97
    

    SHA-1 produces 160-bit (40 character) hashes. It is also broken for security purposes.

    SHA-256

    # Generate SHA-256 hash
    echo -n "password123" | sha256sum
    # Result: efccecda192e9846eb1e8349051cf092b24ee3b8dbba83897b31f404e58f5abd
    

    SHA-256 produces 256-bit (64 character) hashes. It is still secure for integrity checking but not suitable alone for passwords.

    Why Simple Hashing is Not Enough

    Problem 1: Same Password, Same Hash

    password123 -> MD5: 482c811da5d5b4bc6d497ffa98491e38
    password123 -> MD5: 482c811da5d5b4bc6d497ffa98491e38
    

    If two users have the same password, they have the same hash. Attackers can see this and know those users share a password.

    Problem 2: Rainbow Tables

    Attackers precompute hashes for common passwords and store them in lookup tables called rainbow tables. A hash can be reversed by looking it up:

    | Password | MD5 Hash |

    |----------|----------|

    | password123 | 482c811da5d5b4bc6d497ffa98491e38 |

    | 123456 | e10adc3949ba59abbe56e057f20f883e |

    | qwerty | d8578edf8458ce06fbc5bb76a58c5ca4 |

    Problem 3: Speed

    Modern hashes like MD5 and SHA-256 are designed to be fast. Attackers can calculate billions of hashes per second using GPUs:

    # Hashcat benchmark for MD5
    hashcat -b --benchmark-all -m 0
    # Result: Billions of hashes per second on modern GPUs
    

    Password-Specific Hashing Algorithms

    bcrypt

    bcrypt is designed specifically for password hashing. It includes a work factor that makes it intentionally slow:

    import bcrypt
    
    # Hash a password (work factor 12 = 2^12 rounds)
    password = b"secure_password123"
    salt = bcrypt.gensalt(rounds=12)
    hashed = bcrypt.hashpw(password, salt)
    # Result: $2b$12$LJ3m4ys3Lk5Hxq8yQ9x7Qu4tX0c0pQzLk5Hxq8yQ9x7Q
    
    # Verify password
    bcrypt.checkpw(password, hashed)
    # Returns: True
    

    Argon2

    Argon2 is the winner of the Password Hashing Competition and the current gold standard:

    from argon2 import PasswordHasher
    
    ph = PasswordHasher(
        time_cost=3,        # Number of iterations
        memory_cost=65536,  # Memory usage in KB (64MB)
        parallelism=4,      # Number of threads
        hash_len=32,        # Output hash length
        salt_len=16         # Random salt length
    )
    
    # Hash a password
    hashed = ph.hash("secure_password123")
    # Result: $argon2id$v=19$m=65536,t=3,p=4$SALT$HASH
    
    # Verify
    ph.verify(hashed, "secure_password123")
    

    PBKDF2 (Password-Based Key Derivation Function 2)

    import hashlib
    import os
    
    # Generate salt
    salt = os.urandom(32)
    
    # Hash with PBKDF2
    dk = hashlib.pbkdf2_hmac(
        'sha256',           # Hash algorithm
        b'password',         # Password
        salt,               # Salt
        600000,             # Iterations (high count)
        dklen=32            # Output length
    )
    

    Understanding Hash Formats

    Linux Shadow File Hashes

    # /etc/shadow entry format
    username:$algorithm$salt$hash:last_change:min:max:warn:inactive:expire
    
    # $1$ = MD5
    # $5$ = SHA-256
    # $6$ = SHA-512
    # $2y$ = bcrypt
    # $argon2id$ = Argon2
    
    # Example (SHA-512)
    $6$saltvalue$hashvalue...
    
    # Example (bcrypt)
    $2y$12$LJ3m4ys3Lk5Hxq8yQ9x7Qu4tX0c0pQzLk5Hxq8yQ9x7Q
    

    Windows NTLM Hashes

    # NTLM hash format (hex string)
    # LM:NTLM format
    # Example:
    Administrator:500:NO PASSWORD*********************:NTLM_HASH::::
    
    # Crack NTLM with hashcat
    hashcat -m 1000 ntlm_hashes.txt /usr/share/wordlists/rockyou.txt
    

    Identifying Hash Types

    # Using hashid
    hashid '482c811da5d5b4bc6d497ffa98491e38'
    # Result: MD5
    
    hashid '$2y$12$LJ3m4ys3Lk5Hxq8yQ9x7Qu4tX0c0pQzLk5Hxq8yQ9x7Q'
    # Result: bcrypt
    
    # Using hash-identifier
    hash-identifier 482c811da5d5b4bc6d497ffa98491e38
    

    Real-World Examples

    LinkedIn Breach (2012): 6.5 million unsalted SHA-1 hashes were leaked. Because they lacked salts, most were quickly cracked.

    Adobe Breach (2013): 130 million unsalted hashes leaked. Adobe used unhashed password hints and DES-based encryption.

    Ashley Madison (2015): 36 million accounts leaked. Used bcrypt for some users but not all, demonstrating inconsistent security practices.

    Common Mistakes

    Using fast hashes for passwords: MD5, SHA-1, SHA-256 are designed for speed, making them terrible for password storage.

    No salting: Without salts, identical passwords produce identical hashes, enabling rainbow table attacks.

    Reusing salts: Salt reuse defeats the purpose — each password must have a unique salt.

    Self-made cryptography: Custom hash functions are almost always insecure.

    Best Practices

  • **Use Argon2 or bcrypt** — Purposely slow algorithms designed for passwords
  • **Always use salts** — Unique random salt per password
  • **Use adequate work factors** — Adjust based on hardware capabilities
  • **Never roll your own** — Use well-vetted libraries
  • **Use pepper** — A secret key stored outside the database (defense in depth)
  • **Plan for future upgrades** — Rehash with stronger algorithms when users log in
  • **Never truncate or modify hashes** — Use the full output
  • Related Tools

  • **hashid** — Identify hash types
  • **hash-identifier** — Alternative hash identification
  • **Hashcat** — GPU-accelerated password recovery
  • **John the Ripper** — CPU-based password cracking
  • **hash-analyzer** — Analyze hash properties
  • Related Articles

  • Password Security Guide
  • Hashcat Guide
  • John the Ripper Guide
  • Password Security Best Practices
  • Summary

    Password hashing is a one-way process that converts passwords into fixed-length hash values. Simple hashing with MD5 or SHA is insufficient due to speed and rainbow table attacks. Purpose-built algorithms like bcrypt and Argon2 include salting and configurable work factors to resist both GPU-based and ASIC-based attacks.

    Knowledge Check

  • What is the difference between hashing and encryption?
  • Why is salting important for password hashing?
  • What makes bcrypt better than SHA-256 for passwords?
  • How does the work factor in bcrypt resist GPU attacks?
  • What is a rainbow table and how do salts defeat it?
  • Frequently Asked Questions

    What is the difference between hashing and encryption?

    Hashing is a one-way function — you cannot reverse a hash to get the original password. Encryption is two-way — data can be decrypted with the correct key. Passwords must be hashed, never encrypted, because even encrypted passwords can be compromised if the key is stolen.

    Why is salting important for password hashing?

    A salt is a random value added to each password before hashing. Without salts, identical passwords produce identical hashes, enabling rainbow table attacks. Unique salts ensure even duplicate passwords have different hashes.

    Why should MD5 and SHA-256 never be used for passwords?

    MD5 and SHA-256 are designed to be fast — modern GPUs compute billions per second. This makes brute forcing trivial. Password-specific algorithms like bcrypt and Argon2 are intentionally slow, adding work factors that resist GPU-based attacks.

    How does bcrypt resist GPU attacks?

    bcrypt's work factor (e.g., rounds=12) means 2^12 iterations per hash. GPUs are optimized for parallel computation but struggle with bcrypt's sequential memory-hard design. This makes bcrypt significantly slower to crack than fast hashes.

    What is Argon2 and why is it the gold standard?

    Argon2 won the Password Hashing Competition and offers three variants (Argon2d, Argon2i, Argon2id). It's memory-hard, requiring large amounts of RAM per hash, making ASIC and GPU attacks expensive. Use Argon2id for most applications.

    What is a rainbow table?

    A rainbow table is a precomputed lookup table mapping common passwords to their hashes. Attackers use them to quickly reverse hashes. Salts defeat rainbow tables by ensuring each password produces a unique hash, even if the passwords are identical.

    How do you identify a hash type?

    Use hashid or hash-identifier tools. Hash formats often reveal the algorithm: $2y$ = bcrypt, $6$ = SHA-512, $argon2id$ = Argon2. The hash length also helps — MD5 is 32 chars, SHA-1 is 40, SHA-256 is 64.

    What is the work factor in bcrypt?

    The work factor (cost) determines how many iterations are used. A cost of 12 means 2^12 = 4096 iterations. Higher costs increase security but also slow down authentication. Adjust based on your hardware and acceptable login latency.

    What is a pepper in password hashing?

    A pepper is a secret key applied to all passwords before hashing, stored outside the database (e.g., in environment variables). If the database is breached, attackers still need the pepper. It adds defense in depth alongside salting.

    What real-world breaches involved weak hashing?

    LinkedIn (2012) used unsalted SHA-1 — 6.5 million hashes were quickly cracked. Adobe (2013) used DES-based encryption with password hints, making recovery trivial. Ashley Madison (2015) used bcrypt inconsistently. See [Password Security Guide](/learn/password-security-guide) for more.