So I have a basic crypto class. Note that this is a simplified implementation to illustrate the question.
Now to my mind both these methods have an extra byte array and string instance.
xmlString
and bytes
in Encrypt
and
decryptedString
and decryptedBytes
in Decrypt
So how can I rework the usage of streams in this class to minimize the memory usage?
class Crypto
{
Rijndael rijndael;
public Crypto()
{
rijndael = Rijndael.Create();
rijndael.Key = Encoding.ASCII.GetBytes("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); ;
rijndael.IV = Encoding.ASCII.GetBytes("bbbbbbbbbbbbbbbb"); ;
rijndael.Padding = PaddingMode.PKCS7;
}
public byte[] Encrypt(object obj)
{
var settings = new XmlWriterSettings
{
OmitXmlDeclaration = true
};
var ns = new XmlSerializerNamespaces();
ns.Add("", "");
var sb = new StringBuilder();
var xmlSerializer = new XmlSerializer(obj.GetType());
using (var xmlWriter = XmlWriter.Create(sb, settings))
{
xmlSerializer.Serialize(xmlWriter, obj, ns);
xmlWriter.Flush();
}
var xmlString = sb.ToString();
var bytes = Encoding.UTF8.GetBytes(xmlString);
using (var encryptor = rijndael.CreateEncryptor())
using (var stream = new MemoryStream())
using (var crypto = new CryptoStream(stream, encryptor, CryptoStreamMode.Write))
{
crypto.Write(bytes, 0, bytes.Length);
crypto.FlushFinalBlock();
stream.Position = 0;
var encrypted = new byte[stream.Length];
stream.Read(encrypted, 0, encrypted.Length);
return encrypted;
}
}
public T Decrypt<T>(byte[] encryptedValue)
{
byte[] decryptedBytes;
using (var decryptor = rijndael.CreateDecryptor())
using (var stream = new MemoryStream())
using (var crypto = new CryptoStream(stream, decryptor, CryptoStreamMode.Write))
{
crypto.Write(encryptedValue, 0, encryptedValue.Length);
crypto.FlushFinalBlock();
stream.Position = 0;
decryptedBytes = new Byte[stream.Length];
stream.Read(decryptedBytes, 0, decryptedBytes.Length);
}
var ser = new XmlSerializer(typeof(T));
var decryptedString = Encoding.UTF8.GetString(decryptedBytes);
using (var stringReader = new StringReader(decryptedString))
using (var xmlReader = new XmlTextReader(stringReader))
{
return (T)ser.Deserialize(xmlReader);
}
}
}
And here is a unit test
[TestFixture]
public class Tests
{
[Test]
public void Run()
{
var before = new MyClassForSerialize()
{
Property = "Sdf"
};
var dataEncryptor = new Crypto();
var encrypted = dataEncryptor.Encrypt(before);
var after = dataEncryptor.Decrypt<MyClassForSerialize>(encrypted);
Assert.AreEqual(before.Property, after.Property);
}
}
public class MyClassForSerialize
{
public string Property { get; set; }
}
=== Edit ===
Based on the anser from Damien_The_Unbeliever I tried this. Which fails the unit test
public byte[] Encrypt(object obj)
{
var settings = new XmlWriterSettings
{
OmitXmlDeclaration = true
};
var ns = new XmlSerializerNamespaces();
ns.Add("", "");
var xmlSerializer = new XmlSerializer(obj.GetType());
using (var encryptor = rijndael.CreateEncryptor())
using (var stream = new MemoryStream())
using (var crypto = new CryptoStream(stream, encryptor, CryptoStreamMode.Write))
{
using (var xmlWriter = XmlWriter.Create(crypto, settings))
{
xmlSerializer.Serialize(xmlWriter, obj, ns);
xmlWriter.Flush();
}
crypto.FlushFinalBlock();
stream.Position = 0;
return stream.ToArray();
}
}