We're sorry but this app doesn't work properly without JavaScript enabled. Please enable it to continue.

This lesson's interactive features are locked, please to keep using them

Password KDFs

Passwords should never be stored in plaintext... but even hashing them isn't always enough.

If attackers steal your password hashes, they can test guesses offline on their own hardware with no rate limit. A fast general-purpose hash function like SHA-256 lets them rip through candidates, making SHA-256 a terrible password-storage choice.

Click to play video

Make Each Guess Expensive

A password key derivation function is designed to be expensive. For example, Argon2id consumes both CPU time and memory, making large batches of offline guesses much more costly.

Go's golang.org/x/crypto/argon2 package exposes the low-level derivation function. Bearly Secure must generate a random salt and derive the key explicitly:

salt := make([]byte, 16)
if _, err := rand.Read(salt); err != nil {
    return "", err
}
derivedKey := argon2.IDKey([]byte(password), salt, 2, 19*1024, 1, 32)

The provided helpers in internal/auth/passwords/argon2id.go handle the storage format. They encode the algorithm, version, parameters, salt, and derived key into one string, then strictly parse those values during verification. The parser also rejects malformed or excessive parameters before they reach the expensive derivation function.

Handling Legacy Hashes

Suppose your app already has users whose passwords are stored as 64-character SHA-256 hashes. Ruh-roh. Adding an Argon2-only verifier would lock them out!

You'll need to verify both formats during the transition, but create only Argon2id hashes for new or changed passwords:

  • Exactly 64 hexadecimal characters indicate a legacy SHA-256 hash.
  • A valid $argon2id$... value carries the salt and parameters needed for Argon2id verification.
  • Anything else is malformed and must fail closed.

Assignment

Bearly Secure stores passwords with fast SHA-256 hashes. Adopt Argon2id for every new or changed password without breaking existing accounts.

Run and submit the CLI tests from the project root.