Skip to content

PBKDF2 Generator

Turn a password and salt into a PBKDF2 key with SHA-256, SHA-512 or SHA-1 and any number of iterations, or use scrypt or HKDF. Check the result against a key or a stored password hash. Everything runs in your browser.

PBKDF2-HMAC-SHA256("password", "salt", 600000) = 669cfe52…

Hash

Derived key

Type a password to see its key.

Everything is worked out in your browser. Your password is never sent anywhere.

How to generate a PBKDF2 key

  1. Type the password. Click the eye to see what you typed.
  2. Enter the salt, and say whether it is plain Text, Hex or Base64. For a new password, click Random to make one.
  3. Pick the hash (SHA-256 unless something else asks for another) and the number of iterations. The iterations box starts at OWASP's recommended count for SHA-256, SHA-512 and SHA-1.
  4. The key appears as soon as you stop typing. Copy it as hex or Base64, or as a ready-made Django password hash when the settings fit.

To check a password against a hash you already have, paste the hash into Check against a key or stored hash. A Django (pbkdf2_sha256$…) or Werkzeug/Flask (pbkdf2:sha256:…) hash carries its own salt and iterations: click Use these settings and type the password.

Worked example: password and salt

Take the password password and the salt salt, and run 600,000 iterations of HMAC-SHA256 for a 32-byte key. (Real salts should be random; these short ones make the example easy to repeat.)

Step 1: The settings

password “password” · salt “salt” (text) · SHA-256 · 600,000 iterations · 32 bytes

Step 2: The key in hex (64 characters)

669cfe52482116fda1aa2cbe409b2f56c8e4563752b7a28f6eaab614ee005178

Step 3: The same key in Base64

Zpz+UkghFv2hqiy+QJsvVsjkVjdSt6KPbqq2FO4AUXg=

Step 4: As Django stores it

pbkdf2_sha256$600000$salt$Zpz+UkghFv2hqiy+QJsvVsjkVjdSt6KPbqq2FO4AUXg=

Result: 669cfe52…. Click Example in the tool to load these settings. You get the same key from code:

# Python
hashlib.pbkdf2_hmac('sha256', b'password', b'salt', 600000).hex()

// Node.js
crypto.pbkdf2Sync('password', 'salt', 600000, 32, 'sha256').toString('hex')

// PHP (length is in hex characters: 64 = 32 bytes)
hash_pbkdf2('sha256', 'password', 'salt', 600000, 64)

PBKDF2 settings explained

PBKDF2 runs the password and salt through HMAC over and over, then hands back as many bytes as you ask for. Change any one of these four settings and you get a completely different key:

The four PBKDF2 settings, what each does and what to choose
SettingWhat it doesWhat to choose
HashThe hash used inside HMAC on every round.SHA-256. SHA-512 is fine too; SHA-1 only to match an old system.
SaltMakes the key different for every user, even when two people pick the same password.At least 16 random bytes, new for every password. Store it next to the key.
IterationsHow many rounds to run. More rounds make every guess slower for an attacker.600,000 for SHA-256, 220,000 for SHA-512 (OWASP).
Key lengthHow many bytes come out.The hash's own size: 32 bytes for SHA-256, 64 for SHA-512. Or what your cipher needs, such as 32 for AES-256.

How many PBKDF2 iterations should I use?

As many as your server can afford while logging someone in. Each iteration costs an attacker the same as it costs you, so the count is what decides how many guesses per second they can make. OWASP's current minimums are:

OWASP recommended minimum PBKDF2 iterations for each hash
PBKDF2 withMinimum iterationsNotes
HMAC-SHA256600,000The usual choice.
HMAC-SHA512220,000Fewer rounds because each SHA-512 round does more work.
HMAC-SHA11,400,000Only for older systems that need it.

Frameworks go further: Django 6.1 uses 1,500,000 iterations of SHA-256 and Werkzeug (used by Flask) 1,000,000. The tool shows how long each key took, which gives a rough idea of the cost: aim for a few hundred milliseconds on the computer that will check the passwords. Older guides that say 1,000 or 10,000 iterations are out of date; computers have got far faster at guessing.

If you are matching an existing system, use whatever count it used. A stored hash only checks out with its original settings; to move to a higher count, re-hash each password the next time its owner logs in.

Why doesn't my PBKDF2 key match?

Because one setting is different, even slightly. Here is the worked example's key with one thing changed each time:

How small differences change the PBKDF2-SHA256 key of password and salt
What is differentKey starts withWhat to do
Nothing: the worked example669cfe52…This is the reference.
Salt 73616c74 read as text instead of hexb3efcae6…Set the salt to Hex. As hex it is the bytes of “salt”, which gives 669cfe52….
100,000 iterations0394a2ed…Use the count the other system used.
SHA-512 instead of SHA-2568abe2c1b…Pick the same hash.
A space after the password0b701ba1…Remove it; the tool warns about it.
64-byte key instead of 32669cfe52… (twice as long)Same start, so only the length differs. The tool spots this.
PHP hash_pbkdf2 with length 32669cfe52… (half as long)PHP counts hex characters, not bytes. Use 64 for a 32-byte key.
Key written in Base64Zpz+Ukgh…Same key. Switch the output to Base64.

The salt is the most common culprit. Many libraries store it as hex or Base64 but feed the decoded bytes to PBKDF2, while Django and Werkzeug use the salt text itself. If a salt looks like hex, the tool asks whether you meant hex. Also check that the password is UTF-8: older .NET code that uses Encoding.Unicode turns the same text into different bytes.

PBKDF2 vs bcrypt, scrypt and Argon2

All four slow down password guessing; they differ in how hard they are to speed up with graphics cards and custom chips. For storing passwords, OWASP's order is Argon2id first, then scrypt, with bcrypt for older systems and PBKDF2 where FIPS-140 approved algorithms are required. HKDF is not on the list at all, because it is not meant for passwords.

Comparison of PBKDF2, bcrypt, scrypt, Argon2id and HKDF
FunctionBest forGood to know
PBKDF2Passwords where FIPS-140 compliance matters; encryption keys from passwords.Built into every browser and language. Needs very high iteration counts because graphics cards run it fast.
bcryptExisting systems that already use it.Only the first 72 bytes of a password count. Work factor of at least 10.
scryptPasswords when Argon2id is not available.Uses memory as well as time: N = 2^17, r = 8, p = 1 needs 128 MiB. Pick it in the tool above.
Argon2idNew password storage.OWASP minimum: 19 MiB of memory, 2 iterations, 1 thread.
HKDFMaking several keys from one secret that is already random.Fast on purpose. The info field gives each key its own purpose. Pick it in the tool above.

Frequently asked questions

Can PBKDF2 be decrypted?

No. PBKDF2 is one-way: there is no key that turns the result back into the password. The only attack is guessing passwords and running PBKDF2 on each guess, which is exactly what a high iteration count makes slow.

Is the salt secret?

No. The salt is stored in plain sight next to the key, as Django and Werkzeug do inside the hash string. Its job is to be unique, so that one password list cannot be used to attack every user at once. What matters is a fresh random salt for every password.

What should I store with a PBKDF2 password hash?

Everything needed to repeat the calculation: the hash, the number of iterations, the salt and the key. A single string such as pbkdf2_sha256$600000$<salt>$<key> keeps them together and lets you raise the iterations later without breaking old passwords.

Is my password sent anywhere?

No. PBKDF2 and HKDF run in your browser's built-in cryptography, and scrypt runs in a background worker on your device. Nothing you type leaves your computer. Even so, don't paste live production passwords into any website.

Sources