如何在序列化后加密并保存二进制流并将其读回?

当我想在二进制序列化后加密二进制流并将其保存到文件时,我在使用CryptoStream时遇到一些问题。 我收到以下exception

System.ArgumentException : Stream was not readable. 

任何人都可以告诉我如何加密二进制流并将其保存到文件并正确反序列化?

代码如下:

 class Program { public static void Main(string[] args) { var b = new B {Name = "BB"}; WriteFile(@"C:\test.bin", b, true); var bb = ReadFile(@"C:\test.bin", true); Console.WriteLine(b.Name == bb.Name); Console.ReadLine(); } public static T ReadFile(string file, bool decrypt) { T bObj = default(T); var _binaryFormatter = new BinaryFormatter(); Stream buffer = null; using (var stream = new FileStream(file, FileMode.OpenOrCreate)) { if(decrypt) { const string strEncrypt = "*#4$%^.++q~!cfr0(_!#$@$!&#&#*&@(7cy9rn8r265&$@&*E^184t44tq2cr9o3r6329"; byte[] dv = {0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF}; CryptoStream cs; DESCryptoServiceProvider des = null; var byKey = Encoding.UTF8.GetBytes(strEncrypt.Substring(0, 8)); using (des = new DESCryptoServiceProvider()) { cs = new CryptoStream(stream, des.CreateEncryptor(byKey, dv), CryptoStreamMode.Read); } buffer = cs; } else buffer = stream; try { bObj = (T) _binaryFormatter.Deserialize(buffer); } catch(SerializationException ex) { Console.WriteLine(ex.Message); } } return bObj; } public static void WriteFile(string file, T bObj, bool encrypt) { var _binaryFormatter = new BinaryFormatter(); Stream buffer; using (var stream = new FileStream(file, FileMode.Create)) { try { if(encrypt) { const string strEncrypt = "*#4$%^.++q~!cfr0(_!#$@$!&#&#*&@(7cy9rn8r265&$@&*E^184t44tq2cr9o3r6329"; byte[] dv = {0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF}; CryptoStream cs; DESCryptoServiceProvider des = null; var byKey = Encoding.UTF8.GetBytes(strEncrypt.Substring(0, 8)); using (des = new DESCryptoServiceProvider()) { cs = new CryptoStream(stream, des.CreateEncryptor(byKey, dv), CryptoStreamMode.Write); buffer = cs; } } else buffer = stream; _binaryFormatter.Serialize(buffer, bObj); buffer.Flush(); } catch(SerializationException ex) { Console.WriteLine(ex.Message); } } } } [Serializable] public class B { public string Name {get; set;} } 

它抛出序列化exception如下

输入流不是有效的二进制格式。 起始内容(以字节为单位)为:3F-17-2E-20-80-56-A3-2A-46-63-22-C4-49-56-22-B4-DA ……

如果你这样做,它应该工作:

 // A: encrypting when writing // 1. create backing storage stream. In your case a file stream using(Stream innerStream = File.Create(path)) // 2. create a CryptoStream in write mode using(Stream cryptoStream = new CryptoStream(innerStream, encryptor, CryptoStreamMode.Write)) { // 3. write to the cryptoStream binaryFormatter.Serialize(cryptoStream, obj); } // B: decrypting when reading // 1. create backing storage stream. In your case a file stream using(Stream innerStream = File.Open(path, FileMode.Open)) // 2. create a CryptoStream in read mode using(Stream cryptoStream = new CryptoStream(innerStream, decryptor, CryptoStreamMode.Read)) { // 3. read from the cryptoStream obj = binaryFormatter.Deserialize(cryptoStream); } 

您的代码存在一些问题:

  1. 你正在阅读时使用加密器。 这可能是一个错字,但它应该是一个解密者。

  2. 您正在刷新buffer ,但使用CryptoStream时这还不够。 加密器和解密器适用于固定大小的块。 最后一个块可能没有那么大,所以需要特殊处理。 最后一个块是在流关闭之前写入的块,而不是刷新的 。 刷新CryptoStream没有任何用处,因为它不能写任何大小小于加密器/解密器的输入块大小的东西,除非它是最后写的东西。 除此之外,总的来说,无论如何,你都应该关闭你的溪流。 using语句是推荐的方法:

     using(buffer) _binaryFormatter.Serialize(buffer, bObj); 

有关如何在MSDN文档中执行此操作的一个很好的示例: CryptoStream MSDN它位于“示例”部分中。

程序基本上是这样的:

  1. 创建cryptostream(空流)
  2. 将内容写入cryptostream(加密)
  3. 将cryptostream保存到文件
  4. 从文件内容创建cryptostream
  5. 从cryptostream读取(解密)