As indicated at

Key generation for AES-GCM-256 file encryption

I'm currently working on a file encryption software. In the above thread it was suggested that, for performance reasons, I use a combination of scrypt and HKDF.

But how should I go about using HKDF to derive a new key for each file? As suggested in the above thread, I intend to produce a single master key via scrypt and from that I want to derive file encryption keys via HKDF.

So far I have come up with two possible ways of doing this:

(1) Run HKDF (extract-then-expand) with the scrypt result as input key material (ikm) and a NEW random salt for each file to be encrypted

(2) Run HKDF (extract-then-expand) with the scrypt result as ikm, a FIXED random salt, and a random 'info' value for each file to be encrypted

Which - if any of these - is the better or correct way of doing what I want? As I understand it, NIST Special Publication 800-56C, explicitly dsicourages re-using the same ikm and just varying the salt. But I don't exactly understand why and their use case (shared secret Z as ikm) is different from mine.

The salt is not required to make HKDF secure. Using a static salt doesn't make too much sense - you should be perfectly fine with using an empty salt. Either you can use an empty salt, or a new random salt. This salt could be generated and prefixed per file. If it is large enough (say 128 bytes) then it would make each encryption key unique so you don't have to depend on filename or other meta information (that could be part of Input) to derive the file encryption key.

The salt makes the HKDF function easier to proof, but I haven't heard on any attacks on KDF's without it - including those that directly use a hash function while they should not.

There is little need to perform the extraction of key material from the output of scrypt. Basically you can already create a key from the output of scrypt. So there is no need to derive the pseudo-random key (PRK) for using HKDF-extract. That way you should be fine with just applying HKDF-expand, making the calculations slightly less computationally intensive.

So you would have:

IKM = scrypt(password, salt1)
K = HKDF-expand(IKM, Input, 256)

where Input is any canonically encoded information that defines the file to be encrypted.

You could also go for:

IKM = scrypt(password, salt1)
PRK = HKDF-extract(IKM, salt2)
K = HKDF-expand(PRK, Input, 256)

In this case Input can even be empty if salt is random enough. The salt can be stored (prefixed) with the encrypted file.

Note that salt1 is used for scrypt which according to the org. answer of your previous question should only be used once. Therefore it cannot be used for HKDF.

  • I don't see any actual problem with having salt1 and salt2 be the same, although there's also no reason to do it (or, indeed, to use HKDF-extract after scrypt at all). – Ilmari Karonen Nov 19 at 7:49
  • @Ilmari Karonen: Salt1 and salt2 can't be the same because I need an individual key for each file that is to be encrypted. Hence I have one master key (the scrypt result) and from that I intend to derive various file encryption keys. So if salt1 and salt2 were the same I'd still have to throw in an indiviual 'info' value (or 'input' value as Maarten Bodewes named it) per file. – FineJoe Nov 19 at 8:44
  • @Maarten Bodewes: Regarding the second variant you described: As I pointed out, in NIST 800-56C it says on page 12 that the IKM is only to be used once - and zeroized immediately after use. Why? Also, seems to suggest that the IKM should not be re-used. I'm a bit confused. – FineJoe Nov 19 at 9:04
  • Please provide a direct quote and a complete reference including a section indication within the correct version of that standard. I cannot be asked to look up a document, hope that it is the correct version and then try and lookup some generic phrase on a page that may or not be using the actual page number or the number in the PDF document. – Maarten Bodewes Nov 19 at 10:30
  •… -page 12 "In the extraction step, the following notations are used. [...] Z – A shared secret established during an execution of an approved public key-based key establishment scheme. It is represented as a byte string and used as the “message” in a MAC execution in the randomness extraction step. Each call to the randomness extraction step requires a freshly-computed shared secret Z, and this shared secret shall be zeroized immediately following its use in the extraction process." – FineJoe Nov 19 at 10:48

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

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