Replies: 4 comments
-
Having partially implemented networking with encryption with bgt, I think this discussion has merits and I approve of the idea in general principle. |
Beta Was this translation helpful? Give feedback.
-
Hi, I am in full agreement that behind the scenes networking in the manner described would be amazing! Though it's totally cool if it's on by default, I do think it's important that there be a switch to toggle this encryption, for the purposes of connecting to older BGT servers, or any other enet centric application in another language. My thoughts on the library details are as following:
Generally this is a great proposal though and regardless of library used I look forward to seeing where this goes! |
Beta Was this translation helpful? Give feedback.
-
@samtupy I would need to look into how libhydrogen implements the functions that it uses for the steps in each key exchange algorithm. I'm not precisely certain how we would go about using monocypher to implement the key exchange algorithms described here; obviously it's possible but would require great care. (I'm also not very confident in my ability to securely re-implement it, since noise uses a small little token language of sorts to describe the processes and steps.) The ISC license does not require attribution, only that the copyright and permission notice be included in all copies of the software. Unlike other licenses there's no ambiguities -- it strictly uses the word "copies", which means that the standard definition under copyright law applies. Under the Copyright Act of 1976, as amended, the standard definitions that are most relevant are:
So I would say the license is pretty clear and easily understandable. Altering my existing PR to use libhydrogen would, I believe, not be overly difficult, if it's something you'd prefer me to do. |
Beta Was this translation helpful? Give feedback.
-
To briefly add to my prior comment, I will definitely look into how to incorporate these patterns using -- say -- monocypher, if you want to avoid the requirements of even the ISC license. It'll be something I'll probably have to ask the devs of monocypher about though just to ensure I get it right on the first try. |
Beta Was this translation helpful? Give feedback.
-
As it currently stands, Enet connections are completely unencrypted, leaving them open to interception, tampering, etc., and the developer of the game in question is expected to understand and write their own encryption methods for the data transmitted over the UDP transport. This is insufficient and dangerous for individuals who are not knowledgeable with cryptography, or who simply feel unqualified to write such code for themselves, and most developers end up using weird, unvalidated and unverified cryptographic techniques (like lots of fancy bit twiddling) to try to get around the fact that their encryption keys are usually stored in their code.
If accepted, this proposal would deem the current state of things as insufficient and would add automatic and transparent cryptographic negotiation to the start of any Enet-based connection, using algorithms from the Noise Protocol Framework, which has been well-tested and audited by experts in the security field and is used by several communication platforms throughout the world, including WhatsApp, Signal, and more.
What is the Noise protocol framework?
The Noise protocol framework, more often called just Noise, is a cryptographic framework for building higher-level cryptographic protocols. Protocols that are built with Noise support mutual and optional authentication, identity hiding, forward secrecy, zero round-trip encryption, and other advanced features. Noise also defines several protocols in the specification for users who just want to quickly protect a connection, which is what this proposal will be discussing; the usage of the framework to design a custom cryptographic protocol is beyond the scope of this proposal.
How does Noise work?
As with any internet protocol, Noise begins with a handshake. Specifically, two parties exchange handshake messages. Since noise allows for both protocols that are interactive and those that are not, and public keys that are both static and ephemeral, it builds these messages into what are known as handshake patterns. A handshake pattern describes the full sequence of messages that must be transmitted and responded to for a connection to be considered secure. Once the handshake pattern has been completed, both parties in the communication have derived a secret key which they can then use to send messages to one another. No one else -- not even someone monitoring the connection or intercepting packets transmitted over the network interface of either machine in the communication -- will be able to obtain the secret key, since only public keys, or keys that are already well-known, are published over the connection, since until the pattern has been completed, the communication is considered to be wide-open.
There are three possible handshake patterns which this proposal describes, some or all of which could be implemented. This proposal seeks to use the libhydrogen library for this task, as it is a small library comprising only a few files and which securely implements all necessary primitives and other functions required for each of these patterns. These patterns are known, under the rules of Noise, as N, KK, and XX.
The N pattern
The N pattern is the simplest out of the three patterns. Under this pattern, the client need only know the servers public key; the server needn't know anything about the client. This pattern is the simplest because it is designed for non-interactive connections where a client connects to a server, transmits an encrypted message, and disconnects, and where the client must remain anonymous to the server. Under this pattern, the following exchange occurs upon connection establishment:
The KK pattern
The KK pattern is designed for interactive connections and incorporates mutual authentication into the cryptographic scheme. Under this pattern, the client and server have long-term public keys, which they may learn via some out-of-band method not discussed here. Thus, when the client connects to the server, both are able to prove that they are indeed communicating with who they believe they are communicating with. This pattern is most likely the most secure, but also is one of the most complex to implement, as it requires that the server know every client's public key that may ever connect to it, and must be able to store them somewhere.
When connection establishment takes place, the following sequence of events occurs:
After this process completes, both client and server may transmit messages in an encrypted form, using the tx and rx keys, tx for transmission and rx for reception.
The XX pattern
The XX pattern is the most complex pattern but also the best for online protocols. The client and server don't need to know anything about one another, and generate session key pairs on the fly when the connection is established. However, this comes at a cost of two round trips:
Once this process has completed, two sets of session keys are eventually computed on both the client and the server (one set for the client and one for the server). As for the above patterns, the tx key is used for encrypting data to transmit to the server or client, and rx is for decrypting data received from the client or server, respectively.
Implementation details
libhydrogen
is a small C library licensed under the ISC license. Although it is a full cryptographic library supporting hashing, ciphers, and whatnot, this proposal is only interested in it's implementations of the above key exchange algorithms. Key pair generation is done via thehydro_kx_keygen
function. The libhydrogen documentation describes these processes in full detail here (for theN
variant), here (for theKK
variant), and here (for theXX
variant).libhydrogen is small and designed for environments where memory is constrained or resources are tight, such as embedded systems. Though this is it's primary environment, it is usable in non-constrained environments as well.
Anticipated questions
Why not do this in each NVGT application that wishes to do this?
NVGT uses angelscript as it's scripting engine. Angelscript was not designed for cryptographic operations, and there is no way to ensure that cryptographic operations are truly safe from leaking information or resources. Furthermore, these patterns can get quite complex, and it is unrealistic and unreasonable to expect each individual person to figure out cryptography on their own.
What exactly is this proposal trying to accomplish?
The goal of this proposal is to be able to either declare the connection type, or to implement one of these patterns, in such a way that the implementation is entirely transparent to the user of NVGT (the game developer). The developer should not need to care about such things when trying to ensure that the connection between server and client is secure, except in the most primitive of manners (i.e., retrieving public keys of clients, or authenticating them).
Why not wait for TLS?
TLS is definitely something to strive for, but has some significant flaws. In particular, DTLS (that is, TLS over UDP) has some significant drawbacks due to the fact that UDP is a connectionless protocol, and not many cryptographic libraries implement it. If TLS/DTLS were to be implemented, it would be unlikely it would work over connections used via Enet, and would only work for TCP/UDP/QUIC connections.
Can this be done in a plug-in?
No. The NVGT plug-in API does not allow for the interception of engine internals, such as the scanning or modification of connection states, or transmission of early connection data before a script invokes a function from that plug-in, and it would be extremely dangerous to allow a plug-in to do so. This would therefore need to be done in the NVGT core itself.
Proposed implementation strategy
This proposal recommends implementation of the XX pattern to start with. Although it is the most complex in terms of number of messages, it is also the easiest and most transparent and would require little to no modification of the networking API, other than extending it to allow for the following:
The mutual authentication interface would be simple: the developer would be given the public key of the connecting client, or the server to which they are connected to, which they could then, for example, authenticate against a trusted database of known public keys, or use to determine if a client should be allowed to continue connecting (i.e., for a banlist). Such a thing would navigate around the problem of, i.e., dynamic IP address assignment, as is commonly done nowadays with roaming mobile cariers or residential ISPs. It would be up to the developer to store the public keys in a form that would be secure to them, although as the keys are public protection would not need to be the highest priority.
However, the XX pattern does come with the significant drawback of being designed for online connections. As such, the API could in future be extended to implement the KK pattern, where the client is assigned a static public key, and the server knows said public key, which then could allow the public key to be a long-term static key which could be used for extended mutual authentication or for other purposes.
The purpose of this discussion is threefold:
Beta Was this translation helpful? Give feedback.
All reactions