Get a Pentest and security assessment of your IT network.

Cyber Security

Stronger Passwords: Custom Hashing

TL;DR

Standard password hashing (like bcrypt or Argon2) is good, but adding a unique salt *per user* and stretching the hash multiple times makes cracking passwords much harder. This guide shows how to do it.

1. Understand Password Hashing Basics

Password hashing turns your plain text password into an unreadable string of characters. It’s a one-way process – you can’t get the original password back from the hash. Crucially, it should be slow to compute.

  • Hashing Algorithms: Examples include SHA-256, bcrypt, Argon2. bcrypt and Argon2 are generally preferred because they automatically handle salting and stretching.
  • Salts: Random data added to the password *before* hashing. This prevents attackers from using pre-computed tables of common passwords (rainbow tables).
  • Stretching: Repeating the hashing process many times. This makes cracking slower, as it requires more computational power.

2. Why Custom Hashing?

While bcrypt and Argon2 are excellent, a custom approach gives you finer control over security parameters and can potentially offer increased resistance against future attacks if implemented carefully.

3. Implementing a Custom Hashing Procedure

  1. Generate a Unique Salt per User: Each user needs their own random salt. Store this salt securely alongside the hashed password (e.g., in your database).
  2. import os
    salt = os.urandom(16) # Generate 16 bytes of random data
    print(salt)
  3. Choose a Strong Hashing Algorithm: SHA-256 is a good starting point, but consider newer algorithms if available in your programming language/framework.
  4. Multiple Stretching Rounds: Repeat the hashing process several times (e.g., 10,000 or more). The higher the number of rounds, the slower and more secure it becomes, but also increases processing time.
  5. import hashlib
    def hash_password(password, salt, rounds=10000):
      hashed = password.encode('utf-8') # Encode to bytes
      for _ in range(rounds):
        hashed = hashlib.sha256(salt + hashed).digest()
      return hashed
  6. Combine Salt and Hash for Storage: Store both the salt *and* the final hash in your database. Never store passwords in plain text!
  7. Verification Process: When a user logs in, retrieve their salt from the database. Re-hash the entered password using that same salt and compare it to the stored hash.
  8. def verify_password(entered_password, stored_salt, stored_hash):
      hashed = hash_password(entered_password, stored_salt)
      return hashed == stored_hash

4. Important Considerations

  • Salt Length: Use a salt length of at least 16 bytes (128 bits) for good security.
  • Stretching Rounds: Experiment to find a balance between security and performance. Start with 10,000 rounds and increase if your server can handle it.
  • Secure Storage: Protect the salts stored in your database. If an attacker gains access to the salts, they can crack passwords more easily.
  • Regular Updates: Stay informed about new hashing algorithms and best practices in cyber security. Consider updating your hashing procedure periodically.
  • Avoid Re-inventing the Wheel: bcrypt and Argon2 are well-tested and optimized. Only use a custom approach if you have specific requirements or expertise.
Related posts
Cyber Security

Zip Codes & PII: Are They Personal Data?

Cyber Security

Zero-Day Vulnerabilities: User Defence Guide

Cyber Security

Zero Knowledge Voting with Trusted Server

Cyber Security

ZeroNet: 51% Attack Risks & Mitigation