[noise] Pre-shared Secret - preventing DoS, and ensuring post-quantum PFS

Jason A. Donenfeld Jason at zx2c4.com
Wed Nov 11 14:26:09 PST 2015


On Wed, Nov 11, 2015 at 10:16 PM, Trevor Perrin <trevp at trevp.net> wrote:
>  * A Noise handshake specifies a fixed sequence of MixKey / MixHash
> steps, so we can't add an optional MixKey to a handshake.  This would
> require either specifying "preshared_key" versions of the handshakes,
> or always performing an extra MixKey().

Why would optional be bad? The idea would be - if both parties a) know
to use a pre-shared key and b) use the same pre-shared key, their
handshakes will be successful. Otherwise, they're not legitimate.


>  * h is intended to bind *all* previous data, but also to be
> non-secret, so we'd need to MixHash() some value derived from the
> pre-shared key.

I had feared this. So in that case what about: "If a pre-shared key is
provided, in Initialize, call MixKey(psk) followed by MixHash(psk)."
Off-hand, I can't imagine any reason why this would leak anything
important.


> So instead of a pre-shared symmetric key, the parties could use
> pre-shared ephemeral public keys, and you could augment any handshake
> to a "pse" version like this:
>
> Noise_IK_pse(s, rs):
>   -> e
>   <- s, e
>   ------
>   -> dhee, e, dhes, s, dhss
>   <- e, dhee, dhes

In this version, is the pre-shared ephemeral "e" a different "e" (say,
e prime) than what's later exchanged? In other words, do you mean
this:

  -> e'
  <- s, e'
  ------
  -> dhee, e, dhes, s, dhss
  <- e, dhee, dhes

But this has a major problem. From the spec:

    "Calls MixHash() once for each public key listed in the pre-messages
    from new_handshake_pattern, passing in that public key as input"

Since only MixHash() is called on each pre-shared ephemeral, the
pre-shared ephemerals do NOT become part of the symmetric encryption
key. The symmetric encryption key, then, is still derived from only
diffie-hellman results, the public keys for which are shared through
the wire. This means PFS is broken if the DH function is broken
(post-quantum, better rho, other DH weaknesses...), which is the
precise threat model I wanted to protect against. If all our traffic
is logged, I don't want it to be decryptable in the future.

In order for this to work, pre-shared non-DH results need to be mixed
into the symmetric key used.


> Trevor

There's also my second concern:

> > 2. If a pre-shared secret is provided, the first unencrypted public key written receives a MAC (using hmac or keyed-blake2) using the pre-shared secret.
> > This provides DoS defense, so that an attacker can not force a server to compute any DH operations, unless he has the pre-shared secret. Without this mitigation, Noise is very very DoS-able.

DH is expensive; the denial-of-service situation is real. It would be
nice to have a cryptographic solution for this (i.e. not token
buckets).

A weaker form than what I've proposed here with the pre-shared key is
to simply use the recipients public key as a key for a MAC over the
whole message. That way, at the very least, it's not DoS-able by
random third parties, but rather people who already know who they're
talking to.

What do you think of this?


[Or, sticking with the pre-shared key concept, if you're against MACs,
here's a flawed idea: authenticate-encrypt (or just authenticate) the
first ephemeral key using the current 'k'. And make that 'k' depend on
the pre-shared key, as discussed above. That way, there's a Poly1305
authentication that has to occur before a DH occurs. Big big big flaw:
this would result in key-reuse in catastrophic ways. I guess we could
introduce a random salt to mix in. Or adopt XChaCha20 with a massive
nonce, or... Well, things get more complicated I guess. I don't have a
solution to simplify it from there, except going back to my original
idea of a simple MAC (hmac or keyed blake).]


More information about the Noise mailing list