[noise] Notes and thoughts from RWC2017

Rhys Weatherley rhys.weatherley at gmail.com
Mon Jan 16 11:21:06 PST 2017


On Tue, Jan 17, 2017 at 4:19 AM, Trevor Perrin <trevp at trevp.net> wrote:

> They basically separate the chaining key (ck) into 2 separate ck, and
> do periodic HKDF updates to get a new ck, k.  That's a secure design
> (assuming HKDF is a PRF), and nicely reuses the HKDF key chain.
>
> It does mean storing two extra ck values during the transport phase.
> The Noise spec reserved the high nonce value, with the alternative
> idea that we could generate extra secret values from that, if needed
> (key updates, resumption PSKs, or a catch-all like TLS exporters).
>

I like the Lightning method too.  My Rekey() function suffers from
roll-forward problems: if the key for a segment of the session data is
compromised, then all future segment keys can be easily re-computed.  And
if the encryption algorithm becomes vulnerable to a known-plaintext attack
in the future, the segment keys can theoretically be rolled backwards.
Oops.

Lightning's use of an extra chaining key and HKDF fixes these problems in a
fairly elegant way.  At the cost of some extra state for a direction:
HASHLEN bytes for ck and 32 bytes for k.  The main issue I have is the need
to store the raw k value between segments.  With the current Noise design,
the k value can be discarded after the call to InitializeKey() because it
has been transformed into a key schedule.

Before looking at the Lightning spec, I was thinking of ways to fix
Rekey().  The best I came up with was to generate a secret value during
Split() that was combined with the output of EncryptWithAd() using HMAC or
HKDF to generate the new encryption key.  Essentially this secret value
would play the same role as the rolling ck' values in Lightning.

The two methods could be combined as follows:

Split():
  - k1, k2 = HKDF(ck, zerolen)
  - s1, s2 = HKDF(ck, onelen)   // onelen is a 1 byte sequence of zeroes

Rekey(s):  // secret value for this direction, either s1 or s2
  - temp is set to the output of encrypting a block of zeroes with
EncryptWithAd() and the special 2^64 - 1 nonce.
  - s, k = HKDF(s, temp)
  - InitializeKey(k)

Each direction needs an extra HASHLEN-sized "s" value in the permanent
state to assist with key rotation.

Cheers,

Rhys.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://moderncrypto.org/mail-archive/noise/attachments/20170117/f65c782d/attachment.html>


More information about the Noise mailing list