Skip to content
This repository was archived by the owner on Feb 8, 2023. It is now read-only.

Unreliable crypto channels #198

Open
ghost opened this issue Dec 8, 2016 · 26 comments
Open

Unreliable crypto channels #198

ghost opened this issue Dec 8, 2016 · 26 comments

Comments

@ghost
Copy link

ghost commented Dec 8, 2016

Unreliable crypto channels

I've researched the cryptographic channels that work over datagrams in the past few days, and so far there's 4 options, none of which has a really good implementation in go :):)

The reason we need an unreliable crypto channel is that we have strong use cases for being flexible when it comes to modeling reliability. For many cases, reliability at the bottom of the stack (as in: TCP et al) is not an option. Instead, we want datagram transports and layer reliability on top only where needed. Read more about the motiviation in #143.

Definitions

  • Initiator: the node initiating the handshake by sending a request.
  • Responder: the node receiving the handshake request and sending a response.

Desired properties

  1. Handshake responses MUST NOT be bigger than handshake requests. This way the nodes can't be used for amplifying a DDoS attack.
  2. Handshake requests MUST NOT generate state on the remote. This prevents resource exhaustion DoS attacks.
  3. Invalid packets SHOULD be dropped without any response. This hinders debugging problems, but adds "port knocking" known from SSH.
  4. Handshake requests SHOULD include an identifier capable of preventing the teardown of legitimate existing sessions. Wireguard uses a timestamp for this and discards requests which are older than the current session's handshake.
  5. There MUST be a means of protecting against replayed handshake and data packets. One means is a sequence-id and a sliding window.
  6. There MAY be a means of reordering packets that arrived out of order.
  7. For encryption schemes which require a nonce, the packet's respective nonce MUST be included with the packet itself.
  8. The primitives used SHOULD be supported by WebCrypto.

Open questions:

  • Should we allow piggybacking data on top of handshake packets?

Candidates

  • DTLS
    • There's a prototyped implementation in quic-go which is functional enough for a working QUIC server. (cc @lucas-clemente)
    • Apart from that there are DTLS-capable Go bindings to OpenSSL, which is obviously less than ideal.
    • Good explanation of the differences to TLS: http://security.stackexchange.com/a/29179
    • DTLS needs to support RSA keys and thus came up with its own fragmentation mechanism, since RSA keys hardly fit into regular-sized UDP packets. This appears like needless complexity. We still want to eventually support DTLS though, as it unlocks QUIC and WebRTC.
  • Noise Protocol Framework
    • Wireguard is a kernel-space VPN which came up with a crypto channel over datagrams, based on the Noise framework.
    • Its handshake protocol is very promising. One weakness I noticed though is that its replay protection relies on monotonically increasing time. Introducing the concept of time in a distributed system screams for subtle issues.
    • Wireguard has excellent documentation: https://www.wireguard.io/protocol
  • SHS / Secure Handshake
  • CryptoAuth
@dominictarr
Copy link

my shs implementation uses nacl algorithms, which arn't in webcrypto. but the design could be adapted to use other algorithms. but also, over the lifecycle of a connection, asymmetric crypto is only needed in the initial handshake, and it's mostly symmetric, so you could use aes (instead of chacha), hmac, and sha256 from webcrypto, but leave the signatures as ed25519.

oh, btw, I was talking to felix from ethereum about this the other day... I don't know his github handle, but @wanderer can probably point him here

@Kubuxu
Copy link
Member

Kubuxu commented Dec 9, 2016

The TweetNaCL offers Salsa20 and Poly1305 in Js that should be as fast or even faster than Webcrypto AES.

@wanderer
Copy link
Member

wanderer commented Dec 9, 2016

calling @fjl

@fjl
Copy link

fjl commented Dec 9, 2016

Yes, I'm looking into the same topic for Ethereum.

@ghost
Copy link
Author

ghost commented Dec 10, 2016

@dominictarr @fjl wanna meet some time next week? Or any other week for that matter, since I live in Berlin :)

@jbenet
Copy link
Member

jbenet commented Dec 11, 2016

Whatever we do, we have to support at least one IETF recommended construction (Probably DTLS 1.3 or 1.2) and ideally one djb recommended construction.

