-
-
Notifications
You must be signed in to change notification settings - Fork 44
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
Noise protocol framework implementation #142
base: main
Are you sure you want to change the base?
Conversation
This reverts commit 14246c9.
Update: so question 6 is partially solved, at least for ENet (for other protocols running over unreliable transports this is a case-by-case basis problem): the handshake needn't be performed via an unreliable stream. |
Okay, so I've done a lot of thinking, and with the current networking setup the implementation of the actual handshake will be trivial. The remaining question mainly has to do with the handshake pattern. Since the opening of this PR the noise implementation has undergone some significant overhauling, fixing several bugs and moving the handshake state parameters into a configuration struct so that we can store that and then create a new state on the fly whenever we need it. The patterns I'm zooming in on are the KK, KN, XN, or XX patterns. I believe these might be the most suitable because:
As a reminder, the letters in the pattern describe, for the server and client (in that order), the authentication levels:
If we use the process of elimination here, the KK or KN patterns make the most sense, since it can be reasonably assumed that a developer who's making a networked application has control over both the code of the client and server applications. Thus, the developer knows both keys on both ends. The downside to the KK pattern is that, to be effective, the developer would need to add a key generation step for each client installation, and figure out how to permanently store it, since an ephemeral key defeats the purpose of "knowing" anything. This however would be a one-time thing and wouldn't need to be done again, and key pairs are only 64 bytes (32 bytes for the private key and 32 bytes for the public key) so are prime candidates for encoding via something like hex or base64. The KN pattern might however be the simplest to start with: the developer can assume that the client cannot be trusted, as is probably a good idea anyway, but can also authenticate the server. Should that fail, then we know that either the connection has been tampered with or the server's key pair has changed. However, the authentication failure doesn't present itself in an obvious manner (it causes an encryption/decryption failure), but I question whether this will actually be an issue, since if we do encounter this problem we can safely assume that a critical error has occurred, and immediately abort. The advantage to the XN or XX patterns is that, although the keys are known ahead-of-time, they are transmitted during the handshake. That in turn allows game developers to perform their own form of mutual authentication as they see fit, but places the burden of actually doing this onto them, and I'd like this to be as low-overhead as possible. (Mutual authentication can take any form that the developer wants, and usually boils down to "is there a reason to reject this public key?".) Obviously, this would enable many other possibilities as well, but better to start simple and focus on extending this as time goes on. I would appreciate any input/thoughts/opinions. I'm doing my best to not over-complicate this entire process while at the same time being thoughtful about it. My idea is that, if you want this to be used, you need only do two extra things at most: (1) set up some key generation method in your app as a one-time thing, and (2) add, after |
This PR is the one where the Noise implementation will be tracked (see discussion #96 for more). It is reasonably expected that this PR will take quite a while to implement. As much as I would like to grant people network encryption immediately, this is not something that we can rush, lest we make critical mistakes that we cannot come back from.
This initial set of commit contains:
The last two changes are ancillary at best though probably wise to do.
During the implementation phase, some questions need to be answered, as follows:
setup_client
/setup_server
/setup_local_server
; the idea is that the transition should be decently smooth and only require at most an additional few lines to generate the initial key pairs (assuming we go with the XX pattern or similar) and then loading them.Internally, the general idea is that the overall execution of the cryptographic subsystem would work as follows:
At this point, the server or client could perform channel binding if it wishes to by retrieving the handshake hash. That in turn would allow the receiving party to authenticate the receiving party using that hash via some application-defined method such as signatures, passwords, etc., because the token is unique to each session and cannot be used for any other. This is entirely optional however.
So, yeah, lots to consider. I've also added in some other internal bits to the network class that shouldn't actually affect it in any way yet. I would've submitted a much fuller PR but I am uncertain about implementation details, hence me opening it early and raising these considerations. However, the base infrastructure is present, and I think this PR is ready for a collaborative development process now that the most complicated portion is reasonably complete.