[noise] New draft: "noh2" branch

Tiffany Bennett tiffany at stormbit.net
Thu Aug 27 08:50:26 PDT 2015


I had been working on implementing the original draft on this branch
in my Rust implementation, and I had run into a few stumbling points.
Some of them have been fixed in the most recent revision, while others
have not.

 Having a length field that is processed by the session doesn't make
sense, since Session doesn't handle framing for TCP, and is redundant
for UDP. I feel like this should be removed and given to a "framing
layer", which may or may not be explicitly encoded into the
specification. The framing layer would also handle the transport flags
removed from the session. In my implementation I already have a
separate framing layer of a sort, and will simply be giving it more
functionality (framing, explicit nonce, etc.).

More concretely, the framing layer as I envision it is laid out as
such (and may need to be expanded to accommodate branching):

- session: The session as used by the framing layer.
- descriptors: A list of lists of descriptors, for each step of the handshake.
- stepping: As existed before in the session.
- nonce: Mutually exclusive with stepping.
- framing: Whether or not the connection is stream-based or
datagram-based, determines if a length field is needed.
- split: I see that EndHandshake now unconditionally creates a
bidirectional stream, so this flag should perhaps not be included,
unless there is a reason to support one-directional streams.
- state: The current state in the handshake, so we know which
descriptor set to use when creating or processing the next handshake
message. In my implementation, this is just an integer offset into the
descriptor table.

In my current implementation, my `Handshake` type currently performs
some of these duties, and `NoiseTcpStream` performs others. I might
use two separate types for the framing layer, one that handles the
handshake, and one for once the handshake is completed.

I see that the termination handling is now gone. I like this change. I
prefer for application-level protocols to decide when a connection has
been terminated, and for the controlling application, when it receives
its application-layer termination message, to simply destroy all
resources associated with the connection, instead of needing to chain
through two or more layers of the IP stack telling lower layers that
they need to begin closing the connection.

I like where this branch is going at the moment. The session is less
complex than it used to be, now that the kernel has been split off
from it. It has better interoperability than previous versions. I
would like better error detection, though. At the moment, a mismatched
protocol will likely produce an invalid MAC error or something
similarly unhelpful. The only solution I see is including the name of
the protocol (or the hash of it) in the first handshake message,
however.


On Thu, Aug 27, 2015 at 3:37 AM, Trevor Perrin <trevp at trevp.net> wrote:
> On Wed, Aug 26, 2015 at 5:28 PM, Jason A. Donenfeld <Jason at zx2c4.com> wrote:
>>
>> FWIW, I prefer master to noh, and I prefer noh to noh2. Noh2 and noh seem to
>> add quite a bit of complexity and implementation prescription that I don't
>> openly welcome.
>
> I'm still trying to simplify noh2, see if you like revision 1 any better.
>
>
>> What I dislike: the considerable complexity and abstraction added.
>
>
> A lot of the complexity from noh got removed in noh2.  Hard to know
> what else to cut:
>
>  * If the patterns are confusing we could go back to the original
> Noise design that used a single "e, dheX, s, dhsX" pattern for every
> message.  But you'd end up with redundant fields and DH ops (e.g. in
> brackets) that we currently tailor away:
>
> XX:
>  -> e
>  <- e, dhee, s, dhse
>  -> [e, dhee,] s, dhse
>
> IS:
>  -> e, dhes, s, dhss
>  <- e, dhee, [s,] dhss
>
> XS:
>  -> e, dhes, [e, dhes]
>  <- e, dhee, [e, dhee]
>  -> s, dhse, [s, dhse]
>
>
>  * We could write a concrete spec that presents a concrete Noise Pipe
> protocol, and then have the general framework in a separate document.
> But I'm not sure presenting a long list of concrete steps is that much
> better.  For example, I find the pattern easier to deal with then a
> list of steps:
>
>  -> e
>  <- e, dhee, s, dhse
>  -> s, dhse
>
> vs
>
> def WritePipeHandshakeMessage0():
>   kernel.MixKey(name + ZERO + preshared_key)
>   e = GENERATE_KEYPAIR()
>   Write(e.pub)
>   Write(payload)
>
> def WritePipeHandshakeMessage1():
>   e = GENERATE_KEYPAIR()
>   Write(e.pub)
>   kernel.MixKey(DH(e, re))
>   Write(kernel.Encrypt(s.pub))
>   kernel.MixHash(s)
>   kernel.MixKey(DH(s, re))
>   Write(kernel.Encrypt(payload))
>
> def WritePipeHandshakeMessage2():
>   Write(kernel.Encrypt(s.pub))
>   kernel.MixHash(s)
>   kernel.MixKey(DH(s, re))
>   Write(kernel.Encrypt(payload))
>
>
>
>>  While
>> elegant, in fact I don't want the ability for "parties to alter handshake
>> patterns, ciphersets, and transport flags on the fly".
>
> I do think being able to choose whether or not to authenticate, or
> execute a 0-RTT handshake, are pretty useful, and the "noh2" design
> achieves them at low cost.
>
>
>> This might make noise
>> suitable as a general purpose TLS-rank protocol, but I'm after something
>> small, minimal, secure, and easy to produce an audit-able implementation. I
>> don't want it to have so many bells and whistles that I need to write it in
>> Rust or Haskell to have faith in my code; instead I want to write C that I
>> can confidently verify without my eyes bleeding.
>
> I would hope we achieve that to.  I'll try to implement noh2 soon and
> see how it goes.
>
>
>> I also liked the quality of the master branch where all previous bytes were
>> in aad for each encryption, which imposed ordering constraints (in addition
>> to binding relevant data to the exchange).
>
> I'm not sure what "ordering constraint" means here.  I don't think
> there's any way to maliciously reorder handshake messages.
>
>
>> It also had the nice effect of
>> authenticating the prologue, which seems like a nice quality, as I wouldn't
>> want an attacker to be able to "break apart" any components of one message
>> and put them in a message of another type.
>
> None of the type, length fields need to be in aad, nor does an
> explicit nonce.  So I'm not sure what we'd use this for: what data
> needs to be authenticated and go in prologue that couldn't just go in
> the payload?
>
>
> Trevor
> _______________________________________________
> Noise mailing list
> Noise at moderncrypto.org
> https://moderncrypto.org/mailman/listinfo/noise


More information about the Noise mailing list