Live data from Hacker News

Whisper: Wraps any Go io.ReadWriter in a secure tunnel using Ed25519/X25519

github.com

11–20 of 27 posts

Re: Whisper: Wraps any Go io.ReadWriter in a secure tunnel using Ed25519/X25519

#11
post #6

There is no description of the protocol or of its security goals, so I am making some guesses based on a cursory look at the source and what I imagine this might be for. A single symmetric key is derived for both directions, and there is no checking of nonces, so as far as I can tell any message can be dropped, reordered, or replayed in both directions. (Including replaying message from A to B as if they were from B…

I once heard something along the lines of "if you're writing the words RSA, you're doing it wrong." I guess that goes for ED25519 also. If you want to secure a stream with asymmetric cryptography and don't need all the bells and whistles of TLS, what's the correct way to do it? Noise? Is there nothing simpler?

As far as language support goes, it doesn't get much easier than working with TLS, especially in Go.

As far as alternatives go, Noise Pipes[0] never took off, but feel like they'd be well suited to this task.

[0]: https://noiseprotocol.org/noise.html#noise-pipes

Re: Whisper: Wraps any Go io.ReadWriter in a secure tunnel using Ed25519/X25519

#12

There is no description of the protocol or of its security goals, so I am making some guesses based on a cursory look at the source and what I imagine this might be for. A single symmetric key is derived for both directions, and there is no checking of nonces, so as far as I can tell any message can be dropped, reordered, or replayed in both directions. (Including replaying message from A to B as if they were from B…

I mean this looks like standard ECIES to me. I think it could even count as a Noise protocol, as in my understanding that protocol family subsumes most of the classic Diffie Hellman based key exchanges. Reading the source the author seems to use a long-lived ECDSA key pair to sign and exchange an ephemeral ECDH key pair, then derives a symmetric AES key from that and uses that for AES-GCM. Not sure how you would do m…

> If you want replay protection it's probably sufficient to either remember used keys or add a timestamp.

The replay Filippo is talking about is in the context of a single key. The remote side simply reads the nonce || message off the wire and aead.Opens it, without regard to whether or not that nonce has been used before to decrypt a previous message.

Re: Whisper: Wraps any Go io.ReadWriter in a secure tunnel using Ed25519/X25519

#13
post #6

There is no description of the protocol or of its security goals, so I am making some guesses based on a cursory look at the source and what I imagine this might be for. A single symmetric key is derived for both directions, and there is no checking of nonces, so as far as I can tell any message can be dropped, reordered, or replayed in both directions. (Including replaying message from A to B as if they were from B…

I once heard something along the lines of "if you're writing the words RSA, you're doing it wrong." I guess that goes for ED25519 also. If you want to secure a stream with asymmetric cryptography and don't need all the bells and whistles of TLS, what's the correct way to do it? Noise? Is there nothing simpler?

IIUC the correct answer, according to the 2009 blog post that popularized the saying you're referring to, is to just use TLS anyway. In most cases it's better to accept some extra complexity than to get crypto wrong.

Edit: Here's that classic: https://web.archive.org/web/20090606064715/http://www.matasa...

Re: Whisper: Wraps any Go io.ReadWriter in a secure tunnel using Ed25519/X25519

#14

Earlier quoted context omitted.

I mean this looks like standard ECIES to me. I think it could even count as a Noise protocol, as in my understanding that protocol family subsumes most of the classic Diffie Hellman based key exchanges. Reading the source the author seems to use a long-lived ECDSA key pair to sign and exchange an ephemeral ECDH key pair, then derives a symmetric AES key from that and uses that for AES-GCM. Not sure how you would do m…

Each Write encrypts a separate "record" (in the parlance of TLS and Noise). Each of those records can be arbitrarily dropped, replayed, or reflected. Here's an example, if you do Write("Hello") Write(" the password is ") Write("password") then without a key I can make you or your peer read "Hello the password is Hello" (or "HelloHelloHello" or any composition of those messages). No Noise protocol would allow that.

Oh well, I did not realize he uses it like that.

Re: Whisper: Wraps any Go io.ReadWriter in a secure tunnel using Ed25519/X25519

#15
post #8

Earlier quoted context omitted.

I mean this looks like standard ECIES to me. I think it could even count as a Noise protocol, as in my understanding that protocol family subsumes most of the classic Diffie Hellman based key exchanges. Reading the source the author seems to use a long-lived ECDSA key pair to sign and exchange an ephemeral ECDH key pair, then derives a symmetric AES key from that and uses that for AES-GCM. Not sure how you would do m…

Can you express this with Noise framework tokens? I don't think you can. Noise is fiddlier than it looks! It's not just an ordering of DH exchanges; it's transcript hashes, cipher state tracking (and reinitializing), key derivation, the whole 9. The temptation (at least for me) is to just skip to the table of handshakes and skim, but the actual protocol framework is in Section 5, where they define precisely what each…

Probably not, though Noise mentions that you could replace DH operations with signatures.

Re: Whisper: Wraps any Go io.ReadWriter in a secure tunnel using Ed25519/X25519

#16
post #8

Earlier quoted context omitted.

Can you express this with Noise framework tokens? I don't think you can. Noise is fiddlier than it looks! It's not just an ordering of DH exchanges; it's transcript hashes, cipher state tracking (and reinitializing), key derivation, the whole 9. The temptation (at least for me) is to just skip to the table of handshakes and skim, but the actual protocol framework is in Section 5, where they define precisely what each…

Probably not, though Noise mentions that you could replace DH operations with signatures.

Yeah, I don't mean to be coy. You can't end up with this protocol using Noise. :)

Re: Whisper: Wraps any Go io.ReadWriter in a secure tunnel using Ed25519/X25519

#17
post #3

Interesting, though AFAIK a secure tunnel is only useful for a net.Conn, not an io.ReadWriter. What's the usecase for a "secure tunnel" over a bytes.Buffer? btw, I noticed that the decrypt function reads a 32-bit message length and immediately allocates a slice of that size. That means an attacker can send 0xFFFFFFFF and cause you to allocate 4GiB.

You're kinda looking at the interface issue backwards. Being an io.ReadWriter is a promise that the tunnel code won't do anything other than read or write. The tunnel code shouldn't be getting local and remote addresses or setting deadlines of its own, or most of the rest of what net.Conn can do. https://pkg.go.dev/net#Conn

It is good that it doesn't take more than it needs. That bytes.Buffer happens to implement io.ReadWriter is not of consequence; for any given task you want a io.Reader or io.Writer for there may be any number of specific implementations that don't make sense to use with it, but that doesn't mean you should require more methods of the interface.

I'm speaking solely about the interface here; the many other concerns are valid.

Re: Whisper: Wraps any Go io.ReadWriter in a secure tunnel using Ed25519/X25519

#18
post #16

Earlier quoted context omitted.

Probably not, though Noise mentions that you could replace DH operations with signatures.

Yeah, I don't mean to be coy. You can't end up with this protocol using Noise. :)

ECIES is quite fine though for most asynchronous applications, where having a signing key also makes sense as you often want to publish long-lived, signed data and build a trust chain (e.g. generate and sign session keys from a master key). I built several real-world systems based on that (e.g. [1]) and they all made it through the audits fine. I was exploring Noise-based protocols but I find it's best to rely on primitives that are supported by the Web Crypto API.

1: https://github.com/kiebitz-oss/

Re: Whisper: Wraps any Go io.ReadWriter in a secure tunnel using Ed25519/X25519

#19
post #8

Earlier quoted context omitted.

I mean this looks like standard ECIES to me. I think it could even count as a Noise protocol, as in my understanding that protocol family subsumes most of the classic Diffie Hellman based key exchanges. Reading the source the author seems to use a long-lived ECDSA key pair to sign and exchange an ephemeral ECDH key pair, then derives a symmetric AES key from that and uses that for AES-GCM. Not sure how you would do m…

Can you express this with Noise framework tokens? I don't think you can. Noise is fiddlier than it looks! It's not just an ordering of DH exchanges; it's transcript hashes, cipher state tracking (and reinitializing), key derivation, the whole 9. The temptation (at least for me) is to just skip to the table of handshakes and skim, but the actual protocol framework is in Section 5, where they define precisely what each…

Gotta say that I generally like the Noise framework (or rather the protocols that result), but it is one of the most impenetrable specifications I've ever read

I don't remember what it is specifically about it, I just remember the document being a pain to read; a bit like the original Paxos paper in that regard.

Re: Whisper: Wraps any Go io.ReadWriter in a secure tunnel using Ed25519/X25519

#20
post #17
post #3

Interesting, though AFAIK a secure tunnel is only useful for a net.Conn, not an io.ReadWriter. What's the usecase for a "secure tunnel" over a bytes.Buffer? btw, I noticed that the decrypt function reads a 32-bit message length and immediately allocates a slice of that size. That means an attacker can send 0xFFFFFFFF and cause you to allocate 4GiB.

You're kinda looking at the interface issue backwards. Being an io.ReadWriter is a promise that the tunnel code won't do anything other than read or write. The tunnel code shouldn't be getting local and remote addresses or setting deadlines of its own, or most of the rest of what net.Conn can do. https://pkg.go.dev/net#Conn It is good that it doesn't take more than it needs. That bytes.Buffer happens to implement io.…

Sure, in general you want to use the narrowest possible interface. But in this particular case, I think `net.Conn` communicates intent better than `io.ReadWriter` -- the former implies that two distinct parties are involved, whereas `io.ReadWriter` is usually for (single-user) buffers or files. Sometimes it's sensible to use a larger interface than necessary; e.g. if you have a helper function that only calls `SetDeadline` and `Read`, the argument should be a `net.Conn`, not a custom interface with just those methods.

tbh though, it's a very minor quibble and not really worth worrying about ‾\_(ツ)_/‾

Post reply on HN