[noise] Heresy: PSK-only Noise

Rhys Weatherley rhys.weatherley at gmail.com
Thu Jun 7 12:26:33 PDT 2018


I've done a lot with Arduino-based embedded devices and my Arduino
Cryptography Library.  I'm currently working on Noise and NoiseLink for
such devices.  Early days yet - it will take some time to come to fruition.

In the low end space, it is common for devices to lack sufficient memory or
CPU resources to implement DH functions like Curve25519.  Symmetric crypto
and PSK's are fine, but DH is too resource-intensive.  ARM devices can
usually handle it, but AVR devices no.

This begs the question: What is the best way to encrypt packets when
resource limitations preclude the use of public key cryptography?  People
who have used my library invariably invent some scheme using CBC mode and
shared secrets.  Usually by directly encrypting with the shared secret
itself, which is very bad.

It would be nice if I could recommend something better than "roll your own"
and perhaps include it in my library.  So, here is a heretical proposal for
a PSK-only encryption scheme that works within the Noise framework.

A new DH algorithm called "None" is added which only operates with
ephemeral keys:

    DHLEN = 32

    GENERATE_KEYPAIR(): Generate a random 32-byte value v and then set
    k to the first 32 bytes of HASH(v).  Return the pair (k, k) to the
    caller for the public and private components (the private component
    is essentially useless).

    DH(key_pair, public_key): Returns an empty byte sequence to the caller,

The "None" algorithm must be used with PSK-based patterns and the "psk"
token must appear in the pattern before the first "e" token.  Given that
"None" does not support static keys, the only pattern of interest is
"NNpsk0":

    Noise_NNpsk0_None_ChaChaPoly_BLAKE2s
    Noise_NNpsk0_None_AESGCM_SHA256

Together with the use of PSK's, the "e" token for each party becomes:

    v = a new random 32-byte value
    k = the first 32 bytes of HASH(v)
    Append k to the buffer
    MixHash(k)
    MixKey(k)
    discard k and v

The "ee" token stirs the chaining key state but otherwise does nothing:

    MixKey(empty)

An alternative is to simply delete the "ee" token from the pattern when
"None" is specified.

Technically the HASH(v) step is not required, but it provides some
protection against poorly implemented RNG's or hardware RNG's that may have
been backdoored by the CPU manufacturer.  The raw RNG output is hashed
again to destroy watermarks or low-entropy patterns in "v".  There's no way
for the receiver to verify that HASH(v) has been done however.  If the
implementer knows that the underlying RNG is already hashing away
watermarks, then the HASH(v) step can be omitted.

The "ephemeral keys" act as nonces to randomize the keys in each new
session.  If one of the parties has a poor random number generator, then
the randomness from the other party will have to pick up the slack.  In
embedded environments, one party is often a desktop or smartphone client or
a phone-home server with a full desktop-level RNG.  Peer-to-peer sessions
between devices may be a problem unless one of them has a hardware RNG.

I also considered introducing a "n" token for generating nonces and then
use a pattern modifier to replace "e" and "ee" tokens.  That leads to odd
names:

    Noise_NNheresy+psk0_25519_ChaChaPoly_BLAKE2s

With a modifier, we still need a real DH algorithm name, but the algorithm
is effectively erased by the modifier.  Introducing a new DH name was
cleaner.

Possible alternative names for "None": "Nonce" or "Heresy" or "NoWayRhys"
:-)

Thoughts?

Cheers,

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


More information about the Noise mailing list