@dominictarr have you gotten djb to audit shs? Also, what is the suggestd "datagramification" look like? may be useful to draft that up.

@Kubuxu
Copy link
Member

Kubuxu commented Dec 11, 2016

IETF is supporting ChaCha20+Poly1305 (RFC 7539) which is equivalent to Salsa20+Poly1305 created by djb. ChaCha20 is offspring of Salsa20 created also by djb.

@jbenet
Copy link
Member

jbenet commented Dec 12, 2016

@Kubuxu of course. It's beyond just choosing the ciphers-- what i mean is a construction that is djb orignal. the whole TLS and DTLS construction bundles in a lot of other concerns-- usually djb boils protocols down to the essentials needed in a very good way.

@Kubuxu
Copy link
Member

Kubuxu commented Dec 12, 2016

I agree, (D)TLS constructions will have a lot of burden from features that we won't use like re-authentication with new identity which means that they will be much more complex.

Lack of complexity is good. If we end up crafting something (which I am not really for, but we might have no other option), I would like it to be as simple as possible without security any trade offs.

Bugs and exploits can't hide in code you don't have.

@Kubuxu
Copy link
Member

Kubuxu commented Dec 13, 2016

re 4. Shouldn't be hard, if you prevent session interfering with other sessions until it is fully authenticated, which is very good property.

re 5. Sliding window is must have, I think if it is done similarly to how cjdns does it will be good (TCP over it is more reliable than over raw connections when it comes to bad and/or buffer bloated links).

re 6. Reordering should be done by higher layer, IMO. It means buffering and so on.

re 8. I would include "or be fast in software". Salsa20 from TweetNaCl-fast is faster then AES from webcrypto, and there is probably some magic with web-workers that can be done to off-load main thread. Even if it is in the main thread it still is able to pull out 128MB/s on x86 and 43 MB/s on ARM (my bare metal tests on ARM shown that AES is at least 2x slower than Salsa20).

Also I would prefer if we didn't have to craft it ourself but it might be not an option. I will be very happy if we can do it as collab with Ethereum.

@keks
Copy link

keks commented Dec 13, 2016

I'd like to suggest Signal's/OMEMO's double ratchet. I don't mean the initial handshake with an intermediate server (X3DH), just the logic to constantly change the key material and mix in new entropy.

some thoughts:

  • there is a formal security proof
  • google shows Go implementation, don't know quality though
  • message based
  • when we don't use x3dh we still need a handshake protocol (shs?)

edit: note the formal security proof is valid only in conjunction with x3dh

@Kubuxu
Copy link
Member

Kubuxu commented Dec 13, 2016

Double ratchet uses the ratchet because it stores long term session state and doesn't want the leaked state of session at one point to remove the security of future communication.

In my opinion it is not necessary for our usecase as the session keys won't be stored long term, they are purely ephemeral keys and even though x25519 and x448 operations are much cheaper than RSA they still are not as cheap as pure symmetric encryption after the handshake.

It gets even more complex when you add the fact that packets can arrive out of order.

@keks I might not see it but do you think using the ratchet protocol would have some benefits?


X3DH is quite a interesting and novel concept: https://whispersystems.org/docs/specifications/x3dh but our use case is quite different from theirs.

@keks
Copy link

keks commented Dec 13, 2016

Most of the previous work done with transport security considers a connection. In TLS with forward secrecy the keys for the connection are deleted - after the connection terminated.

In message-based communication there is not really a connection. Maybe there is a request-response style thing, but doing a new n-way handshake for sending one encrypted message and receiving one seems bad performance wise.
I'm sure every protocol has their own answer to this situation (I don't know about DTLS or the Noise Framework and shs and cryptoauth haven't been analysed yet). Signal's answer is to have a very-long-running session and constantly update the key material to have forward secrecy within one session. Additionally they do a (piggy-backed) DH key exchange on each round trip, both to allow post-compromise security (some session state has been leaked and the security recovers) and to add further entropy to the session.


X3DH is mainly interesting when you have an intermediate server that stores ephemeral keys for you. When you have direct communication, I think you could probably also just use shs. That is not formally analysed yet, but is very very similar to the case without the OPK. Also, maybe formal verification is in the pipeline hint hint.

