Search code examples
c#encryptionserializationaes

Encrypt and Decrypt a List of objects to byte[]


Current solution

So, I got a reliable AES ( Rijndael ) decryption and encryption methods for C# that can transform strings into an array of bytes ( byte[] ).

This is very useful, since it allows me to send and receive information secured by symmetric cryptography to the network.

Method for encryption ( string to byte[] ):

private byte[] EncryptStringToBytes(string plainText, byte[] Key, byte[] IV)
        {
            if (plainText == null || plainText.Length <= 0)
                throw new ArgumentNullException("plainText");
            if (Key == null || Key.Length <= 0)
                throw new ArgumentNullException("Key");
            if (IV == null || IV.Length <= 0)
                throw new ArgumentNullException("IV");
            byte[] encrypted;

            using (RijndaelManaged rijAlg = new RijndaelManaged())
            {
                rijAlg.Key = Key;
                rijAlg.IV = IV;

                ICryptoTransform encryptor = rijAlg.CreateEncryptor(rijAlg.Key, rijAlg.IV);

                using (MemoryStream msEncrypt = new MemoryStream())
                {
                    using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
                    {
                        using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
                        {
                            swEncrypt.Write(plainText);
                        }
                        encrypted = msEncrypt.ToArray();
                    }
                }
            }
            return encrypted;
        }

Method for decryption ( byte[] to string ):

private string DecryptStringFromBytes(byte[] cipherText, byte[] Key, byte[] IV)
        {
            if (cipherText == null || cipherText.Length <= 0)
                throw new ArgumentNullException("cipherText");
            if (Key == null || Key.Length <= 0)
                throw new ArgumentNullException("Key");
            if (IV == null || IV.Length <= 0)
                throw new ArgumentNullException("IV");

            string plaintext = null;

            using (RijndaelManaged rijAlg = new RijndaelManaged())
            {
                rijAlg.Key = Key;
                rijAlg.IV = IV;

                ICryptoTransform decryptor = rijAlg.CreateDecryptor(rijAlg.Key, rijAlg.IV);
                try
                {
                    using (MemoryStream msDecrypt = new MemoryStream(cipherText))
                    {
                        using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
                        {
                            using (StreamReader srDecrypt = new StreamReader(csDecrypt))
                            {
                                plaintext = srDecrypt.ReadToEnd();
                            }
                        }
                    }
                }
                catch (Exception)    //if decription doesnt work, do normal conversion
                {
                    plaintext = Encoding.Unicode.GetString(cipherText);
                }
            }
            return plaintext;
        }

Problem

Now the necessity is to send and receive an entire List of custom objects over the network, while still using AES cryptography.

I need to encrypt an entire List< CustomObject> to byte[] and then later be able to decrypt it from byte[] to List< CustomObject>. Keep in mind that CustomObject is a example / Foo class.

But I don't know how I could modify these methods to use my List< CustomObject> instead of string. Nothing seems to work so far...

The List< CustomObject> I want to convert:

public List<CustomObject> ListCustomObjects = new List<CustomObject>();

And this is the CustomObject class inside the List<>:

public class CustomObject
    {
        public string NameFoo { get; set; }
        public float NumberFoo { get; set; }
        public bool ConditionFoo { get; set; }
    }

Any solutions? Converting the list of objects to an encrypted byte array and be able to convert it back to list when needed is vital to this project.


Solution

  • How about you serialize it to a string first and then encrypt.

    Then on the other side, decrypt and deserialize.

    One format to represent an object as a string is JSON, and serialize/deserialize to JSON is build into dotnet since dotnet core 3. You can also use Newtonsoft.JSON (which used to be the default json serializer for c#)

    So you can add the following code:

    // using System.Text.Json;
    // using System.Text.Json.Serialization;
    private byte[] EncryptObjectToBytes<T>(T inputObject, byte[] Key, byte[] IV) {
      var jsonString = JsonSerializer.Serialize(inputObject);
      return EncryptStringToBytes(jsonString, Key, IV);
    }
    
    // and for the other side
    private T DecryptObjectFromBytes<T>(byte[] cipherText, byte[] Key, byte[] IV) {
      var jsonString = DecryptStringFromBytes(cipherText, Key, IV);
      return JsonSerializer.Deserialize<T>(jsonString);
    }
    
    // Call the decryption like:
    DecryptObjectFromBytes<YourClassName>(...);
    // or for collections
    DecryptObjectFromBytes<List<YourClassName>>(...);
    
    

    You can even optimize the above code (because you can also (de)serialize to and from a byte array, which would make it even faster. And you can also use the async SerializeAsync and DeserializeAsync methods, but this code should get you started.

    Other serialization methods

    Using JSON is preferred (by me) because of the fact that you as a human can also read the data that is inside and it's less bytes then xml. You can also consider these formats.

    • MessagePack (serialization to a by humans none readable byte array) = way smaller for big objects.
    • XML this is what developers used to use before they invented json. Looks like html, but needs way more charcters to serialize a message.