[noise] Questions and feedback
mike at r3.com
Thu Sep 12 05:42:17 PDT 2019
We're experimenting with Noise in a commercial product designed for enterprise use cases, where small size / easy auditability of the codebase is important and we can sacrifice TLS compatibility.
Firstly, thanks! Noise is very nicely done, the spec is easy to read and the mix'n'match approach is a good fit for what we need. We're planning to use a derivative of the Noise-Java library, so thanks to Rhys Weatherley too.
Having read the specs I had a few questions.
There's a requirement to support two different symmetric cipher suites. The spec gives justifications for many decisions, but curiously does not justify the choices here. For instance, it specifies the use of BLAKE2 rather than SHA3. An obvious question a security auditor might have is why the backup option for SHA2 is not the winner of the NIST competition but rather a runner-up. The spec says "BLAKE2 is fast and similar to ChaCha20", but that seems somewhat light as a justification - does the Noise community believe there's no reason to ever use SHA3, for example?
Although I understand the desire to have backup options, as far as I know there are currently no clouds on the horizon for AES or SHA2 and negotiation/fallback is a rather complex feature that has created problems in the past with TLS. Because part of the value of Noise to me is the small size of an implementation (and ease of convincing people it's correct), it's tempting to use only AESGCM/SHA256 and spin an entirely new rev of the protocol if one day these primitives start to break (e.g. different port number), rather than do negotiation on the fly. This is doubly tempting because the product in question is designed for conservative organisations that tend to have whitelists of "approved" cryptography, and ChaCha20-Poly1305 is unlikely to be on them yet. Yes, I know Chrome already supports these and they're being widely deployed. If only "Chrome does it" was always a winning argument :(
A common justification for ChaCha20 over AES is that AES is hard to implement well in software. But in this specific product, all the CPUs we'll run on have AES hardware acceleration, so this is not a concern for us.
If we instantiate a protocol with only AES/SHA2, are there any compelling reasons to believe that will create big problems later? Given the long history of strength for both AES and SHA2 my guess is my customers will request a move to post-quantum crypto before caring about ChaCha20/BLAKE2.
With respect to the DH curve, the spec says: "The 25519 DH functions are recommended for typical uses, though the 448 DH functions might offer extra security in case a cryptanalytic attack is developed against elliptic curve cryptography".
This phrasing leads to an obvious question - if Curve448 might offer extra security and has no other downsides then why is it not the default? Is it slower? Or is there some advantage of 25519 over 448 that isn't mentioned in the spec? Curve25519 seems more widely deployed, but the spec itself leaves a lot of leeway in which to pick, so auditors might disagree with our choices.
The NoiseSocket spec doesn't seem to be obviously linked from the homepage of noiseprotocol.org - I understand this could be because NoiseSocket is less mature. It took a while to discover the spec, as well as how it relates to NoiseLingoSocket. It might be less confusing if the specs were all in one place.
This looks like a sharp edge, and the longer I look at it the sharper it gets.
The spec says, "Applications must consider that a sequence of Noise transport messages could be truncated by an attacker. Applications should include explicit length fields or termination signals inside of transport payloads"
It feels like detecting truncation is useless because it's not actionable. TCP connections drop all the time for mundane reasons. If a MITM injects a RST or FIN packet there's no way to differentiate this from ordinary events like the user closing their laptop lid, and no clear action to take even if you could. Signalling an alert to the user is pointless as the FP rate would be so high, and anyway, there's not much they can do in response. I doubt any alert is even explainable.
The intuition here is that if an attacker knows a lot about the plaintext they might be able to gain advantage by monitoring the flow of encrypted bytes and truncating the stream in such a way that one side gets confused about what the other side meant. So perhaps a better approach would be to misalign transport and application frames by injecting padding into random locations inside the message, instead of just at the end. For instance some padding could be inserted at the start of a payload, and then some bytes of the real message, and then some more padding, and then the final payload bytes. The splice would itself be random and could split across Noise packets. This would make truncation attacks much harder to pull off because any truncation the attacker chooses might yield a truncation of the plaintext randomly offset from the intended target. It would also satisfy the desire to hide message sizes.
Does that sound plausible?
I'm a bit skeptical whether the small saving in bytes is worth defining so many different profiles. The Noise spec points out that you can just use a dummy key if you have an X handshake and want an N. The "default and entry level" NoiseLink proposal uses XX, which seems reasonable. My own "Noise Box" code (written before I discovered NLS) just uses an X handshake and a private key of zero if no sender private key was provided. The other side recognises the corresponding public key as meaning the sender is anonymous.
I implemented the header/framing/prologue from Noise Socket and then thought about allowing the N handshake as well as X, but couldn't figure out if that was better or worse than just using a dummy key. The specs provide no guidance on this - is the only real difference wire size efficiency? If so is the extra complexity of multiple modes worth saving the few extra bytes?
The spec defines aliases, but they only have meaning in NoiseTinyLink. Is it really justified to have a separate profile for this, given the tiny sizes of the strings in question? Would it be better to have these aliases be defined in the regular Noise spec, given it already enumerates all the handshake patterns anyway?
The spec allows senders to define max_send and max_recv sizes. Why would you want to pick a value lower than the Noise maximum? Likewise, the short_term mode. This seems like an additional axis of flexibility that isn't necessary - surely it could be either always true for one-way handshakes, or the feature could be removed, as again, it seems like a relatively small byte saving.
It seems like the NLS spec can't quite decide if it wants to save every byte possible or not, and so ends up with many different configurations each of which might save a small amount here or there. Perhaps all the optimisations should just be rolled into the base spec and made mandatory, as it means fewer codepaths to test and hey, who doesn't like saving bandwidth?
Using both Curve25519 and Ed25519.
My server needs to be able to build encrypted connections and also sign things at the app protocol level. Are there any problems with using the same private key bytes to generate both Curve25519 and Ed25519 public keys? I can't think of any problem that could occur from having the same private key be used to generate two related public keys with different algorithms, but it'd be nice to get confirmation.
Thanks for the work and for any guidance.
-------------- next part --------------
An HTML attachment was scrubbed...
More information about the Noise