C# 加密.NET二进制序列化流
我在学C#的加密技术,我遇到了麻烦。我有一些,它的工作与字符串完美。但是现在我正在研究序列化,C# 加密.NET二进制序列化流,c#,encryption,C#,Encryption,我在学C#的加密技术,我遇到了麻烦。我有一些,它的工作与字符串完美。但是现在我正在研究序列化,BinaryWriter在没有任何保护的情况下编写类的数据。我正在使用;有没有“加密类”或类似的方法 为了澄清这个问题,以下是我的代码: FileStream file = new FileStream(Environment.CurrentDirectory + @"\class.dat", FileMode.Create); using (BinaryWriter sw = new BinaryWr
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));
}
谢谢 当传递到不同的流对象时,您可以将多个流链接在一起,将输出从一个流传递到另一个流的输入,而不是转换为
字节[]
这种方法在这里是有意义的,因为你是链接在一起的
二进制序列化=>加密=>写入文件
记住这一点,您可以将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
对象,这些对象可以与这些二进制序列化函数链接。下面的示例函数看起来与您链接到的文章中的加密
/解密
函数有些不同,因为现在随机生成并写入流(并从另一端的流读取)。重要的是,为安全起见,您加密的每个数据块的IV都是唯一的,您还应该使用用于加密目的的随机数生成器,如,而不是伪随机数生成器,如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);
}
请注意,我们将文件
流对象传递给CreateEncryptionStream
(和CreateDecryptionStream
),然后将加密流
对象传递给WriteObjectToStream
(和ReadObjectfromStream
)。您还将注意到,流的作用域是使用块限定在内的,因此,当我们完成它们时,它们将自动被清除
以下是完整的测试程序:
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);
}
}
}
我不确定.Net库是否已更改,或者只是代码错误。我不能直接运行软件编写的代码。
从那以后,我根据答案修改了代码,以便正确使用。这里有一个例子
公共类加密序列化
{
公共静态void WriteObjectToStream(Stream outputStream,object obj)
{
如果(obj为null)抛出新ArgumentNullException(“obj不能为null”);
BinaryFormatter bf=新的BinaryFormatter();
序列化(outputStream,obj);
}
公共静态对象ReadObjectFromStream(Stream inputStream)
{
BinaryFormatter bf=新的BinaryFormatter();
返回bf.反序列化(inputStream);
}
公共静态加密流CreateEncryptionStream(流输出流,字节[]密钥,字节[]IV)
{
Rijndael Rijndael=新的RijndaelManaged();
返回新的加密流(outputStream,rijndael.CreateEncryptor(Key,IV),CryptoStreamMode.Write);
}
公共静态加密流CreateDecryptionStream(流输入流,字节[]密钥,字节[]IV)
{
Rijndael Rijndael=新的RijndaelManaged();
返回新的加密流(inputStream,rijndael.CreateDecryptor(Key,IV),CryptoStreamMode.Read);
}
公共静态void EncryptObjectToFile(对象对象对象,字符串路径,字节[]键,字节[]IV)
{
使用FileStream file=newfilestream(路径,FileMode.Create);
使用(CryptoStream CryptoStream=CreateEncryptionStream(文件、密钥、IV))
{
WriteObjectToStream(cryptoStream,obj);
}
}
公共静态对象DecryptObjectFromFile(字符串路径,字节[]密钥,字节[]IV)
{
使用FileStream file=newfilestream(路径,FileMode.Open);
使用(CryptoStream CryptoStream=CreateDecryptionStream(文件、密钥、IV))
{
返回ReadObjectFromStream(cryptoStream);
}
}
}
[可序列化]
公立班学生
{
公共字符串名称;
公共信息;
}
静态异步任务主(字符串[]args)
{
//原始字符串“[这是一个示例键字符串!]”;
//我不知道字符串的长度是否必须是32,但当我尝试64时,它出错了。
字符串cryptoKey=“W1ROAXMGYW4GZXHHBXBSSBRZXKGC3RYAW5NIV0=”;
字节[]键=Convert.FromBase64String(加密键);
字节[]IV=新字节[16];
使用(RNGCryptoServiceProvider rngcsp=new RNGCryptoServiceProvider())
{
rngcsp.GetBytes(IV);
}
//同
//Rijndael Rijndael=新的RijndaelManaged();
//rijndael.GenerateIV();
//字节[]iv=rijndael.iv;
列出学生=新名单(){新学生{Name=“John”,年龄=10},新学生{Name=“Marry”,年龄=15};
CryptoSerialization.EncryptObjectToFile(学生,Environment.CurrentDirectory+@“\testCrypto.dat”,密钥,IV);
List newStudents=(List)CryptoSerialization.DecryptObjectFromFile(Environment.CurrentDirectory+@“\testCrypto.dat”,Key,IV);
newStudents.ForEach((stu)=>
{
控制台写入线(stu.Name+,“+stu.Age);
});
Console.ReadKey();
}
您可以在ConverteObject和ConverteByteObject内部使用。在链接中有Rijndael的例子…非常感谢!!我在这里测试过,它在多个类中都能完美地工作。只有一个问题,出于安全原因,我更改了加密密钥,但我不知道这是什么bIV,这是可变的吗?再次感谢这是个好问题。为安全起见,您加密的每个文件的IV都应该是唯一的(不要再次使用相同的IV)。我已经更新了示例,以显示它是随机生成的,并写入和读取文件,这将是通常的方法。我尝试了更改,但我不知道如何生成新的IV。如何做?您看到我的示例的更新了吗,我在其中随机生成了IV?