Cybersecurity/Networking

Password Hashing Algorithm Selection and Work Factor Tuning

5 min read by DebuggedIt

Quick answer

Store passwords with a slow, salted, purpose-built hashing algorithm, not a fast general hash. Argon2id is the usual first choice for new systems, with scrypt,...

Store passwords with a slow, salted, purpose-built hashing algorithm, not a fast general hash. Argon2id is the usual first choice for new systems, with scrypt, bcrypt, and PBKDF2 as established alternatives depending on constraints. Tune the work factor so one hash takes a noticeable fraction of a second on your production hardware, and plan to raise it over time as hardware improves.

Why Do Passwords Need Special Hashing?

General-purpose hash functions such as SHA-256 are designed to be fast. That is a virtue for checksums and a disaster for passwords, because an attacker who steals a database can test billions of guesses per second on modern hardware. Password hashing algorithms are deliberately slow and, in the better designs, memory-hungry, which makes large-scale guessing expensive.

A password hash must also include a unique random salt for each password. The salt ensures that identical passwords produce different hashes, and it defeats precomputed tables. Modern password hashing libraries generate and store the salt automatically inside the output string.

Encryption is the wrong tool. Passwords should be hashed so they cannot be recovered, since you only ever need to verify them, never read them back.

Which Algorithm Should You Choose?

Guidance from standards bodies and security organizations has converged on a short list. Check the current recommendations from sources such as OWASP and NIST, because parameters and preferences evolve.

  • Argon2id: the winner of the Password Hashing Competition and the common recommendation for new applications. It is memory-hard and resists attacks using specialized hardware, with parameters for memory, iterations, and parallelism.
  • scrypt: also memory-hard, widely implemented, and a sound choice where Argon2id is unavailable.
  • bcrypt: old, battle-tested, and still acceptable. It has a limit on password length, commonly 72 bytes, and a smaller memory footprint, so it is less resistant to specialized hardware.
  • PBKDF2: not memory-hard, but widely approved and often required by compliance regimes. It needs a high iteration count to be effective.

Use a well-maintained library from your language ecosystem instead of implementing anything yourself, and prefer the encoded hash format that embeds the algorithm, parameters, and salt, so you can verify and upgrade later.

How Do You Tune the Work Factor?

The work factor, whether cost, iterations, or memory, controls how expensive each hash is. Too low, and attackers guess quickly. Too high, and your own login endpoint becomes slow and easy to overload with requests.

Benchmark on the hardware you actually run in production. A common target is a hash time in the range of tens to a few hundred milliseconds per login, balancing user experience and server capacity. Consider peak login traffic and how many hashes your servers can compute concurrently, since hashing is deliberately CPU and memory intensive.

# conceptual tuning loop
for each candidate parameter set:
    measure time to hash one password on production-class hardware
choose the strongest set that stays under your latency budget
re-run the benchmark when hardware or load changes

Because high-cost hashing makes login a target for resource exhaustion, combine it with rate limiting and limits on password length, so attackers cannot force huge computations with giant inputs.

How Do Peppers and Migrations Fit In?

A pepper is a secret value, kept outside the database, that is mixed into the hashing process. It adds protection if only the database leaks, but it adds operational complexity, including secure storage and rotation, so adopt it only if you can manage it well.

Plan for upgrades from the start. When you raise the work factor or change algorithms, you cannot rehash stored hashes directly. The standard approach is to rehash on successful login: after verifying the password with the old parameters, compute a new hash with the current ones and store it. For accounts that never log in, you may wrap old hashes in the new algorithm or require a reset.

  • Store the algorithm and parameters with each hash, so verification knows what to do.
  • Check whether a stored hash needs upgrading each time a user logs in.
  • Never log passwords or hashes, and compare using constant-time functions provided by your library.
  • Pair strong hashing with breach checks and multi-factor authentication.

Frequently Asked Questions

Is SHA-256 with a salt good enough for passwords?

No. It is too fast. Use Argon2id, scrypt, bcrypt, or PBKDF2 with adequate parameters.

What is the best password hashing algorithm?

Argon2id is the common recommendation for new systems. Others are acceptable depending on constraints. Check current guidance.

How slow should a password hash be?

Slow enough to hurt attackers but fast enough for your login capacity. Tens to hundreds of milliseconds is a typical target.

How do I upgrade old password hashes?

Rehash on successful login with the new parameters, and handle inactive accounts with a reset or wrapping strategy.

Summary

Use a slow, salted, modern algorithm, tune the work factor on real hardware, upgrade hashes on login, and protect the login endpoint. Consult current OWASP and NIST guidance and your library documentation.