[noise] Resumption PSKs

Christopher Wood christopherwood07 at gmail.com
Thu Jun 7 08:54:21 PDT 2018


On Thu, Jun 7, 2018 at 12:02 AM Trevor Perrin <trevp at trevp.net> wrote:
>
> On Tue, Jun 5, 2018 at 2:38 PM, Christopher Wood
> <christopherwood07 at gmail.com> wrote:
> > On Tue, Jun 5, 2018 at 2:02 AM Trevor Perrin <trevp at trevp.net> wrote:
> >>
> >> On Mon, Jun 4, 2018 at 3:00 PM, Christopher Wood
> >> <christopherwood07 at gmail.com> wrote:
> >> >
> >> > Would it not be cleaner to move this export functionality to a
> >> > different API? For example, one could specify an explicit Export() API
> >> > that functions precisely as you describe above, with the exception
> >> > that CipherState objects are not returned.
> >>
> >> Hi Chris,
> >>
> >> The issue is that the transport keys and these new "key chains" have
> >> to be created at the same time, so that the value used to derive them
> >> (the chaining key ck) can be deleted afterwards.
> >>
> >> Put another way: a goal is that additional key outputs are independent
> >> from each other and from the parent session's keys, at any point in
> >> time ("independent" in the sense that none of these keys can derive
> >> the others).
> >>
> >> Thus we're avoiding designs where the parent session would hold a
> >> single long-lived key and repeatedly produce outputs from it.
> >
> > It seems as though one can accomplish this by generating the transport
> > and key chains at the
> > same time (from ck) and then simply discard both ck and the transport
> > keys.
>
> I think that's true even if you don't discard the transport keys
> (because they were generated to be independent from the key chains).

Yep, that seems correct.

>
>
> > I'm not advocating
> > for an API that allows clients to pump out keying material
> > indefinitely from the same root. I was
> > just hoping to avoid overloading an already well-defined and clearly
> > specified API.
>
> Makes sense as a goal, but if you don't want to change Split()'s
> interface, I think the options are:
>
> (A) A function that can be called multiple times, after Split(), to
> create new key chains or additional keys.  This probably requires
> storing a single key and deriving from it repeatedly, thus defeating
> the key-independence / forward-secrecy goal.
>
> (B) A function that can be called once after Split() to create a new
> set of key chains, by deriving them from an extra key that is then
> destroyed.  This wouldn't change the underlying crypto, but it would
> mean that uses of Split() that don't require this extra key would have
> to derive and store it, in case this later function was called.
>
> Since changing Split() to take additional optional arguments is just a
> notation / API thing, it seems better than these alternatives which
> would have actual downsides in security properties or efficiency.

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?). From the spec, it
only seems to be called when message patterns are finished.
Applications call this as needed during the handshake. At the end of
the handshake, they may call Split() to get CipherState objects for
encrypting/decrypting transport data, or, as suggested, get derived
keys to use for other purposes.

For clarity, below is what I think you proposed. Please correct me if
it's wrong!

~~~
Split(labels [][]byte) {
  Sets temp_k1, temp_k2, temp_k3 = HKDF(ck, zerolen, 3)
  If HASHLEN is 64, then truncates temp_k1, temp_k2, temp_k2 to 32 bytes
  Creates two new CipherState objects c1 and c2
  Calls c1.InitializeKey(temp_k1) and c2.InitializeKey(temp_k2)
  Create list `keychains` that stores label keys
  For each label_i = labels[i], create ck_i = HMAC(temp_k3, h ||
label_i), and set keychains[i] = ck_i
  Returns list (c1, c2, keychains)
}
~~~

Here's what I was proposing:

~~~
Split() {
   // Same as today
}

Foo(labels [][]byte) {
  Sets temp_k1 = HKDF(ck, zerolen, 1)
  Create list `keychains` that stores label keys
  For each label_i = labels[i], create ck_i = HMAC(temp_k1, h ||
label_i), and set keychains[i] = ck_i
  Returns keychains
}
~~~

At the end of the day, this boils down to cleanliness of the API, I
think, so this distinction is likely not critical. I do think it's
worth considering, though.

Best,
Chris


More information about the Noise mailing list