Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement cryptography for laminar #41

Open
fhaynes opened this issue Oct 17, 2018 · 11 comments
Open

Implement cryptography for laminar #41

fhaynes opened this issue Oct 17, 2018 · 11 comments
Labels
difficulty: hard enhancement New feature or request help wanted Extra attention is needed
Milestone

Comments

@fhaynes
Copy link
Collaborator

fhaynes commented Oct 17, 2018

Start with one time padding and DTLS.

@fhaynes fhaynes added this to the 0.2.0 milestone Oct 18, 2018
@lain-dono
Copy link

I play with my protocol implementation based on netcode.io 1.02 that uses xchacha20poly1305 ietf and chacha20poly1305 ietf from libsodium. I have a port of these algorithms from libsodium, rewritten in Rust (without simd and only detached mode). You can also use libsodium directly like this. In short, chacha-poly is relatively simple and easy to implement. I think simplicity makes it a bit safer than AES (because AES is quite complex). Also chacha-poly is faster in software implementation. Also see RFC7905: ChaCha20-Poly1305 Cipher Suites for Transport Layer Security (TLS).


My (re)implementation of netcode.io has a different header format. Overhead: 18-25(or 24) bytes per payload packet, 19-20 bytes in most cases (16 bytes for Poly1305 and 2-9 bytes for sequence). I saved at least one byte because I can. In fact, I just used the implementation details of the prefix varint. So I got the following format for payload packages:

[sequence] 2-9 bytes
[encrypted data] variable size
[hmac] 16 bytes

I think I could prohibit the use of the full 64-bit sequence. 56 bits is enough. This is quite a fun byte counting game.

@TimonPost
Copy link
Owner

@lain-dono really thanks for your input, saying after 2 months :). Cryptography just doesn't have very high prio now.

However, I did some research on cryptography and we might use TLS 1.3 on top of laminar. QUIC also uses it for secure communication. TLS 1.3 offers a 0-Roundtrip solution, is safer and more.

@daxpedda
Copy link
Contributor

Would like to tackle this if possible.
Imo we should use rustls if we intend to use TLS. Is there any kind of agreement on this yet?

@TimonPost
Copy link
Owner

I was questioning if TLS is really fitted our purpose. I am thinking this because TLS is asymmetric encryption method. Basically, symmetric encryption fits us very well and is a lot faster, for example, we could use RC4, AES, DES, 3DES, QUAD.

@daxpedda
Copy link
Contributor

TLS is only using asymmetric encryption for key exchange or key agreement, cyphers used by TLS are using symmetric encryption.
Without an asymmetrical key exchange, there is no way to protect the initial key exchange and all further encryption is compromised.

Basically we want to protect against the following "attacks" (rough overview):

  1. Protect the data from anybody unauthorized reading it: done by encryption
  2. Protect the keys used for the encryption: done by doing an asymmetric encryption key exchange
  3. Protect against man-in-the-middle attack: done by having valid certificates server side, no viable solution for normal users (except manual certificate exchange 😆)

Especially things like key exchange are really hard to get right. Using a well established standard is they way to go here I believe. Another part of it is maintenance, not only is encryption, security issues and bugs kept up to date and fixed, but the protocol itself is constantly monitored and improved.

@TimonPost TimonPost changed the title Investigate crypto options for UDP Implement cryptography for laminar Jul 6, 2019
@TimonPost TimonPost added difficulty: hard enhancement New feature or request help wanted Extra attention is needed labels Jul 6, 2019
@maugier
Copy link

maugier commented Oct 22, 2020

Have you considered using Noise instead of (D)TLS? It's the protocol used by Wireguard.

Noise is much simpler than DTLS, and easy to implement on top of libsodium. You would probably get something close to what @lain-dono has implemented, but with the possibility of an asymmetric handshake. 0-RT is also a possibility.

@TimonPost
Copy link
Owner

That's interesting never heard of it! It could be of use in our scenario as far I can tell.

@bschwind
Copy link

@TimonPost I can recommend snow as a nice implementation of the Noise Protocol.

@lain-dono
Copy link

lain-dono commented Aug 17, 2021

Wow, it's been two years and the problem is still unexplored.
I have some additions as I have recently returned to the task of encrypted protocol for games.

For a start, what problems do we want to solve?

  • We want to authenticate clients
  • We want to protect servers from denial of service attacks
  • We want to have good performance

Among other things, you usually want to separate auth-server and game-server.

To solve these problems, we need a 3-way handshake and special auth tokens.

Auth over TCP/TLS/HTTPS/etc
  Client <-     auth-token    <- Auth   (0)

Handshake:
  Client -> [hello   request] -> Server (1)
  Client <- [response/denial] <- Server (2)
  Client -> [ask    response] -> Server (3)

Session:
  Client <> [payload / close] <> Server (4)

The AuthToken (0) contains:

  • Addr of Server
  • Some information that only the server can decrypt
  • Information that allows the server to reject the connection before decrypting
  • Token life time (I recommend around 2-10 seconds)

To hide the private parts of the token, I recommend XChaCha20Poly1305. The reason for this is the 192-bit (24-byte) nonce. This allows randomisation to be used to generate nonce. Also RustCrypto/AEADs#1. Rediced-round variations are about 2.5 times faster.

The client receives his token from Auth and attempts to perform a handshake based on it. Let's talk about a handshake.

The first message (1) can be unencrypted. However, all meaningful data must be protected by AEAD. The server must discard the data first on the basis of the open data. The server then tries to verify an attempt to reuse the token. The server then decrypts the private part.

If all is well, the server half-opens the connection and replies with an encrypted message (2). There is an option to explicitly deny a connection to a client (e.g. the server is full). Inside this message is a token that is sent back via the client. Only the server can read this.

The client must confirm that it can decrypt messages from the server and is the owner of the IP (protection against ip-spoofing attacks). (3)

After receiving (3), the server considers the connection fully open. The client considers the connection open after receiving any payload packet.

Messages (1) and (3) are sent by the client with a certain frequency. For example 5-10 times per second. And only 5-10 times. The lifetime of the AuthToken is chosen to be long enough to establish a connection.

This is how a scheme based on netcode.io will work. This scheme could be improved in some places, but it already solves all our problems. The only thing I would replace the ChaCha20 with the ChaCha8. Because Too Much Crypto.


Great, now let's talk about Noise.

The scheme above can be supplemented by some key exchange scheme. I would suggest using either NKpsk0 or NNpsk0. The only difference between them is the presence of a server static public key. If you want to use NKpsk0, this key may be passed to the client along with the AuthToken or hardcoded into the client. The psk is actually transferred via the private part of the AuthToken.

I wouldn't recommend using something like snow. Such libraries are designed for the general case. If you hardcode a specific handshake algorithm, it will be faster and more robust. It is also easier to use a non-standard set of cryptographic primitives. ChaCha8Poly1305 as AEAD. Blake3 as hash. However, I have not investigated the Diffie-Hellman key exchange replacement. x25519 is ok.


Any questions?

@lain-dono
Copy link

Note: I implement XChaChaPoly reduced-round. RustCrypto/AEADs#355

@TimonPost
Copy link
Owner

TimonPost commented Aug 25, 2021

This library is not actively maintained anymore, unfortunately. Due to some other priorities, I can not focus on implementing, reviewing, and analyzing this feature with you. Feel free to take this issue, implement it and maybe discuss it with others who might be interested in solving this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
difficulty: hard enhancement New feature or request help wanted Extra attention is needed
Projects
None yet
Development

No branches or pull requests

6 participants