3

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.

Ilmari Karonen
  • 46,120
  • 5
  • 105
  • 181
FineJoe
  • 71
  • 7

1 Answers1

4

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.

Maarten Bodewes
  • 92,551
  • 13
  • 161
  • 313
  • 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 '18 at 07: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 '18 at 08: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, https://crypto.stackexchange.com/a/59070/56772 seems to suggest that the IKM should not be re-used.

    I'm a bit confused.

    – FineJoe Nov 19 '18 at 09: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 '18 at 10:30
  • https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-56c.pdf -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 '18 at 10:48
  • I do realize scrypt is not a "public key-based key establishment scheme" but I wonder whether the restriction of using a NEW ikm per HKDF-extract call applies to my use case, too. – FineJoe Nov 19 '18 at 10:52
  • Ah, OK. Yes, if you need more than one key you can call HKDF-expand multiple times, possibly putting the salt within the Info parameter. That only applies to the extract phase after all. And yes, if you use any input key material correctly you should destroy (zeroize) the key as soon as you don't need it anymore. What it does not or should not indicate is that you cannot use the same input material as input to a KDF. In that case you could not separately derive two keys, e.g. one for encryption and one for authentication. – Maarten Bodewes Nov 19 '18 at 11:45
  • @Maarten: Well, but the above document makes this point about HKDF-extract. Also, please again take a look at https://crypto.stackexchange.com/a/5356/56772, expecially the 2nd comment (by David Cash). Do you share his concerns? – FineJoe Nov 19 '18 at 11:55
  • After all this, you still think the following is safe?

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

    (with Input = Null)

    – FineJoe Nov 19 '18 at 11:55
  • Absolutely, especially since you're first using a password (which you should zero as well). Regardless of the salt, the HKDF part will be much stronger than the password in scrypt (or one of the Argon2 alternatives). I'd rather focus on implementation details such as making sure that the password is strong enough and removing the key material from memory. Beware of the birthday problem when determining the salt size (think about the security strength in bits and then double it). – Maarten Bodewes Nov 19 '18 at 13:27