Skip to main content
 首页 » 编程设计

c#之加密 .NET 二进制序列化流

2024年09月07日34xing901022

我正在研究 C# 中的加密,但遇到了麻烦。我有一些 Rijndael encryption code它与字符串完美配合。但现在我正在研究序列化和 BinaryWriter在没有任何保护的情况下写入类的数据。我正在使用 this code to test ;有没有办法“加密类(class)”或类似的东西?

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

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 (Initialization Vector)现在随机生成并写入流(并从另一端的流中读取)。重要的是,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); 
        } 
    } 
}