2

I am working on a project where I need to implement encryption for sending quite large amounts of data through a tcp connection. I wish to write it in C#. The project is also a part of my learning, by implementing such encryption I'll get experience.

I've made some research and tested some things out and I've written how I think I have to go about implementing it below.

Basically, I'd like to ask if someone could please check what I've written below and warn me about any mistakes, security holes or incorrect statements I made. Pointing those out and explaining what I should do to rectify the problems is greatly appreciated.

  1. We have host A and B connected via tcp.
  2. Host A creates an instance of System.Security.Cryptography.RSA via RSA.Create(2048). By doing that, the RSA instance created random public and private keys. The private key can be used to decrypt data that was encrypted by the public key. The public key can be derived from the private key, but reverse is impossible.
  3. A calls rsa.ExportParameters(includePrivateParameters: false); to export the public key and uses some serializer like XmlSerializer to serialize the RSAParameters object into bytes. A can then send the serialized object via TCP with no encryption to B.
  4. B receives and deserializes the RSAParameters object and uses it for creating it's own instance of RSA: RSA.Create(deserializedRSApar);. The RSA object of B now has the public key of A's RSA and thus can encrypt data so that noone else but A can decrypt it because A has the private key.
  5. B creates an instance of System.Security.Cryptography.Aes in CBC mode with 256 bit key and 16 byte IV.
  6. B encrypts the AES key using the RSA object with the imported public key and sends it back to A.
  7. A receives the encrypted data and decrypts it using it's private key and creates it's own instance of System.Security.Cryptography.Aes and sets the key it decrypted. The RSA objects can now be disposed because both hosts have the same AES key.
  8. Further communication will be encrypted with AES in separate messages, the hosts need to use a different unpredictable IV for each of the messages, IV will be prepended in plain bytes before the encrypted data. I will also be putting the length of the given message after IV and before the encrypted data.. I've written it to write the length of the data before encryption because I've heard that AES does not change data length when encrypting.

A part of the method used for sending should look something like this:

        aes.GenerateIV();
        using(var writer = new BinaryWriter(networkStream))
        using(var encryptor = aes.CreateEncryptor())
        using(var cryptoWriter = new CryptoStream(networkStream, encryptor, CryptoStreamMode.Write))
        {
            writer.Write(aes.IV);
            writer.Write((int)bytesToSend.Length);
            cryptoWriter.Write(bytesToSend, 0, bytesToSend.Length);
        } 

And a part of the method for receiving should look something like this:

        using(var reader = new BinaryReader(networkStream))
        using(var decryptor = aes.CreateDecryptor(aes.Key, reader.ReadBytes(aes.IV.Length)))
        using(var cryptoReader = new CryptoStream(networkStream, decryptor, CryptoStreamMode.Read))
        {
            int toRead = reader.ReadInt32();
            if (toRead > bufferArray.Length)
                throw new Exception("Throw an exception or handle in another way, unimportant for now");
            cryptoReader.Read(bufferArray, 0, toRead);
        }

I know I should be creating those BinaryReaders and Writers out of scope of the method, I wrote the usings here (as well as that needless (int) cast) to show my intent better than "There is a BinaryReader in the class this snippet of a method is in"

Another question I'd like to ask is: Does it matter how long the messages will be? Is there a limit to how big the messages should be? I don't intend on sending messages bigger than 32kB.

Petrusion
  • 940
  • 4
  • 11
  • 1
    Well, that's a start. Now you need to consider authenticating the endpoints, computing a MAC over the messages, choosing a mode for AES ... many little things that are important. At each step you should compare your protocol to TLS and try to figure out why TLS does it their way. – President James K. Polk Sep 10 '20 at 00:06
  • As long as you're in the learning stage, I recommend [the paper](https://cr.yp.to/highspeed/coolnacl-20120725.pdf) describing NaCl and the derived implementations, specifically [libsodium](https://doc.libsodium.org/). The NaCl design hinges on encrypting messages much like you're doing here (rather than a stream-based design which is prevalent in most SSL implementations) but with a specific emphasis on making things secure *without* making the developer think about the details (and getting them wrong). Disclaimer: I'm not involved with the projects in any way. – Jeroen Mostert Sep 10 '20 at 08:25
  • @PresidentJamesK.Polk Thank you for your answer. Could you please set me on the right track to computing MACs over the messages / authorizing messages? As far as I've seen, System.Security.Cryptography.Aes doesn't really have any method with "mac" or "auth" in it's name. Does someting else that comes with C# do that? Will I have to do Aes in a completely different way? – Petrusion Sep 12 '20 at 18:45
  • @JeroenMostert I'll be sure to read the links you posted, thank you. – Petrusion Sep 12 '20 at 18:46
  • There are modes of AES that include a built-in MAC. The most well-known of these is AES-GCM and it is provided by the AesGcm class in .Net Core. Use a 12-byte nonce filled by an instance of RandomNumberGenerator and a 16-byte tag. – President James K. Polk Sep 12 '20 at 19:42
  • another post you will want to read... https://security.stackexchange.com/questions/18197/why-shouldnt-we-roll-our-own – DarkSquirrel42 Sep 13 '20 at 22:11
  • don't roll your own crypto does not only mean don't invent you own primitives (you've choosen RSA and AES, so far so good...) but the whole protocol ... what you have is prone to man in the middle attacks for example... – DarkSquirrel42 Sep 13 '20 at 22:19

0 Answers0