Closed LostSoulfly closed 6 years ago
Hey @LostSoulFly
Thanks for your interest in the library, would love to see any contributions others have to make.
Haven't given the encryption much thought as I haven't had a requirement for it yet.
A few thoughts..
I see that .Net Standard added some nice additions, so while I haven't implemented it before, I don't think it would be too tough.
I would, personally, opt to encrypt everything rather than individual packet types. I would likely use RSA to create key pairs, sign the public keys, exchange them, create an AES key on one side, sign and encrypt it with RSA, send it to the other user, verify it, then use AES for the rest of the encryption. At this point, I would look at saving the public key on both ends for future use as well. This could probably be expanded to support other crypto providers for exchange, signing, and encryption. However, those are the two I've been researching the most.
I've done some research and found NETCore.Encrypt. It looks like it should support the same targets as Networker.
I've added the ability to encrypt/decrypt Byte arrays in NETCore.Encrypt, where it previously only handled strings, so that should make things even easier and more performant without constant conversion to strings and back.
I've never used Interfaces in C# but I believe I understand how they work. I don't, however, know how I should use them to implement encryption. I'd like the encryption to be as transparent as possible so whether you call Send, SendAndHandleResponse or Broadcast while encryption is enabled and setup on both ends that it just works.
I'm still trying to figure out how best to implement it with minimal changes to existing methods. I'm thinking about creating Networker.Common.AesHandler and adding it to each TcpConnection and setting up AesHandler for each socket with unique keys/IVs, and then adding a new Packet De/Serializer methods to do the encryption/decryption before deserialization and after serialization, which would require passing connection-specific Key/IV. This would mean I'd need to prepend some data onto each packet, like whether the packet was encrypted (which would also need to be applied to the original De/Serializer methods), and the encrypted length. This could be expanded to include a unique identifier for each endpoint to solve some UDP encryption issues.
Adding the encryption to UDP adds some challenges such as determining which decryption key must be used prior to decrypting and seeing who it's from unless all clients are using the same key. Also packet segmentation?
Any insight or advice on how best to proceed to ensure this can be merged down the road is most appreciated. I could certainly do it my own way and hack it together but I'd really like to contribute in a meaningful way so others can benefit.
Hey @LostSoulFly - I've had a lot on lately but will try get back to you on this ASAP.
NETCore.Encrypt looks like a solid library which will be suitable. Let's assume for now that if encryption is enabled then every packet going through the library will be encrypted.
There are various benefits to using interfaces. We can use dependency injection to register our encryption handlers and hopefully we can support multiple encryption types.
For example, we might have an interface such as IPacketEncryptor.
public interface IPacketEncryptor
{
byte[] Encrypt(NetworkerPacketBase packetBase);
}
From this, we can create an MD5PacketEncryptor class and an AESPacketEncryptor class. Then inside the NetworkerServerBuilder class we can add new methods such as UseMd5Encryption() and UseAesEncryption(). These methods will register the encryption implementation with the IOC container.
We can create a factory class for providing the packet encryptor and decryptor.
public interface IPacketEncryption
{
IPacketEncryptor GetEncryptor();
IPacketDecryptor GetDecryptor();
byte[] GenerateKey();
void SetKey(byte[] key);
}
I think the best place to deserialize the packets will be before they are passed to the packet handlers, such as in NetworkerServerBase.HandlePacket method. This means the IPacketEncryption needs to be injected into the NetworkerServerBase class so we can call them.
IPacketEncryption will probably have to be injected into TcpConnection and UdpConnection as that is also where packets are sent. Each time we inject the IPacketEncryption the dependency injection library will create a new instance, so we can set the key for each connection.
As far as UDP goes, I think we can make the assumption for now that the user already knows the key and there is one global key for the whole instance of Networker. This means hard-coding or adding as configuration. We can revisit this in the future.
I've done a bunch of reading on IoC and it's currently above my skill level to implement it as you've laid out above, unfortunately. I'm not sure how to inject/resolve it into the TcpConnection and UdpConnection instances.
@LostSoulFly I'll try and take a look at this soon and see if I can add some stubbed code in for you.
Here's the basics of some of what you outlined above: https://github.com/LostSoulFly/Networker/commit/8f390d52b2b7e8167b58e9e6bf01221885056773
On Fri, Feb 16, 2018 at 9:48 AM, Mark Eastwood notifications@github.com wrote:
@LostSoulFly https://github.com/lostsoulfly I'll try and take a look at this soon and see if I can add some stubbed code in for you.
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/MarkioE/Networker/issues/8#issuecomment-366255280, or mute the thread https://github.com/notifications/unsubscribe-auth/AIsrB74oabPRXy-P0mt1nuP9S6pYz_Xrks5tVZVHgaJpZM4Rlkd6 .
I pulled those changes into my repo and started expanding on it here: https://github.com/MarkioE/Networker/commit/bf7890e21bbf17ad69f247bbe587b53168005326
Still work to do but hopefully that gives you a bit more insight.
See the "encryption" branch.
Closing this now as it would no longer be compatible with v3.
I see that encryption is on your road map -- and it's a feature I desperately want in a library like this.
I'm tempted to try and implement it myself in a fork, but I'd likely use something like Inferno. How are you planning to add encryption?
I was looking at the code and I figured it would be fairly easy to register some packet handlers for passing public keys between client/server and then encrypting/decrypting just before serialization/deserialization.