Exploring Methods to Hash Passwords: SHA-256, bcrypt, scrypt, Argon2 & more

56 views

Hashing passwords before saving them in a database is crucial for security. Here are several methods to hash passwords, each with its pros and cons:

1. SHA-256

Pros: Widely adopted and available in many programming languages. Cons: Fast hashing makes it susceptible to brute-force attacks without proper salting and iterations.

import hashlib

def hash_password_sha256(password: str) -> str:
    sha_signature = hashlib.sha256(password.encode()).hexdigest()
    return sha_signature

# Usage
hashed_password = hash_password_sha256("my_secure_password")

2. bcrypt

Pros: Specifically designed for password hashing, includes a salt automatically. Cons: Slower compared to some other hashing methods (which is also a security feature).

import bcrypt

def hash_password_bcrypt(password: str) -> str:
    hashed = bcrypt.hashpw(password.encode(), bcrypt.gensalt())
    return hashed.decode()

# Usage
hashed_password = hash_password_bcrypt("my_secure_password")

3. scrypt

Pros: Very memory-intensive, making it more resistant to GPU-based attacks. Cons: Similar libraries are not as common as bcrypt.

import hashlib
import os

def hash_password_scrypt(password: str) -> str:
    salt = os.urandom(16)
    hash = hashlib.scrypt(password.encode(), salt=salt, n=16384, r=8, p=1)
    return salt + hash

# Usage
hashed_password = hash_password_scrypt("my_secure_password")
# Store as base64 for easier database storage
import base64
hashed_password_b64 = base64.b64encode(hashed_password).decode()

4. Argon2

Pros: The winner of the Password Hashing Competition. Cons: Slightly more complex API, but increasing support in modern libraries.

from argon2 import PasswordHasher

def hash_password_argon2(password: str) -> str:
    ph = PasswordHasher()
    hashed = ph.hash(password)
    return hashed

# Usage
hashed_password = hash_password_argon2("my_secure_password")

5. PBKDF2 (Password-Based Key Derivation Function 2)

Pros: NIST recommended, flexible (can increase iterations). Cons: Not memory-hard as scrypt or Argon2.

import hashlib
import os

def hash_password_pbkdf2(password: str) -> str:
    salt = os.urandom(16)
    hash = hashlib.pbkdf2_hmac('sha256', password.encode(), salt, 100000)
    return salt + hash

# Usage
hashed_password = hash_password_pbkdf2("my_secure_password")
# Store as base64 for easier database storage
import base64
hashed_password_b64 = base64.b64encode(hashed_password).decode()

6. Cryptographic Libraries

Utilize other well-established cryptographic libraries provided by various programming languages, which often have built-in safety and additional features.

Example using Python's passlib:

from passlib.context import CryptContext

# Define password hashing context
pwd_context = CryptContext(schemes=["pbkdf2_sha256", "bcrypt", "argon2"], deprecated="auto")

def hash_password_passlib(password: str) -> str:
    return pwd_context.hash(password)

# Usage
hashed_password = hash_password_passlib("my_secure_password")

Advice:

  1. Always use a salt: It prevents attacks using precomputed hashes (rainbow tables).
  2. Use built-in libraries: Where possible, rely on well-tested libraries for hashing.
  3. Iterate: Use multiple iterations to slow down hash computations.
  4. Upgrade regularly: Stay updated with the latest recommendations and algorithms.

Pick the right tool for your environment and security requirements, and make sure to store and handle your hashed passwords securely.