[noise] Deriving resumption PSKs (was: SAS (was: Explicit nonces (for lossy transports))

Trevor Perrin trevp at trevp.net
Wed Jul 12 20:26:30 PDT 2017

I think we're mostly talking about resumption now (?), so I re-titled this:

On Wed, Jul 12, 2017 at 10:20 PM, Rhys Weatherley
<rhys.weatherley at gmail.com> wrote:
> On Wed, Jul 12, 2017 at 6:44 PM, Trevor Perrin <trevp at trevp.net> wrote:
>>  (B) One party can just transmit a PSK to the other.
> My concern with transmitting the PSK's is that they are no longer "mutual" -
> the sending party solely determines the value.

That's true, you could call this a "contributory" vs "non-contributory" PSK.

I'm unsure how much contributoriness gets you here:

It's probably common to send a PSK shortly after the handshake, so if
the sender's RNG is bad for generating the PSK it's probably also bad
during the handshake.  Many patterns rely on a good ephemeral to
authenticate the other party, so with a bad RNG (=bad ephemeral) the
other party can be impersonated to steal PSKs anyways.

>  And if that party's random
> number generator has become borked (e.g. accidentally or deliberately
> outputting all-zeroes), then the PSK value is essentially in the clear as
> the transmitted ciphertext.
> What about this: modify Rekey() to return 64 bytes instead of 32.  The first
> 32 are used as the new transport key, and the second 32 can be exported from
> the protocol as a PSK if the protocol needs a PSK at that point.  If the
> protocol requires multiple PSK's, it can Rekey() multiple times before
> continuing with data transport.

Deriving resumption PSKs via rekey seems complicated to implement.
Suppose the server is sending a bunch of resumption PSKs and
associated session IDs or session tickets.  Where exactly in the
stream does it do the rekeys?  How does it signal this to the lower
layer Noise code?

On the receiving end, you can no longer have a Noise layer just
decrypting messages and providing a byte stream to the application.
The application will need to peek at the stream until it figures out
where exactly the rekeys are, then tell the Noise layer.

What we could do is say that the underlying rekey mechanism should be
able to return an extra key-derivation key (KDK), as you describe.
This wouldn't affect the existing API, it would just say that
internally you could encrypt 64 bytes of zeros instead of 32, and use
the second key as a "KDK".

You could use KDK with different nonces to output "KDK-derived" keys
for different purposes.

Then we could define resumption PSKs as explicitly-transmitted,
"non-contributory" PSKs, but recommend that they are derived by
HMAC'ing a secure random value with a KDK-derived key.

So we'd be recommending implementations get the benefits of a
"contributory" key, but we wouldn't be enforcing this in the protocol,
to keep it simple.


My previous email mis-stated something about resumption.  I think
resumed sessions should use the original session's static public key
as prologue, not the original session's handshake hash.  This doesn't
require per-client server state (at most, it might require the server
to remember old static public keys).

Putting this all together:  In addition to our current option of 0-RTT
based on server static, we'd have 2 more options:
 * A server could transmit resumption PSKs (+ session IDs or session
tickets), and/or
 * Semi-ephemeral public keys (as in QUIC).

The client could use these transmitted values for 0-RTT resumption
just by identifying the session ID, session ticket, or ephemeral
public key (e.g. in the negotiation_data), along with the server's
static public key, then using the server's static public key as

What do people think of that?


More information about the Noise mailing list