bcrypt vs Argon2id vs scrypt: Which Password Hashing Algorithm Should You Use?

Use Argon2id for all new password storage implementations, configured with at least 19 MiB of memory, 2 iterations, and 1 thread, the minimum the OWASP Password Storage Cheat Sheet recommends. If Argon2id is unsupported, use scrypt. Bcrypt remains acceptable for legacy systems with work factor 10 or greater, but truncates passwords at 72 bytes.
Selecting the right cryptographic algorithm for credential storage is a fundamental architectural decision. For over two decades, the bcrypt algorithm served as the default standard across web frameworks, operating systems, and authentication microservices. However, advances in cracking hardware, particularly massively parallel graphics processing units (GPUs) and application-specific integrated circuits (ASICs), have transformed modern security requirements.
Today, security standards like the OWASP Password Storage Cheat Sheet prioritize memory-hard functions over pure CPU-bound algorithms. Fast general-purpose digests like MD5 and SHA-256 must never be used for password storage; to learn how digest architectures and collision vulnerabilities differ, see our guide on MD5 vs SHA-256. Understanding the architectural distinctions between Argon2id, scrypt, and bcrypt enables engineering teams to protect user credentials against offline dictionary and brute-force attacks. You can inspect hashes and test cost factors using our client-side Bcrypt Generator & Verifier, generate high-entropy master keys with our Password Generator, or verify raw checksums with our Hash Generator.
Which Algorithm Does the Official OWASP Cheat Sheet Recommend?
The OWASP Foundation maintains clear, authoritative guidance on password storage. Rather than treating all adaptive functions equally, the current OWASP Password Storage Cheat Sheet establishes a strict priority hierarchy for development teams building authentication pipelines.
OWASP establishes that developers should always choose modern algorithms designed to resist both GPU-based and memory-based attacks:
- Argon2id (Primary Choice): Argon2 won the 2015 Password Hashing Competition; Argon2id is its hybrid variant, specified in RFC 9106. OWASP instructs: "Out of the three Argon2 versions, use the Argon2id variant since it provides a balanced approach to resisting both side-channel and GPU-based attacks."
- scrypt (Secondary Alternative): OWASP states: "While Argon2id should be the best choice for password hashing, scrypt should be used when the former is not available."
- bcrypt (Legacy Systems): OWASP emphasizes: "The bcrypt password hashing function should only be used for password storage in legacy systems where Argon2 and scrypt are not available. The work factor should be as large as verification server performance will allow, with a minimum of 10."
- PBKDF2 (FIPS-140 Mandates): Permitted under NIST SP 800-63B where FIPS-140 validated modules are legally required, utilizing a minimum of 600,000 iterations for PBKDF2-HMAC-SHA256 or 220,000 iterations for PBKDF2-HMAC-SHA512.
What Are the Exact Parameter Configurations for Each Algorithm?
Cryptographic algorithms cannot protect credentials when executed with inadequate cost parameters. OWASP and primary RFC specifications prescribe exact minimum settings to ensure cracking attempts remain economically and computationally infeasible.
1. Argon2id Configuration (RFC 9106)
Under RFC 9106: Argon2 Memory-Hard Function for Password Hashing and Proof-of-Work Applications, Argon2id provides hybrid defense by combining data-independent memory access (resisting side-channel timing attacks) and data-dependent memory access (maximizing GPU resistance).
Argon2id relies on three tuning parameters defined in RFC 9106 Section 3.1: memory size in KiB ($m$), iteration passes ($t$), and degree of parallelism ($p$). OWASP recommends benchmarking the target host and selecting one of the following equivalent minimal defense configurations:
- $m = 19456$ (19 MiB), $t = 2$, $p = 1$ (OWASP standard minimum)
- $m = 47104$ (46 MiB), $t = 1$, $p = 1$ (High RAM, low CPU pass)
- $m = 12288$ (12 MiB), $t = 3$, $p = 1$
- $m = 9216$ (9 MiB), $t = 4$, $p = 1$
- $m = 7168$ (7 MiB), $t = 5$, $p = 1$
These configurations provide an equal level of defense, offering a flexible trade-off between CPU cycles and RAM footprint.
2. scrypt Configuration (RFC 7914)
Created by Colin Percival and standardized in RFC 7914: The scrypt Password-Based Key Derivation Function, scrypt pioneered sequential memory-hard cryptographic functions. Its parameters govern CPU/memory cost ($N$), block size ($r$), and parallelization ($p$).
OWASP specifies one of the following minimum parameter sets:
- $N = 2^{17} = 131072$ (128 MiB), $r = 8$ (1024 bytes), $p = 1$
- $N = 2^{16} = 65536$ (64 MiB), $r = 8$ (1024 bytes), $p = 2$
- $N = 2^{15} = 32768$ (32 MiB), $r = 8$ (1024 bytes), $p = 3$
- $N = 2^{14} = 16384$ (16 MiB), $r = 8$ (1024 bytes), $p = 5$
- $N = 2^{13} = 8192$ (8 MiB), $r = 8$ (1024 bytes), $p = 10$
Where RAM allows, configuring $N = 2^{17}$, $r = 8$, $p = 1$ enforces a 128 MiB memory footprint that severely penalizes mass-scale GPU search pipelines.
3. bcrypt Configuration & The 72-Byte Truncation Limit
Bcrypt was introduced in 1999 by Niels Provos and David Mazières. Its work factor represents logarithmic rounds: cost 10 computes $2^{10} = 1,024$ Blowfish key schedules, while cost 12 computes $2^{12} = 4,096$ rounds. OWASP recommends a work factor of 10 or more.
Crucially, bcrypt imposes an immutable input boundary: standard implementations use only the first 72 bytes of the input password. As explained in our guide on how bcrypt works, Blowfish XORs key material into an 18-element 32-bit subkey array ($18 \times 4 = 72$ bytes total). Any password bytes beyond byte 72 are silently ignored. If a user enters an 80-character passphrase, the trailing 8 bytes do not contribute to credential security.
| Algorithm | Primary Specification | Memory Hardness | Input Length Boundary | OWASP Baseline Parameter Set |
|---|---|---|---|---|
| Argon2id | RFC 9106 | High (configurable, 19 MiB to 64 MiB) | Arbitrary length (no practical limit) | m=19456 (19 MiB), t=2, p=1 |
| scrypt | RFC 7914 | High (configurable, 16 MiB to 128 MiB) | Arbitrary length (up to 2^64 - 1 bytes) | N=2^17 (128 MiB), r=8, p=1 |
| bcrypt | Provos & Mazières (1999) | Low (~4 KB, fits in L1 CPU cache) | Hard limit: 72 bytes maximum | Work factor >= 10 (cost 10 to 12) |
| PBKDF2 | RFC 8018 / NIST SP 800-63B | None (memory-free iteration loop) | Arbitrary length (HMAC pre-hashing) | >= 600,000 iterations (HMAC-SHA-256) |
Why Does Memory Hardness Matter Against GPU and ASIC Attackers?
When adversaries compromise an SQL database dump containing password hashes, they mount offline attacks using specialized hardware clusters rather than web requests.
A modern consumer GPU contains thousands of stream cores, while custom ASIC chips house millions of dedicated execution units. When cracking an unsalted digest like MD5 or fast hashes like SHA-256, an off-the-shelf GPU cluster evaluates tens of billions of guesses per second.
Bcrypt mitigates this by introducing computational delay via its configurable work factor. However, bcrypt requires only 4 KB of memory per thread. Because 4 KB fits entirely into the high-speed L1 cache of a GPU core or custom ASIC register bank, cracking hardware can compute thousands of bcrypt hashes simultaneously on a single chip without bottlenecking on memory bandwidth.
Argon2id and scrypt counter this advantage through memory hardness. By requiring 19 MiB to 64 MiB of high-speed RAM per calculation, a GPU with 16 GB of VRAM can fit only a few hundred simultaneous hashing threads before exhausting its memory bus. Attackers unable to fit parallel worker threads onto chip dies are restricted to the throughput of the physical memory bus.

