I am currently revising an AES data format. I would like to determine whether a provided password/key is incorrect. Previously this was done by validating the HMAC, but this makes it impossible to distinguish between data corruption and a bad password. It also requires reading the entire stream before validating the password, which is problematic.

My new design is as follows (the HMAC step is HKDF):

prk = PBKDF2(SHA512, password, salt, rounds, 512 bits)
(validator[16], iv[16]) = HMAC(SHA512, prk, "rncryptor.validator+iv" || 0x01, 256 bits)

The validator is 16 bytes that are written to the header. During decryption, I recompute the validator to check the password before proceeding.

I believe this scheme is secure. Common best-practice for password validation is a salted and stretched hash. I believe HKDF is providing the same. My one slight concern is NIST SP 800-56a, Section 5.8:

An Approved key derivation function (KDF) shall be used to derive secret keying material from a shared secret. The output from a KDF shall only be used for secret keying material, such as a symmetric key used for data encryption or message integrity, a secret initialization vector, or a master key that will be used to generate other keys (possibly using a different process). Non- secret keying material (such as a non-secret initialization vector) shall not be generated using the shared secret.

The validator is not "keying material" at all, so I don't believe this is relevant, but I don't understand the restriction even for "a non-secret initialization vector." Why would it be dangerous to use a proper, salted KDF to generate a non-secret IV? Does this impact my use as a key/password validator?

  • 1
    $\begingroup$ I'd call HKDF-Expand twice with different strings, once for the IV and once for the validator. Or implicitly use a MAC as validation. One could also consider using HKDF-Extract on the password and feeding its output to PBKDF2. $\endgroup$ – CodesInChaos Jan 23 '14 at 15:50
  • $\begingroup$ How are you deriving the key? $\endgroup$ – CodesInChaos Jan 23 '14 at 15:53
  • $\begingroup$ I originally called the HKDF twice, but I did have some concern at truncating a 512-bit hash down to 128 bits. I'm using SHA512 because it's called for by draft-mcgrew-aead-aes-cbc-hmac-sha2 for AES256, and I'd like to keep the number of primitives required to a minimum. $\endgroup$ – Rob Napier Jan 23 '14 at 15:54
  • $\begingroup$ Full spec is here: github.com/RNCryptor/RNCryptor-Spec/blob/master/…. If you pass I key, I use HKDF-Extract. If you use a password, I use PBKDF2. $\endgroup$ – Rob Napier Jan 23 '14 at 15:55
  • $\begingroup$ Note that I don't think it is particularly bad what you are doing in above scheme. It's just not standardized (as far as I know) and probably not well researched. $\endgroup$ – Maarten Bodewes Jan 24 '14 at 0:56

It's best practice to use the KBKDF to generate separate key material for validation as well as for generating the key used for encryption using a different input or counter of each key.

If you do apply a KBKDF for each key / IV (using different ID's/counters for each) then you should not have any concern leaking any information. These KBKDF's are plenty fast (especially in comparison with PBKDF2 of course) so speed should not be a concern.

I would suggest to use a counter mode KDF in NIST SP800-108 if you want to stay within NIST boundaries. You can still use your favourite HMAC as PRF.

Note that there is some discussions regarding the security of KDF's. NIST approved KDF's may not always be the most safe. For instance, consider scrypt over PBKDF2 and HKDF-Expand (your currently selected KBKDF) over NIST SP800-108 if you don't require NIST approved algorithms.

Note that all the KBKDF's of NIST as well as HKDF have been added to Bouncy Castle 1.50 lightweight API for Java (I did the implementation / testing against NIST CAVP vectors), in case you require an implementation.

  • $\begingroup$ "You are trying to generate your own KBKDF." I don't quite understand. The KDF I'm using here is exactly HKDF (RFC 5869), isn't it? $\endgroup$ – Rob Napier Jan 23 '14 at 15:51
  • $\begingroup$ Oh sorry, I overlooked that sentence, I'll rewrite some stuff... done. $\endgroup$ – Maarten Bodewes Jan 23 '14 at 15:52
  • $\begingroup$ Thanks. BTW, I have considered scrypt and bcrypt. I've chosen PBKDF2 because of its ubiquitous availability. I am strongly trying to avoid implementers writing any more crypto primitives than absolutely required. rncryptor.github.io/blog/2014/01/21/why-not-scrypt $\endgroup$ – Rob Napier Jan 23 '14 at 15:58
  • 1
    $\begingroup$ @RobNapier Yeah, I think that is a sane choice, I mainly added it as a hint to other readers. $\endgroup$ – Maarten Bodewes Jan 23 '14 at 16:02

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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