我正在研究 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);
}
}
}