Skip to content
AZ Tools

scrypt Key Derivation (RFC 7914)

Derive a key from a password with scrypt in the browser, with the memory cost worked out and the PBKDF2 and ROMix stages shown.

How to use

  1. Press RFC 7914 #1, #2 or #3 and derive to see a key the RFC publishes; the first also reproduces the RFC's ROMix vector at stage 2.
  2. Enter your own password and salt — check hex if the salt is raw bytes — and choose N, r, p and the key length.
  3. Watch the memory figure before deriving: it is what each guess costs an attacker, and what each login costs your server.
  4. Paste a key you are trying to reproduce into the expected field to have it compared byte for byte.
  5. Use the OWASP preset as a starting point for new password storage, then raise N until one derivation takes as long as you can afford.

About this tool

Show

Run scrypt on a password and salt and see what the cost parameters actually buy. scrypt is three steps: PBKDF2-HMAC-SHA256 with a single iteration expands the password into p blocks of 128 × r bytes, ROMix fills a table of N such blocks and then reads it back in an order that depends on the data, and a second single-iteration PBKDF2 uses the mixed blocks as its salt. The table is the whole idea — it needs 128 × r × N bytes at once, so an attacker cannot trade memory for more cores the way they can against PBKDF2 or bcrypt — and the page shows that figure as you change the parameters: N = 2^14 with r = 8 is 16 MiB, and OWASP's minimum for password storage, N = 2^17, r = 8, p = 1, is 128 MiB. Both intermediate stages are printed. For the first test vector of RFC 7914 they are exactly the input and output of the ROMix vector in section 10, so every step can be compared with a published number rather than trusted. The parameter rules are enforced as the RFC states them, including one that surprises people: N must be below 2^(16 × r), so with r = 1 the largest allowed N is 2^15, and OpenSSL refuses 2^16 even though it fits easily in memory. The password is hashed as its UTF-8 bytes, which means the same visible text typed in two Unicode normalisation forms — é as one code point or as e plus a combining accent — produces two different keys. The derived key's length does not change its beginning: a 32-byte key is the first half of the 64-byte key from the same inputs, because the final PBKDF2 produces its output block by block. The computation runs in the tab and yields to it regularly, so a large N shows progress and can be cancelled; the page will allocate up to 1024 MiB, which is what the RFC's own fourth vector needs.

Frequently asked questions

What do N, r and p do?

N is the number of blocks in the ROMix table and the number of mixing rounds, so it sets both the memory and the time. r is the size of each block in units of 128 bytes; raising it makes each memory access larger and was chosen at 8 to suit cache lines and memory latency. p runs that many independent ROMix computations; it multiplies the work, and the memory only if they run at the same time.

Why can't N be 2^16 with r = 1?

RFC 7914 requires N to be less than 2^(128 × r / 8), which is 2^16 when r is 1. The rule keeps the index derived from each block large enough to address the table. OpenSSL enforces it, and so does this page, which is why the error appears even though 8 MiB would fit in memory without trouble. With r = 2 the limit is already 2^32.

Why does my key differ from another implementation's?

Usually the bytes going in differ. Check that the password is encoded as UTF-8 and in the same Unicode normalisation form, that the salt is the same bytes rather than its hex or base64 spelling, and that N is the value itself and not its logarithm — some libraries take ln=14 where others take N=16384. The stage 1 value here is PBKDF2 alone, so if even that differs, the inputs are the problem.

Is a shorter key just the start of a longer one?

Yes. The last step is PBKDF2, which produces its output in 32-byte blocks that do not depend on the requested length, so the first 32 bytes of a 64-byte key are the 32-byte key for the same inputs. That makes truncation safe, and it also means two lengths from the same password are not independent keys.

Should I use this to hash real passwords?

Use it to choose parameters, to check an implementation against the RFC, or to reproduce a stored hash while debugging. The password stays in the tab but is kept in local storage, and the arithmetic is not written to resist timing measurement. For production, use your platform's scrypt or Argon2id with a per-user random salt, and store the parameters beside the hash so you can raise them later.

Related tools