What Are the Real Benchmark Timings on Our Test Machine?
To measure how these algorithms perform in practice, we ran direct benchmarks using Node.js v24.17.0 on our test machine (64-bit AMD x86_64 architecture). We evaluated native Node.js standard library cryptographic functions alongside the widely adopted bcryptjs pure JavaScript implementation.
The table below reflects real measured execution latencies averaged over multiple runs on our test machine:
| Library & Algorithm | Configured Parameters | Average Latency | Min / Max Observed |
|---|---|---|---|
bcryptjs v3.0.3 | Work factor 10 (1,024 rounds) | 159.7 ms | 147 ms / 180 ms |
bcryptjs v3.0.3 | Work factor 12 (4,096 rounds) | 682.4 ms | 590 ms / 814 ms |
Node native crypto.scryptSync | N=16384 (2^14), r=8, p=1 | 85.6 ms | 77.9 ms / 99.4 ms |
Node native crypto.scryptSync | N=65536 (2^16), r=8, p=1 | 336.5 ms | 300.5 ms / 399.2 ms |
Node native crypto.pbkdf2Sync | 600,000 iterations, HMAC-SHA-256 | 355.0 ms | 290.0 ms / 556.2 ms |
These timings illustrate the latency-security trade-off in modern authentication. A verification latency between 150 ms and 350 ms is imperceptible to a human logging into a web application, but it forces an attacker attempting 100,000,000 dictionary guesses to expend months of dedicated computation.
bcryptjs. We do not offer an online Argon2 or scrypt web tool at this time. If your project uses bcrypt, our tool lets you benchmark cost factors and verify 60-character hashes client-side. For new production applications, we encourage integrating native Argon2id libraries directly into your backend code.How Do Modern Programming Languages Support These Algorithms?
Before committing to an algorithm for your production stack, review runtime support and library availability:
- Node.js & TypeScript: Includes native bindings for scrypt via
crypto.scryptandcrypto.scryptSyncin the standard library. For Argon2id, applications install theargon2npm package (wrapping the C reference library) or WebAssembly distributions. For bcrypt, teams usebcrypt(native addon) orbcryptjs(pure JS). - Python: Python 3.8+ provides
hashlib.scryptin the standard library. For Argon2id, the standard solution isargon2-cffi, which serves as the default password hasher in modern Django. For bcrypt, thebcryptpackage provides C-accelerated bindings. - PHP: PHP provides first-class native support via
password_hash()andpassword_verify(). Developers invokePASSWORD_ARGON2IDnatively when PHP is compiled with Argon2 support (standard in PHP 7.3+), or usePASSWORD_BCRYPTwith custom cost options. - Java & Spring Boot: Spring Security includes
Argon2PasswordEncoder,SCryptPasswordEncoder, andBCryptPasswordEncoder. While Spring defaults toBCryptPasswordEncoder(10)for backward compatibility, moving toArgon2PasswordEncoderrequires only a one-line configuration bean. - Go (Golang): The official Go cryptography repository (
golang.org/x/crypto) provides pure Go and assembly implementations for all three:argon2,scrypt, andbcrypt, requiring zero Cgo dependencies.
How Do You Migrate a Legacy Database from Bcrypt to Argon2id?
Migrating an existing user database from bcrypt to Argon2id cannot be accomplished with a batch script because one-way cryptographic hashes cannot be reversed to reveal plaintext passwords. Wrapping existing bcrypt hashes inside Argon2id introduces unnecessary complexity.
Instead, production applications implement the rehash-on-login pattern:
- Retain Existing Hashes: Keep your current database table containing bcrypt hashes. Store an algorithm identifier column (e.g.,
algo: "bcrypt"vsalgo: "argon2id"), or inspect the hash prefix string ($2b$vs$argon2id$). - Authenticate User: When a user logs in with their plaintext password, check the algorithm flag. If marked as bcrypt, verify credentials using standard bcrypt verification logic.
- Transparent Rehash: If bcrypt verification succeeds, immediately hash the plaintext password using your new Argon2id configuration ($m=19456$, $t=2$, $p=1$).
- Update Record: Overwrite the database record with the new Argon2id hash and update the algorithm column. Subsequent logins for that user will now authenticate directly against Argon2id.
- Periodic Audits: Over several months, active users will naturally migrate to Argon2id without experiencing authentication downtime or forced password resets. Inactive accounts can be prompted to reset their passwords upon return.
For teams managing account security policies, combining strong algorithm parameters with credential hygiene is essential. Learn how to generate high-entropy master passphrases in our guide on how to use a password generator safely.
Frequently asked questions
Which password hashing algorithm is recommended by OWASP today?+
Under the OWASP Password Storage Cheat Sheet, Argon2id is the primary recommendation for all new systems, followed by scrypt if Argon2id is unavailable. Bcrypt is restricted to legacy applications where modern memory-hard alternatives cannot be installed.
Why is Argon2id better than bcrypt against modern GPU and ASIC cracking rigs?+
Bcrypt requires only 4 KB of memory during key scheduling, allowing an attacker to run thousands of parallel instances on modern GPUs and custom ASICs. In contrast, Argon2id is memory-hard, requiring tens of megabytes of RAM per hash to bottleneck high-speed custom hardware.
What is the exact password length limit for bcrypt?+
Bcrypt implementations truncate plain text input at exactly 72 bytes because the underlying Blowfish key schedule operates on eighteen 32-bit words (72 bytes total). Argon2id and scrypt support arbitrarily long passwords without truncation.
How can an existing production database migrate safely from bcrypt to Argon2id?+
Applications should use the rehash-on-login migration pattern. When a user enters their credentials, verify the input against the existing bcrypt hash; upon successful verification, rehash the plaintext password using Argon2id and overwrite the database record.
When should a developer choose PBKDF2 instead of Argon2id or bcrypt?+
PBKDF2 is recommended strictly when regulatory environments require FIPS-140 compliance, such as US federal agency systems, using HMAC-SHA-256 with at least 600,000 iterations as specified in NIST SP 800-63B.
Prashant Sharma · Founder & Technology Strategist
Prashant Sharma is the founder of Zynocode IT Solutions, specializing in web development, SEO tooling and generative AI workflows.