Security / Cryptography/PBKDF2
PBKDF2 is a key derivation function, used in the process of deriving encryption keys.
The main idea of PBKDF2 is repeatedly applying the input and the salt to a hash function like HMAC to produce a key, which can be used later on in subsequence operations.
Passwords managers like 1Password and Bitwarden use this function (in a combination of a much more complex scheme) with your Master Password to generate a symmetric key for encrypting and decrypting data in your vault.
The PBKDF2 function takes several input parameters and produces the derived key as output:
$$
\text{Output} = \text{PBKDF2}(\text{PRFn}, \text{Password}, \text{Salt}, \text{N}, \text{KeyLen})
$$
where:
- $PRFn$ is a pseudorandom function that produces an output length $hLen$ bits, for example, keyed HMAC.
- $Password$ is the input password
- $Salt$ is a securely generated random bytes, minium 64 bits but 128 bits is recommended
- $N$ is the number of iterations of HMAC derivation. For example, in Bitwarden, it’s 100,001 iterations
- $KeyLen$ is the expected key length for the output, for example, 32 bytes (256 bits)
The iterations count is directly proportional to the time it takes for key derivation. The slower key derivation, the slower login time but the password is more secure against cracking attacks.
The $Output$ is the concatenation of many $hLen$ bit blocks:
$$
\text{Output} = T_1 + T_2 + … + T_{\text{KeyLen} / \text{hLen}}
$$
Each block $T_i$ is computed as:
$$
T_i = F(\text{Password}, \text{Salt}, \text{N}, i)
$$
The function $F$ is the XOR of $Count$ iterations of chained $PRFn$. Chained mean, the later iterations will use the computed result of the previous iteration as an input:
$$
F(\text{Password}, \text{Salt}, \text{N}, i) = U_1 \oplus U_2 \oplus … \oplus U_{\text{N}}
$$
Where each $U$ is:
$$
U_1 = \text{PRFn}(\text{Password}, \text{Salt} + \text{Int32BigEndian}(i))
$$
$$
U_2 = \text{PRFn}(\text{Password}, U_1) \quad \quad \quad \quad \quad \quad \quad \quad \quad \quad
$$
$$
…
$$
$$
U_N = \text{PRFn}(\text{Password}, U_{N-1}) \quad \quad \quad \quad \quad \quad \quad \quad \quad
$$
The $Output$ is extracted as the first $KeyLen$ bits of the final hash.
It’s important to note that PBKDF2 is not resistant to GPU attacks for ASIC attacks (attacks using specialized hardware). For new systems, it’s recommended to use a more secure algorithm like Bcrypt, Scrypt, or Argon2 instead.
What’s next?
- https://bitwarden.com/help/bitwarden-security-white-paper/◹
- https://1passwordstatic.com/files/security/1password-white-paper.pdf◹