[noise] Resumption PSKs

Christopher Wood christopherwood07 at gmail.com
Tue Jun 12 09:13:24 PDT 2018


On Fri, Jun 8, 2018 at 9:23 PM Trevor Perrin <trevp at trevp.net> wrote:
>
> On Thu, Jun 7, 2018 at 3:54 PM, Christopher Wood
> <christopherwood07 at gmail.com> wrote:
> >
> > In both examples, you note that Split() is always invoked. I
> > envisioned the new function being called in lieu of Split(), since
> > Split() does not modify the SymmetricState (right?).
>
> Implementations are likely to delete the HandshakeState (including the
> SymmetricState) after calling Split(), the spec touches on that:
>
> """
> Processing the final handshake message returns two CipherState
> objects, the first for encrypting transport messages from initiator to
> responder, and the second for messages in the other direction. At that
> point the HandshakeState should be deleted except for the hash value h
> [...]
> """
>
> Holding onto ck would defeat the forward-secrecy benefits of rekey,
> and wastes space if you don't need additional keys.
>
> Implementations might hold onto ck, after Split(), only if they
> thought additional keys would be needed.  But if they knew that at the
> time of Split(), they might as well create the additional keys at that
> point.  So I still think having the labels as an additional argument
> into Split() makes sense.

Good point! I missed the bit about deleting the handshake state.

> ---
>
> However, you've highlighted the case where the transport keys aren't
> needed at all, and only additional keys are used.  In that case, my
> sketch starting this thread would be suboptimal, because it would have
> to generate the first two HKDF outputs (the transport keys) before it
> could generate the output needed for additional keys, since HKDF uses
> every output to generate the next output.
>
> To allow an optimization in the case where only additional keys are
> needed, maybe instead of this:
>
> transport1, transport2, K = HKDF(ck, zerolen, 3)
> additional1 = HMAC(K, label1)
> additional2 = HMAC(K, label2)
> ...
>
> We could do something like this:
>
> transport1, transport2 = HKDF(ck, zerolen, 3)
> additional1 = HMAC(ck, label1)
> additional2 = HMAC(ck, label2)
> ...
>
> Where labels are required to be non-zero-length.
>
> Slight variations would be to replace HMAC -> HKDF, or HKDF with
> info=label (we don't use the info label currently, so I'm not sure we
> should start, but it would be a little more efficient.

This optimization is nice. However, I still think there's room to
improve from an API perspective. Assuming
implementations discard the handshake state after calling Split and
also have access to a PRF, what if we did this:

~~~
  transport1, transport2, K = HKDF(ck, zerolen, 3)
  c1, c2 = CipherState(transport1), CipherState(transport2)
  tk = HMAC(K, h)
  delete ck
  return c1, c2, tk
~~~

Applications could then derive whatever keying material they wanted
from the third output -- tk -- independently
from c1 and c2. Applications which don't want this can simply toss it,
much like apps that don't need both CipherState
objects will do. Of course, punts additional key derivation
responsibility to the application. Provided we describe how
additional keys are derived, e.g., HMAC(tk, label), this seems fine.

What do you (all) think? For what it's worth, I see little difference
between this and the original proposal (where Split()
accepts labels), so I could go either way. I'm just trying to make
sure we cover the design space.

Best,
Chris


More information about the Noise mailing list