[noise] Semi-ephemeral patterns

Trevor Perrin trevp at trevp.net
Sat May 14 10:50:36 PDT 2016

We previously had 4 patterns where the initiator had pre-knowledge of
the responder's "semi-ephemeral" public key, e.g.:

Noise_NE(rs, re):
  <- s, e
  -> e, dhee, dhes
  -> e, dhee

We removed them temporarily because they were a lot to think about:

But semi-ephemerals are potentially useful for zero-RTT encryption,
since some servers might be able to change their semi-ephemeral key
more frequently than their static key.

Semi-ephemerals add complexity since the server has to manage a new
set of keys and the client has to acquire and authenticate the public
keys.  But they reduce the impact of server compromise on data
exchanged in the first round-trip (better forward-secrecy and

The older _E patterns were (arguably) too complicated.  They included
an ephemeral-static DH with the server's static, which is only useful
if either:
 (1) The responder's semi-ephemeral private key might be compromised,
but not their static private key
 (2) The initiator might possess an incorrect semi-ephemeral public
key for the responder

In practice:
 (1) Static and semi-ephemeral private keys are probably stored in the
same place (e.g. if the responder has an HSM for the static private
key, it could keep the semi-ephemeral private key there too).
 (2) The initiator retrieves the semi-ephemeral signed by the static
key, or retrieves the semi-ephemeral over a connection authenticated
by the static key.

Also, expiration could limit the risk of (1) or (2).

If we skip re-authenticating the server static we get simpler _E
patterns that are very similar to the _K patterns:

Noise_NK(rs):         Noise_NE(rs, re):
  <- s                  <- s, e
  ...                   ...
  -> e, dhes            -> e, dhee
  <- e, dhee            <- e, dhee

Noise_XK(s, rs):      Noise_XE(s, rs, re):
  <- s                  <- s, e
  ...                   ...
  -> e, dhes            -> e, dhee
  <- e, dhee            <- e, dhee
  -> s, dhse            -> s, dhse

Noise_KK(s, rs):      Noise_KE(s, rs, re):
  -> s                  -> s
  <- s                  <- s, e
  ...                   ...
  -> e, dhes, dhss      -> e, dhee, dhse
  <- e, dhee, dhes      <- e, dhee, dhes

Noise_IK(s, rs):      Noise_IE(s, rs, re):
  <- s                  <- s, e
  ...                   ...
  -> e, dhes, s, dhss   -> e, dhee, s, dhse
  <- e, dhee, dhes      <- e, dhee, dhes

One subtlety is that the _E patterns treat the server static as a
pre-message, even though it's not used for DH.  This is to prevent
identity misbinding where an attacker presents a victim's
semi-ephemeral public key as the attacker's own.

Arguably we could just use the _K patterns with semi-ephemeral keys by
treating the semi-ephemeral as a static and binding the "real" static
into the prologue, but I think that's confusing.

The other way around might be more useful:  _E patterns could be used
for _K by setting the semi-ephemeral equal to the server's static.

For example, you could have a Noise Pipe variant using XX and IE
instead of XX and IK.  During the XX connection, the server would send
its semi-ephemeral to the client, which would cache it and reuse it
for IE resumptions.  If the server doesn't want to manage extra
semi-ephemeral keys, it can just send its static public key in place
of the semi-ephemeral, and the IE handshake becomes identical to IK.

So client behavior is identical, whether servers use semi-ephemerals or not.

Anyways, I'm thinking of adding these as the mainline semi-ephemeral
patterns.  Of course, you could add an extra DH with the server's
static if you want, but those would be alternate patterns we stick in
an appendix or something.


More information about the Noise mailing list