[noise] What needs forward secrecy? (for Disco)
trevp at trevp.net
Tue Nov 21 11:08:30 PST 2017
On Mon, Nov 20, 2017 at 5:58 PM, David Wong <davidwong.crypto at gmail.com> wrote:
>> Noise certainly considers the security properties of individual
>> handshake messages to be important (e.g. tables in section 7.4 and
>> 7.5). It's totally plausible that an application could care about
>> forward-secrecy of, say, 0-RTT data, when considering a compromise
>> later in the handshake.
> The Split() function introduces forward secrecy with the RATCHET()
> function. Would this be enough for 0-RTT? It's certainly enough for
> other scenarios.
There are cases where you might care about forward secrecy for
encrypted data and key compromises that occur entirely during the
handshake phase, before Split().
In your favor: In most patterns both parties use their ephemeral
private key during the last handshake message they handle before
calling Split(), so it's not possible for them to delete their
ephemeral private key earlier for forward-secrecy. So you're right
that it would *often* be sufficient to only require Split() to delete
old keys, and not MixKey().
However, there are other cases:
* With a PSK modifier like "psk0", the initiator could normally
delete the PSK after sending her first message, and would then get
forward-secrecy for the initial payloads.
* We've considered a "sig" modifier which replaces "es" and "se" with
signatures from the static key. This would allow the ephemeral
private key to be deleted earlier, giving forward-secrecy to earlier
* We've considered "hybrid forward secrecy" which adds an additional
set of "ephemeral private keys" that are used for "ee"-type operations
but not for "es"/"se" authentications - thus these hybrid private keys
could be deleted earlier, for forward secrecy.
* There's nothing that currently requires patterns to use the
ephemeral private key in the final message, so there could be patterns
like below, where the ephemeral private keys can be deleted earlier:
<- e, ee
<- s, psk
We could try to distinguish all these cases and have two different
modes for MixKey(), but that seems very complicated for a tiny
There are other reasons to prefer a consistent/conservative MixKey():
* The KDF has to be secure when given a single good input, even if
all other inputs are malicious. For example, maybe you're given a
malicious PSK, or maybe someone sends you a malicious ephemeral public
key, to try somehow "cancel out" the "es" or "se" DH that performs
Having "lots" of hashing between different KDF inputs might protect
them from such malicious interactions, even if the hash has
weaknesses. This is one reason we're OK with HMAC/HKDF, though we've
fielded similar complaints that they are"overkill" in the KDF.
Also, I think things are easier to analyze if they are consistent. In
this case, if we always RATCHET in MixKey, then every new KDF input
gets processed in the same way, using the same part of the permutation
We've recently seen libhydrogen experiment with the Gimli permutation.
IIRC, there was some debate between DJB and Mike Hamburg regarding
whether it was fair game for cryptanalysis to consider the key placed
in different parts of the permutation.
While I thought Mike was right, it also seems more conservative and
simpler to analyze if we use the function in such a way that the key
material is always at the same location.
So for those reasons, I think Disco should provide the same semantics
as current MixKey (deleting old key material), and use the same
operation for all MixKey() steps, like current Noise.
More information about the Noise