加密.NET二进制序列化流

我在C#学习加密,我遇到了麻烦。 我有一些Rijndael加密代码 ,它与字符串完美配合。 但现在我正在研究序列化,而BinaryWriter在没有任何保护的情况下写入类的数据。 我正在使用此代码进行测试 ; 有没有办法“加密类”,或类似的东西?

为了澄清这个问题,这是我的代码:

 FileStream file = new FileStream(Environment.CurrentDirectory + @"\class.dat", FileMode.Create); using (BinaryWriter sw = new BinaryWriter(file)) { byte[] byt = ConverteObjectEmByte(myVarClass); sw.Write(byt); } 

这就是我读它的方式:

 MyClass newMyVarClass; FileStream file = new FileStream(Environment.CurrentDirectory + @"\class.dat", FileMode.Open); using (BinaryReader sr = new BinaryReader(file)) { // 218 is the size of the byte array that I've tested (byt) myNewVarClass = (MyClass)ConverteByteEmObject(sr.ReadBytes(218)); } 

谢谢!

传递给不同的流对象时,不是转换为byte[]作为中间步骤,而是可以将多个流链接在一起,将输出从一个传递到另一个的输入。

这种方法在这里有意义,因为你在一起链接

二进制序列化 => 加密 => 写入文件

考虑到这一点,您可以将ConvertObjectEmByte更改为:

 public static void WriteObjectToStream(Stream outputStream, Object obj) { if (object.ReferenceEquals(null, obj)) { return; } BinaryFormatter bf = new BinaryFormatter(); bf.Serialize(outputStream, obj); } 

同样, ConvertByteEmObject可以变为:

 public static object ReadObjectFromStream(Stream inputStream) { BinaryFormatter binForm = new BinaryFormatter(); object obj = binForm.Deserialize(inputStream); return obj; } 

要添加加密/解密,我们可以编写创建CryptoStream对象的函数,我们可以使用这些二进制序列化函数进行链接。 下面的示例函数与您链接的文章中的Encrypt / Decrypt函数略有不同,因为IV(初始化向量)现在是随机生成的并写入流(并从另一端的流中读取)。 重要的是,对于为安全性而加密的每个数据块,IV都是唯一的,并且您还应该使用用于加密目的的随机数生成器(如RNGCryptoServiceProvider ,而不是像Random这样的伪随机数生成器。

 public static CryptoStream CreateEncryptionStream(byte[] key, Stream outputStream) { byte[] iv = new byte[ivSize]; using (var rng = new RNGCryptoServiceProvider()) { // Using a cryptographic random number generator rng.GetNonZeroBytes(iv); } // Write IV to the start of the stream outputStream.Write(iv, 0, iv.Length); Rijndael rijndael = new RijndaelManaged(); rijndael.KeySize = keySize; CryptoStream encryptor = new CryptoStream( outputStream, rijndael.CreateEncryptor(key, iv), CryptoStreamMode.Write); return encryptor; } public static CryptoStream CreateDecryptionStream(byte[] key, Stream inputStream) { byte[] iv = new byte[ivSize]; if (inputStream.Read(iv, 0, iv.Length) != iv.Length) { throw new ApplicationException("Failed to read IV from stream."); } Rijndael rijndael = new RijndaelManaged(); rijndael.KeySize = keySize; CryptoStream decryptor = new CryptoStream( inputStream, rijndael.CreateDecryptor(key, iv), CryptoStreamMode.Read); return decryptor; } 

最后,我们可以把它粘在一起:

 byte[] key = Convert.FromBase64String(cryptoKey); using (FileStream file = new FileStream(Environment.CurrentDirectory + @"\class.dat", FileMode.Create)) using (CryptoStream cryptoStream = CreateEncryptionStream(key, file)) { WriteObjectToStream(cryptoStream, myVarClass); } MyClass newMyVarClass; using (FileStream file = new FileStream(Environment.CurrentDirectory + @"\class.dat", FileMode.Open)) using (CryptoStream cryptoStream = CreateDecryptionStream(key, file)) { newMyVarClass = (MyClass)ReadObjectFromStream(cryptoStream); } 

请注意,我们将file流对象传递给CreateEncryptionStream (和CreateDecryptionStream ),然后将cryptoStream对象传递给WriteObjectToStream (和ReadObjectfromStream )。 您还会注意到流using块进行内部限制,以便在我们完成它们时自动清理它们。

这是完整的测试程序:

 using System; using System.IO; using System.Runtime.Serialization.Formatters.Binary; using System.Security.Cryptography; namespace CryptoStreams { class Program { [Serializable] public class MyClass { public string TestValue { get; set; } public int SomeInt { get; set; } } public static void WriteObjectToStream(Stream outputStream, Object obj) { if (object.ReferenceEquals(null, obj)) { return; } BinaryFormatter bf = new BinaryFormatter(); bf.Serialize(outputStream, obj); } public static object ReadObjectFromStream(Stream inputStream) { BinaryFormatter binForm = new BinaryFormatter(); object obj = binForm.Deserialize(inputStream); return obj; } private const string cryptoKey = "Q3JpcHRvZ3JhZmlhcyBjb20gUmluamRhZWwgLyBBRVM="; private const int keySize = 256; private const int ivSize = 16; // block size is 128-bit public static CryptoStream CreateEncryptionStream(byte[] key, Stream outputStream) { byte[] iv = new byte[ivSize]; using (var rng = new RNGCryptoServiceProvider()) { // Using a cryptographic random number generator rng.GetNonZeroBytes(iv); } // Write IV to the start of the stream outputStream.Write(iv, 0, iv.Length); Rijndael rijndael = new RijndaelManaged(); rijndael.KeySize = keySize; CryptoStream encryptor = new CryptoStream( outputStream, rijndael.CreateEncryptor(key, iv), CryptoStreamMode.Write); return encryptor; } public static CryptoStream CreateDecryptionStream(byte[] key, Stream inputStream) { byte[] iv = new byte[ivSize]; if (inputStream.Read(iv, 0, iv.Length) != iv.Length) { throw new ApplicationException("Failed to read IV from stream."); } Rijndael rijndael = new RijndaelManaged(); rijndael.KeySize = keySize; CryptoStream decryptor = new CryptoStream( inputStream, rijndael.CreateDecryptor(key, iv), CryptoStreamMode.Read); return decryptor; } static void Main(string[] args) { MyClass myVarClass = new MyClass { SomeInt = 1234, TestValue = "Hello" }; byte[] key = Convert.FromBase64String(cryptoKey); using (FileStream file = new FileStream(Environment.CurrentDirectory + @"\class.dat", FileMode.Create)) { using (CryptoStream cryptoStream = CreateEncryptionStream(key, file)) { WriteObjectToStream(cryptoStream, myVarClass); } } MyClass newMyVarClass; using (FileStream file = new FileStream(Environment.CurrentDirectory + @"\class.dat", FileMode.Open)) using (CryptoStream cryptoStream = CreateDecryptionStream(key, file)) { newMyVarClass = (MyClass)ReadObjectFromStream(cryptoStream); } Console.WriteLine("newMyVarClass.SomeInt: {0}; newMyVarClass.TestValue: {1}", newMyVarClass.SomeInt, newMyVarClass.TestValue); } } }