[noise] NoiseLink questions

Rhys Weatherley rhys.weatherley at gmail.com
Sun Jul 1 15:31:14 PDT 2018


On Sun, Jul 1, 2018 at 3:38 PM, Trevor Perrin <trevp at trevp.net> wrote:

> My hope is that code-generators could combine the flexibility of
> names/patterns/modifiers with simple/auditable outputs.  Someday!
>

Yes, someday.

>
>
> > I have now begun work on NoiseSocket and NoiseLink and have a few
> > observations / questions.  Apologies if these issues have already been
> > raised previously.
>
> Nope, this is great - these are untested and unstable specs in
> desperate need of feedback...
>
> (Also, Gerardo and I are discussing this renaming, if you have opinions:
>
> https://moderncrypto.org/mail-archive/noise/2018/001594.html
> )
>

It would be nice if there was a uniform set of tags so that 4 doesn't mean
different things in different contexts.  But I can live with it the way it
is.

The only "wart" I've found is "string rejected_protocol = 5" in
NoiseLingoNegotiationDataRequest and "bool rejected = 5" in
NoiseLingoNegotiationDataResponse.  The tag numbers and field types are
otherwise identical between request and response.  The change in type for
tag 5 struck me as odd.


> > Section "2.3 Encrypted Payloads" of NoiseSocket is a little unclear as to
> > the handling of cleartext payloads in handshake messages.  Should they
> also
> > have a body_len and padding, or should they be omitted?
>
> Only encrypted payloads should have those things (for padding).
> [...]
> You want padding, even for cleartext payloads?  Seems like a slight
> waste of bytes.  I assume implementations can combine decryption with
> de-padding, and that's clean enough?
>

The issue is one of payload formatting: knowing ahead of time to add the
body_len prefix to the payload when the payload is encrypted, but leave it
off if the payload is cleartext.  I think I've come up with an API solution
with an extra parameter to WriteMessage()/ReadMessage() to indicate "apply
length prefix and padding if the payload is encrypted, or encode as literal
if cleartext".

Maybe this needs to be thought about in the core Noise specification:
applying a conditional padding transformation to the payload before calling
EncryptAndHash().

> Only NoiseTinyLink appears to allow transport options to be negotiated,
> but
> > not full NoiseLink.  How do I select continuous rekey in the full
> protocol
> > for example?  Or negotiate smaller packet lengths?
>
> As of now, you don't.  NoiseLink was intended as a simple starting
> point for Internet protocols.  You could modify the NoiseLink profile
> to include those things if you need them, but your typical Internet
> protocol doesn't.
>

OK.  If the feature can be asked for, then it isn't a drama.  See below.

  * BLAKE2s: was specified for NoiseTinyLink, but not NoiseLink.
> Rationale was that SHA256 is everywhere, so it makes sense for
> Internet devices.  For tiny devices maybe the efficiency advantage of
> BLAKE2 would make a difference.  But on considering this, I'm not sure
> it's worth it.  There are better symmetric-crypto optimizations we
> could do for small devices (non-HMAC/HKDF; unifying the ck and h
> chains; coalescing repeated MixHash inputs into a single hash block;
> Keccak/STROBE/Disco etc).  So maybe we should just stick with SHA256
> for the default profiles, until we've spec'd these other things.
>

BLAKE2s has a speed advantage over SHA256 when there's no hardware
acceleration available.  Memory space is identical in small-footprint
configurations.

Since both MD5 and SHA-1 fell to attacks, I've been looking to get away
from that family wherever possible.  Same with AES frankly - timing attacks
are hard to avoid without trusting your privacy to a black box in-CPU
crypto accelerator, so I usually say "No sboxes!  It's the law!".

As for Keccak and friends - slow.  I'd look at the finalists in the CAESAR
AEAD competition instead for a Disco-style replacement.  ACORN128 is
freaking incredible in terms of speed and memory footprint.


> > Negotiation of max_send_length and max_recv_length is a little fuzzy.
> The
> > simplest interpretation is "if my send length is greater than the other
> > party's receive length, then reduce my send length so as not to overflow
> > their receive buffer".  In fact, I think only one buffer size on each end
> > needs to be negotiated.  I would reduce it to max_recv_length only with a
> > policy of "don't send me transport messages larger than this or I'll cut
> you
> > off".
>
> That's true; if you advertise a max_send_length the receiver can
> allocate a smaller buffer, but maybe that's not worth the effort.  We
> could take it out of NLS entirely, or just not use it in the default
> profiles?
>

Leave it in for now - at the moment I'm allocating buffers before the
session starts so as to reduce the likelihood of a failed memory allocation
mid-session.  But another implementation might find it useful to reclaim
the memory if it isn't needed.

This bring up another problem w/TransportOptions:  There's no way to
> advertise/negotiate which options you support.  You have to know in
> advance whether the other side is able to accept your options.
>
> If we expect to have a small number of options, we could possibly just
> add a uint32 bitfield to TransportOptions saying which options you
> support (it will be encoded as a varint, so typically smaller than 4
> bytes).  Each party can send whatever options it wants, but it will
> only assume the other party accepted the option if it receives a
> bitfield with the appropriate bit set.
>

Or a packed array of tag numbers which will be extensible to tag numbers
beyond 31.  It is also useful to distinguish between optional/desirable
options that would be nice to use if the other side supports them (e.g.
continuous_rekey), and mandatory options that the other side must support
or communications isn't possible (e.g. packet length negotiation for
NoiseTinyLink):

  repeated int32 desirable_options = ??;
  repeated int32 mandatory_options = ??;

The trick is where to announce this so that both sides have the opportunity
to configure a desirable option value.  In NoiseTinyLink, the
server/responder is the first to announce transport options.  The client
cannot ask for or demand a feature before then.  Even if the client does
ask for a feature in the third message, the server can no longer say "yes,
and here is my value" because the handshake is over.

Possibly the client could list its desirable/mandatory options in the early
payload section of the negotiation request, with the server responding in
kind in the second handshake message.  The client then sends its actual
values in the third handshake message.

Example 1: Tiny client connecting to full server that cannot negotiate
packet lengths:
    Client: mandatory_options = {2} /* max_recv_length */
    Server: rejected = true, bye!

Example 2: Tiny client connecting to full server that *can* negotiate
packet lengths:
    Client: mandatory_options = {2}
    Server: desirable_options = {3}, continuous_rekey = true,
max_recv_length = 65535
    Client: max_recv_length = 256, continuous_rekey = true

Example 3: Tiny client that does not support continuous_rekey:
    Client: mandatory_options = {2}
    Server: desirable_options = {3}, continuous_rekey = true,
max_recv_length = 65535
    Client: max_recv_length = 256

The lack of the continuous_rekey value in the client's Example 3 response
indicates that the server cannot use it either and must drop the option
value it sent previously.  The presence of an option value indicates that
the request to use the feature has been ACK'ed.

Note that the client in Example 2 may respond with continuous_rekey = false
to indicate that while it accepts re-keying in messages from the server, it
will not be re-keying its own transmitted messages (for whatever reason).

Cheers,

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


More information about the Noise mailing list