@Kubuxu
Copy link
Member

Kubuxu commented Dec 13, 2016

The session exists as long as other party hasn't authenticated other session or till some timeout (long but session state is very small: shared key, nonce counter, sliding window).

Signal has very long running sessions because the messages are sent very rarely and there is option that the other party is offline, meaning it can't negotiate new session. This isn't a problem in our case as the other party has to be online, there is no server to act as mailbox.


Main use case of X3DH is establishing encrypted session when the other party is offline, otherwise it is quite easy to do normal DH, shs or cjdns alike.

@keks
Copy link

keks commented Dec 13, 2016

Signal has very long running sessions because the messages are sent very rarely and there is option that the other party is offline, meaning it can't negotiate new session.

Doing a 4-way handshake to do one request and get one response seems wasteful. If we talk to a host more often, the session can live really long. Also, the Signal state is also quite small (root key, chain key + some message keys for dropped messages, which can be deleted after some timeout).
Speaking of dropped messages - that could be a reason against the double ratchet. While I believe having dropped packets should work, this has not been tested very much. This just doesn't happen in Signal, WhatsApp and OMEMO.

@Kubuxu
Copy link
Member

Kubuxu commented Dec 13, 2016

The session exists as long as other party hasn't authenticated other session or till some timeout (long but session state is very small: shared key, nonce counter, sliding window).

UDP allows you to keep sessions quite long as there is no connection to keep alive. You don't have to do DH to send data, just use session symmetric key with new nonce, this is how cjdns and DTLS work.

@Kubuxu
Copy link
Member

Kubuxu commented Dec 13, 2016

Something to consider too, is that the smaller the handshake packets the higher the probability that they will go through.

@dominictarr
Copy link

@jbenet I havn't shown it to him. Given my requirements for ssb, I don't personally have a need for an unreliable protocol, and have too much to do anyway.

@keks of course, the tradeoff with the long lived session is that you then need persistent state, so your network protocol needs access to disk also.

@keks
Copy link

keks commented Dec 13, 2016

The session exists as long as other party hasn't authenticated other session or after some timeout (long but session state is very small: shared key, nonce counter, sliding window).

Yeah but that's not less than Signal's state: A root key, a chain key and a sliding window of message keys.

the tradeoff with the long lived session is that you then need persistent state, so your network protocol needs access to disk also.

During a program run I'd keep it in memory and garbage collect if the list of open sessions grows too large. If one of the peers loses state, a new handshake can be initiated.

@ghost
Copy link
Author

ghost commented Dec 16, 2016

A talk and slides on WireGuard has recently be published:

My talk on WireGuard is finally online!

Video: https://www.youtube.com/watch?v=eYztYCbV_8U
Slides: https://www.wireguard.io/talks/codeblue2016-slides-en.pdf

This has a general overview of NoiseIK in addition to WireGuard.

@jbenet
Copy link
Member

jbenet commented Dec 21, 2016

@lgierth WG looks promising

@Kubuxu
Copy link
Member

Kubuxu commented Dec 22, 2016

Looking at WireGuard's timestamp requirements it only needs monotonicity from the same initiator, is that still a problem?


Just finished reading the whitepaper on WireGuard [0]. Very interesting protocol, simple and still robust in security and DoS prevention.

I don't know how I feel about some higher layer decisions, like rekeying every 120s or other timeouts but this could be changed if it comes to it.

[0]: https://www.wireguard.io/papers/wireguard.pdf

@ghost
Copy link
Author

ghost commented Jan 19, 2017

@fjl let's chat at the meetup next monday?

@fjl
Copy link

fjl commented Jan 20, 2017

Sounds good. I'll be there. Which meetup though?

@ghost
Copy link
Author

ghost commented Jan 23, 2017

@jfl oops didn't notice your edit -- today at the ethereum office in waldemarstrasse, at 7pm: https://www.meetup.com/Berlin-Ethereum-Meetup/events/236898828/

I'll be there by 9, we got the the IPFS sprint calls from 6 to 8.

@fjl
Copy link

fjl commented Jan 23, 2017

I'm there, see you then.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

7 participants