I want to derive session keys for many clients from a Master Key. Suppose I derive a key for the client $n$ in the following way:

master_key = HKDF-extract(salt, IKM)

key_client_n = HKDF-expand(master_key, info_client_n, L)

Then, I generate session keys for the client $n$:

key_client_n_session_0 = HKDF-expand(key_client_n, 0, L)

key_client_n_session_1 = HKDF-expand(key_client_n, 1, L)

Is that safe? Is it a correct way to use HKDF? I am concatenating two stages of expansion to generate session keys.


1 Answer 1


Is that safe?

Safe is something that applies to systems, not algorithm use alone.

Is it a correct way to use HKDF?

That seems to be the case yes.

the HKDF RFC specifies the Info parameter as a string, by which they mean an octet string. Currently you've specified a number value. However, you should also specify a way to convert that to an octet string.

You haven't specified the info encoding but that's not hard, you could e.g. use "client" | 64 bit client number for client keys and "session" | 64 bit client number for the session keys. The labels "client" and "session" can be encoded using ASCII. The number could be encoded as a 64 bit unsigned value in network order.

Quite often we use multiple session keys, e.g. one for sending and one for receiving, and possibly one for MAC generation or key confirmation (validating that both sides have the expected key without having to send a particular message, e.g. a MAC over a session transcript). You could add some context for that as well, e.g. "session_send" and "session_receive" (etc.) instead of the current labels.

The size should obviously be linked to the possible number of clients and / or sessions. That requires protection against an adversary being able to deliberately increase the session counter though; a 64 bit or larger value would require fewer assumptions about security.

So although not incorrect, I would not deem it complete.

I am concatenating two stages of expansion to generate session keys.

That's fine in general.

For a system it could make more sense to use e.g. double ratcheting as to provide forward security in addition to dependence of keying material.

  • $\begingroup$ Hi @Maarten Bodews, thanks for answering. So, could I use info parameter in first expansion an ASCII string "client 5" to derive the key for the client number 5? And, could I use an unsgined 64 bit number as info in second expansion to derive session keys for that client? $\endgroup$ Commented Apr 18, 2023 at 18:07
  • $\begingroup$ I'd keep it to 5, and put the "client" part into the label. The label already delivers domain separation, no need to put it in the context as well. Of course, you'd also need to define some way of encoding that value, e.g. reuse the same method as for the other number encoding. In the end everything goes into HMAC, so as long as key, context & label are unique... $\endgroup$
    – Maarten Bodewes
    Commented Apr 18, 2023 at 18:12
  • $\begingroup$ Hold on, I'm making a mistake, the extract uses L for length instead of label. Ugh. $\endgroup$
    – Maarten Bodewes
    Commented Apr 18, 2023 at 18:16
  • $\begingroup$ Bodews Yes, first expansion uses info_client_n as info and L as L (using RFC notation). Second expansion uses 0, 1, ... as info and L as L. Am I missing something? $\endgroup$ Commented Apr 18, 2023 at 18:25
  • $\begingroup$ As indicated, you need to convert it to octet strings. I'm slightly partial to using binary encoding for numbers, but using info_client_n where n is any number and encoding in ASCII is fine as well. As long as you clearly define it and the total encoding is unique. $\endgroup$
    – Maarten Bodewes
    Commented Apr 18, 2023 at 19:04

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.