Launch offer: the first 1,000 users get Settl free for a year*Claim your spot
settlbuilding in public

Hashing vs Encryption for Passwords

If your app needs to recover a user's password, the design is already wrong.

Encryption is reversible with a key. Use it for data your system must read again. Password verification does not need the original password, so store a slow password hash instead.

The password-storage contract

Use a maintained password-hashing library with Argon2id or bcrypt. The library should generate a unique random salt and store the algorithm parameters with the encoded hash. Do not build this from a general-purpose SHA function, and do not invent your own salt format.

At login:

  1. Load the encoded hash for the account.
  2. Pass the submitted password and stored value to the library's verify function.
  3. Use a constant-time implementation supplied by the library.
  4. If verification succeeds and the work factor is old, create a stronger hash and replace it.

The work factor should make one login acceptable and a large offline guessing attack expensive. Measure it on production-class hardware. Keep the chosen algorithm and parameters in a reviewed security policy rather than scattering defaults through controllers.

Migration without locking everyone out

Keep the old verifier temporarily. When a user logs in successfully, verify using the old scheme, then rehash with the new one inside the same account flow. Track migration coverage. Users who never return need a reset path, not a reversible backdoor.

Password reset tokens are credentials too. Generate a strong random token, store only a verifier or hash, set a short expiry, invalidate it after use, and revoke other outstanding reset tokens for the account.

Do not log submitted passwords, reset tokens, or full credential records. Keep any optional pepper in a secret manager, separate from the database.

Verification checklist

  1. Hash the same password twice. The encoded values differ because their salts differ.
  2. Verify both hashes with the right password and reject a wrong one.
  3. Measure the selected work factor and protect the login endpoint from abuse.
  4. Log in with a valid old-format hash and prove it upgrades.
  5. Use a reset token once, then prove reuse and expiry fail.
  6. Search logs, traces, fixtures, and error output for credential material.
  7. Prove the application has no route that can decrypt or return a password.

The runnable starter takes credential types, current password records, login flows, reset rules, and migration limits. It returns the classification, hashing plan, work-factor policy, migration path, and test suite for review. Dry-run performs no credential change.

Download the runnable pack

Comment HASH for the pack. Passwords are verified, not recovered.

Get the next one in your inbox