Skip to content
uencoder
TUTORIAL

How to Derive Keys with PBKDF2

Derive a cryptographic key from a password using PBKDF2 with a high iteration count and salt.

Problem

You need to derive a symmetric key from a user password, but passwords are low-entropy and need stretching.

Prerequisites

  • Understanding of key derivation
  • Knowledge of salt and iteration count

Steps

  1. 1. Generate a random salt

    Generate a cryptographically random salt of at least 16 bytes. The salt ensures that the same password produces different keys for different users or sessions. Store the salt alongside the derived key; it is not secret.

    Input
    16 random bytes
    Output
    salt: a1b2c3...
  2. 2. Choose an iteration count

    Select an iteration count high enough to make brute force expensive. OWASP recommends at least 600,000 iterations for PBKDF2-HMAC-SHA256. Higher is more secure but slower. Tune based on your server's capacity.

    Input
    iterations: 600000
    Output
    ~500ms per derivation
  3. 3. Derive the key

    Run PBKDF2 with the password, salt, iteration count, and a PRF (HMAC-SHA256). The output is a deterministic key of the requested length. The same password and salt always produce the same key, but an attacker must repeat all iterations for each guess.

    Input
    password + salt + 600000 iters
    Output
    32-byte derived key

Expected result

A derived key that is computationally expensive to brute force, suitable for encrypting data or verifying passwords.

Common errors

Iteration count too low
Anything below 100,000 is too fast for modern GPUs. Use at least 600,000 for SHA-256 per OWASP 2023 guidance.
Reusing the salt across users
Generate a unique random salt per password. A shared salt enables multi-target attacks.

Troubleshooting

  • If derivation is too slow, reduce iterations or switch to a faster KDF like scrypt or Argon2 which are memory-hard.
  • If you need to verify passwords, store the salt and iteration count with the derived key.

Security limits

  • PBKDF2 is CPU-hard but not memory-hard, making it vulnerable to GPU/ASIC attacks. Consider scrypt or Argon2 for stronger resistance.
  • All derivation is local.

Related tools

Related glossary

Related tasks

Ready to run it?

References