5
$\begingroup$

That is, in the case where the iterations value is a large number, since iterations are costly is there a difference in security of doing something like this, where two separate derivations are performed on the original password with the same large iterations value but different salts:

PBKDF2(password, randomSaltA, iterations = 1000000))
{       
    cryptKey = PBKDF2.Derive(); 
}
PBKDF2(password, randomSaltB, iterations = 1000000))
{       
    authKey = PBKDF2.Derive();  
}

vs something like this, where the crypt key is derived from the password with a high iterations value, but then the auth key is derived from the crypt key with a low iterations value (maybe just a single iteration), and so it runs in ~half the time but still yields two different keys:

PBKDF2(password, randomSaltA, iterations = 1000000))
{       
    cryptKey = PBKDF2.Derive(); 
}
PBKDF2(cryptKey, randomSaltB, iterations = 1))
{       
    authKey = PBKDF2.Derive();  
}

I believe in either case an attacker would have to do 1000000 iterations to guess the password, so the second example saves me time but doesn't save the attacker time... unless it creates a vulnerability that I am not aware of. Does the second example weaken the security somehow?

$\endgroup$
1
  • 1
    $\begingroup$ If you have to use PBKDF2, make sure you use SHA-512 because it requires less iterations. $\endgroup$ Jan 28, 2023 at 9:40

1 Answer 1

7
$\begingroup$

It's probably better your way because in the first instance you'd perform the work / iterations twice, while an attacker can simply verify a password doing the work once (either for the cipher / encryption key or for the authentication tag / authentication key).

Generally though we'd try and make sure we would not be able to get either of the keys given another key. In your case, if you'd be able to retrieve the encryption key you'd also be getting the authentication key. That's probably better than the other way around, but it can be avoided by using a KDF twice:

$$K_{master} = \text{PBKDF}(\mathit{password}, \mathit{salt}, \mathit{iterations})\\ K_{enc} = \text{KDF}(K_{master}, \texttt{'enc'})\\ K_{mac} = \text{KDF}(K_{master}, \texttt{'auth'})$$

Here you can indeed use PBKDF2 as password hash, and PBKDF2 with a single iteration and the string as salt as KDF. However, if you have a choice, it makes more sense to use HKDF or HKDF-Expand to derive the encryption and authentication keys.

You could also use SHA-256 for PBKDF2 to derive two 128 bit keys or SHA-512 to derive two 256 bit keys. It is however not recommended to get retrieve more than the output size of the hash algorithm from PBKDF2, because it will perform all the iterations again to get additional output. And, as we've just discussed, an attacker doesn't have to perform those iterations to verify the correctness of a password.

You could also look at other algorithms such as Argon2.

$\endgroup$
5
  • 3
    $\begingroup$ I second "look at other algorithms such as Argon2". PBKDF2 protects against adversaries with CPUs, less so against adversaries with GPUs, even less so against adversaries with FPGAs, and very little so against adversaries with ASICs. Argon2, scrypt, or even bcrypt are a considerable improvement from this standpoint. PBKDF2 is the most ASIC-friendly iterated KDF a state-level adversary can dream of. Perhaps not coincidentally, US authorities do not actively recommend to phase it out, consistent with pushing for 56-bit DES, and Dual_EC_DRBG. $\endgroup$
    – fgrieu
    Jan 28, 2023 at 6:59
  • 2
    $\begingroup$ This would also be my recommendation. I would go with Argon2. bcrypt can't be used as a KDF but is decent for password hashing. $\endgroup$ Jan 28, 2023 at 9:44
  • $\begingroup$ Comments are not for extended discussion; this conversation has been moved to chat. $\endgroup$
    – Maarten Bodewes
    Jan 29, 2023 at 13:27
  • 1
    $\begingroup$ @samuel-lucas6 Left your comment here (it's also in the chat room) so I can ask you a followup: why wouldn't you be able to use bcrypt as a KDF? Isn't it a PBKDF which is a KDF by definition? $\endgroup$
    – Maarten Bodewes
    Jan 29, 2023 at 13:28
  • 2
    $\begingroup$ @MaartenBodewes bcrypt is only a password hashing algorithm, not a PBKDF. If you look at the original presentation, it only says password hashing. It also has a fixed output that's not even long enough for a 256-bit key, and what's returned by libraries is typically a string containing the algorithm, cost, salt, and hash, not bytes/just the hash (e.g. see bcrypt.net). $\endgroup$ Jan 29, 2023 at 20:47

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.