Score:5

For password-based authenticated encryption is it OK to derive the auth key from the crypt key with 1 iteration?

bq flag

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?

samuel-lucas6 avatar
bs flag
If you have to use PBKDF2, make sure you use SHA-512 because it requires [less](https://tobtu.com/minimum-password-settings/) iterations.
Score:7
in flag

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.

fgrieu avatar
ng flag
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.
samuel-lucas6 avatar
bs flag
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.
Maarten Bodewes avatar
in flag
Comments are not for extended discussion; this conversation has been [moved to chat](https://chat.stackexchange.com/rooms/142430/discussion-on-answer-by-maarten-bodewes-for-password-based-authenticated-encrypt).
Maarten Bodewes avatar
in flag
@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?
samuel-lucas6 avatar
bs flag
@MaartenBodewes bcrypt is only a password hashing algorithm, not a PBKDF. If you look at the [original presentation](https://www.usenix.org/legacy/events/usenix99/provos/provos_html/node1.html), 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](https://github.com/BcryptNet/bcrypt.net)).
mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.