If you are encrypting data with a password, you need a way to turn that password into a cryptographic key. AES-256 needs a 256-bit key. Your password is not 256 bits. Something has to bridge that gap.
That something is a key derivation function, or KDF. There are three serious options: PBKDF2, bcrypt, and Argon2. They all do the same basic job (turn a password into a key), but they take very different approaches to slowing down attackers. Understanding the differences will help you choose the right one.
What a KDF Does and Why You Need One
A cryptographic key needs to be the right size (256 bits for AES-256) and it needs to look random. Human passwords are neither. They are too short, they are not uniformly distributed, and they often contain patterns.
A KDF takes a password and produces a key of the desired length. It does this by hashing the password with a salt (random data that makes the output unique) many times. The iteration count controls how many times, and this is what makes the KDF slow.
Why does slow matter? Because the slowness is your defense against brute-force attacks. If an attacker steals your encrypted data, they can try different passwords, run each through the KDF, and attempt to decrypt. Each attempt takes as long as the KDF takes. If the KDF takes 200 milliseconds per derivation, the attacker can try 5 passwords per second per CPU core. If the KDF takes 1 microsecond, they can try a million per second.
The KDF turns a weak password into a computationally expensive one. The more iterations, the more expensive. This is why choosing the right KDF and the right parameters is critical.
PBKDF2: The NIST Standard
PBKDF2 (Password-Based Key Derivation Function 2) was standardized by NIST in 2000 (RFC 2898). It is the oldest of the three options and the most widely supported. It is available in the Web Crypto API, in every major programming language's standard library, and in countless frameworks.
**How it works:** PBKDF2 applies a pseudorandom function (typically HMAC-SHA-256) repeatedly to the password and salt. Each iteration feeds its output into the next iteration. After the specified number of iterations, the output is the key. The output length can be whatever you need.
**Strengths:** - NIST standard, which means it is required for compliance in many government and enterprise contexts. - Available everywhere, including the Web Crypto API (crypto.subtle.deriveKey with PBKDF2). - Supports arbitrary output lengths, making it ideal for deriving AES keys. - Simple to implement correctly.
**Weaknesses:** - CPU-hard but not memory-hard. Each iteration requires very little memory, which means an attacker can run thousands of parallel derivations on a single GPU. A modern GPU can compute millions of PBKDF2-SHA-256 hashes per second. - The iteration count is the only tuning parameter. To make it harder to crack, you increase iterations, which linearly increases the time. This does not scale well against specialized hardware.
**When to use it:** PBKDF2 is the right choice when you need a KDF for browser-side encryption (it is the only one available in the Web Crypto API), when you need NIST compliance, or when you are deriving an AES key from a password. Use at least 600,000 iterations with SHA-256 for general use.
Bcrypt: The Battle-Tested Password Hasher
Bcrypt was designed in 1999 specifically for password hashing. It is not a general-purpose KDF in the same way PBKDF2 is, but it can be used for key derivation in some contexts.
**How it works:** Bcrypt is based on the Blowfish cipher's key scheduling algorithm. It takes a password, a salt, and a cost factor, and produces a 184-bit hash. The cost factor is an exponent: the algorithm runs 2^cost iterations. Cost 12 means 4,096 iterations.
**Strengths:** - 25+ years of real-world testing with no discovered vulnerabilities. - Adaptive cost factor: you can increase the cost over time as hardware improves. - The salt and cost factor are embedded in the hash string, making storage simple. - Requires more memory per hash than PBKDF2, making GPU attacks somewhat less efficient.
**Weaknesses:** - 72-byte password limit. Passwords longer than 72 bytes are silently truncated. This is rarely a problem for human passwords but can be an issue for derived keys or long passphrases. - Fixed 184-bit output. This is fine for password storage but not ideal for deriving a 256-bit AES key. You would need to use bcrypt's output as input to another KDF, which adds complexity. - Not available in the Web Crypto API. You need a JavaScript implementation for browser-side use.
**When to use it:** Bcrypt is an excellent choice for password storage (hashing passwords for a login system). It is not ideal for key derivation because of the fixed output length. For a deeper look, see our bcrypt explained post.
Argon2: The Modern Champion
Argon2 was the winner of the 2015 Password Hashing Competition. It was designed from the ground up to address the limitations of both PBKDF2 and bcrypt.
**How it works:** Argon2 is both CPU-hard and memory-hard. You configure it with three parameters: memory cost (how much RAM to use), time cost (how many iterations to run), and parallelism (how many threads to use). The memory-hardness is the key innovation: each derivation requires a large block of memory, which means an attacker cannot parallelize attacks cheaply.
**Strengths:** - Memory-hard: each derivation requires a configurable amount of RAM (typically 64MB or more). An attacker would need that much memory for each parallel derivation, making GPU and ASIC attacks prohibitively expensive. - Tunable on three dimensions (memory, time, parallelism), giving you fine-grained control over the cost profile. - Supports arbitrary output lengths, making it suitable for key derivation. - No password length limit. - Recommended by OWASP as the primary choice for password hashing.
**Weaknesses:** - Newer than PBKDF2 and bcrypt, with less real-world testing (though still over a decade of use). - Not available in the Web Crypto API. You need a JavaScript implementation (like argon2-browser) for browser-side use. - More complex to configure correctly. You need to choose three parameters instead of one, and getting the balance right requires testing. - Memory usage can be a concern in resource-constrained environments.
**When to use it:** Argon2id (the recommended variant) is the best choice for password storage when you have the flexibility to use it. It is also a good choice for server-side key derivation. For browser-side encryption, you are currently limited to PBKDF2 via the Web Crypto API, though Argon2 can be used via WebAssembly.
Which One Should You Use?
The answer depends on your use case:
**For browser-side encryption (deriving an AES key from a password):** Use PBKDF2. It is the only one available in the Web Crypto API, it is fast enough for interactive use, and with 600,000+ iterations it provides adequate protection. This is what our AES text encryptor uses.
**For server-side password storage:** Use Argon2id if you can. It is the most resistant to hardware attacks. If Argon2 is not available, use bcrypt with a cost factor of 12. Both are far better than PBKDF2 for password storage because they are harder to parallelize on GPUs.
**For NIST compliance:** Use PBKDF2. It is the only one that is a NIST standard, which may be a requirement for government or regulated industries.
**For high-security server-side key derivation:** Use Argon2id with high memory and time costs. The memory-hardness makes it the most expensive for an attacker to crack.
The Common Thread
All three of these functions do the same fundamental thing: they make password-based cryptography expensive to attack. The differences are in how they achieve that expense (CPU time, memory, or both) and how easy they are to deploy.
The most important thing is not which one you choose, but that you use one. Using a raw password as a key (or hashing it once with SHA-256) is a catastrophic mistake that makes brute-force attacks trivial. Any of these three, used with appropriate parameters, will make your encryption secure against all but the most determined attackers.
For a deeper look at the encryption mode these keys are used with, read our AES-256-GCM explained post. For a comparison of bcrypt, scrypt, and Argon2 specifically for password hashing, see our bcrypt vs Argon2 vs scrypt breakdown.