如何在加密和解密期间避免额外的内存使用?

所以我有一个基本的加密类。 请注意,这是一个简化的实现来说明问题。

现在我想这两个方法都有一个额外的字节数组和字符串实例。

Encrypt xmlStringbytes

decryptedBytes中的DecryptDecrypt

那么如何重新设计此类中的流的使用以最小化内存使用?

 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(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); } } } 

这是一个unit testing

 [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(encrypted); Assert.AreEqual(before.Property, after.Property); } } public class MyClassForSerialize { public string Property { get; set; } } 

===编辑===

基于Damien_The_Unbeliever的anser,我尝试了这个。 哪个unit testing失败了

 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(); } } 

您可以直接在CryptoStream之上构建XmlWriter (将crypto传递给XmlWriter.Create ),而不是使用单独的缓冲区。 (同上解密)

MemoryStream有一个ToArray方法,因此您不必手动分配,重新定位和读取它。

除此之外,它看起来像一个合理的实施 – 是否有需要修复的具体问题?


根据您的编辑,如果我将解密更改为:

  public T Decrypt(byte[] encryptedValue) { using (var decryptor = rijndael.CreateDecryptor()) using (var stream = new MemoryStream(encryptedValue)) using (var crypto = new CryptoStream(stream, decryptor, CryptoStreamMode.Read)) using (var xmlReader = XmlReader.Create(crypto)) { var ser = new XmlSerializer(typeof(T)); return (T)ser.Deserialize(xmlReader); } } 

然后它似乎对我有用。


新版本包含XML BOM,而旧版本则不包括。 XmlReader 应该应付,我想,但似乎没有。 在Encrypt尝试以下设置:

 var settings = new XmlWriterSettings { OmitXmlDeclaration = true, Encoding = new UTF8Encoding(false) }; 

现在它适用于旧的Decryptfunction。

完整解决方案

加密

 public byte[] Encrypt(object obj) { var settings = new XmlWriterSettings { OmitXmlDeclaration = true, Encoding = new UTF8Encoding(false) }; 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(); return stream.ToArray(); } } 

解码

 public T Decrypt(byte[] encryptedValue) { using (var decryptor = rijndael.CreateDecryptor()) using (var stream = new MemoryStream(encryptedValue)) using (var crypto = new CryptoStream(stream, decryptor, CryptoStreamMode.Read)) { var ser = new XmlSerializer(typeof(T)); return (T)ser.Deserialize(crypto); } }