[noise] NoiseLink questions

Trevor Perrin trevp at trevp.net
Sun Jul 1 16:39:57 PDT 2018


On Sun, Jul 1, 2018 at 10:31 PM, Rhys Weatherley
<rhys.weatherley at gmail.com> wrote:
>
> 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.

We could just number the fields from 1 in each message.  That's also
the most efficient because fields numbers <=15 get stored in a single
byte.

Instead I aligned the fields (3,4,5) in
NegotiationDataRequest/Response because they matched up pretty well.

There's a type mismatch between rejected_protocol(string) /
rejected(bool), as you point out, but despite that it seemed ergonomic
to just use the same number.


> 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().

You could also call HasKey(), and add/remove padding if it returns true?


>>   * 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!".

SHA-2 doesn't seem to have the same cryptanalytic problems as SHA-1,
or the sidechannel problems of AES, though.

So if we're trying to steer towards a limited set of compatible crypto
for the default profiles, I'm still wondering if just anointing
SHA-256 is the easiest thing.


>> 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.

OK.


>> 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.

We could do that, but if we use a uint64 instead that's probably all
the transport options we'll need, considering it was a stretch to come
up with 4 of them?


> 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.

You're describing a 3-way handshake, with XX:
  client: advertise supported options (in clear)
  server: send options, advertise supported
  client: send options

An alternative is a 2-way handshake:
  client: -
  server: send options, advertise supported
  client: send options, advertise supported

In this case, the server just sends all its options, and then learns
which ones the client supports.

Pros:

 * Encrypts all the options, from both client and server

 * Simple message format (the same for both parties).

Downsides:

  (a) The server has to send all its options, whether or not they're
going to be respected.  That's less efficient that filtering by what
the client supports.  OTOH, we only have a few options.

 (a) The server wouldn't learn until the 3rd message whether its
requested transport options are being respected or disregarded.  If
the server has some mandatory options, it would be easier to reject
the connection earlier.  OTOH, clients are more likely to be the
limited party, and rejecting the communication 1 round-trip later
isn't a huge deal.

So I guess I like the idea of keeping all options encrypted, but just
adding a supported_options bitfield?

Trevor


More information about the Noise mailing list