C#在写入磁盘之前加密序列化文件

时间:2011-05-03 13:08:50

标签: c# serialization encryption

假设我的程序有一个名为“customer”的类,并且客户类是可序列化的,因此我可以读取并将其写入磁盘。客户类持有我想要加密的敏感信息,我知道可以保证文件安全的唯一方法是:

  

1 - 将文件序列化为磁盘

     

2 - 重新打开并加载文件

     

3 - 加密文件

     

4 - 将文件重写到磁盘

这样可行,但是文件可能会在未加密的状态下被拦截,而且这样做效率非常低。

相反,我想:

  

1 - 在内存中创建文件

     

2加密内存中的文件

     

3 - 将加密文件写入磁盘

这可能吗?如果是这样的话?提前谢谢。

4 个答案:

答案 0 :(得分:33)

您可以在将类序列化为文件的同时使用CryptoStream进行加密:

byte[] key = { 1, 2, 3, 4, 5, 6, 7, 8 }; // Where to store these keys is the tricky part, 
    // you may need to obfuscate them or get the user to input a password each time
byte[] iv = { 1, 2, 3, 4, 5, 6, 7, 8 };
string path = @"C:\path\to.file";

DESCryptoServiceProvider des = new DESCryptoServiceProvider();

// Encryption
using (var fs = new FileStream(path, FileMode.Create, FileAccess.Write))
using (var cryptoStream = new CryptoStream(fs, des.CreateEncryptor(key, iv), CryptoStreamMode.Write))
{
    BinaryFormatter formatter = new BinaryFormatter();

    // This is where you serialize the class
    formatter.Serialize(cryptoStream, customClass);
}

// Decryption
using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read))
using (var cryptoStream = new CryptoStream(fs, des.CreateDecryptor(key, iv), CryptoStreamMode.Read))
{
    BinaryFormatter formatter = new BinaryFormatter();

    // This is where you deserialize the class
    CustomClass deserialized = (CustomClass)formatter.Deserialize(cryptoStream);
}

答案 1 :(得分:25)

除了评论中表达的担忧之外,如果您要问的是如何处理内存中的字节并且只将它们写入文件一次,那么首先将对象序列化为内存流。加密这些字节并将它们写入文件。

using (var fileStream = File.OpenWrite(theFileName))
using (var memoryStream = new MemoryStream())
{
    // Serialize to memory instead of to file
    var formatter = new BinaryFormatter();
    formatter.Serialize(memoryStream, customer);

    // This resets the memory stream position for the following read operation
    memoryStream.Seek(0, SeekOrigin.Begin);

    // Get the bytes
    var bytes = new byte[memoryStream.Length];
    memoryStream.Read(bytes, 0, (int)memoryStream.Length);

    // Encrypt your bytes with your chosen encryption method, and write the result instead of the source bytes
    var encryptedBytes = yourCrypto.Encrypt(bytes);
    fileStream.Write(encryptedBytes, 0, encryptedBytes.Length);
}

答案 2 :(得分:0)

很有可能,

让我们说你的课看起来像

public class Customer
{
public string Name{get;set;}
public int salary {get;set;}
}

您可以加密对象属性中保存的数据 所以customer.Name ='ABC'可以成为customer.Name ='WQW'之类的东西

而不是序列化。

在反序列化时,在向用户显示数据之前必须显示数据时必须解密数据

希望这个帮助

答案 3 :(得分:0)

我会为序列化创建一个提供属性的类。读取它(给出一个文件名)返回反序列化的对象,写入它(也给出一个文件名)序列化对象。 我添加了第二个带有字符串密码的属性。使用它时,您可以加密序列化的对象字符串和nwrite到磁盘或从中读取1.加密,然后反序列化。

要加密,我建议使用密码而不是直接使用密码。 不幸的是我在vb.net中只有一个代码示例:

Function Encrypt(ByVal data As String, ByVal password As String) As String
  Dim pdb As New Rfc2898DeriveBytes(password, Salt)
  Dim alg As Rijndael = Rijndael.Create()
  alg.Key = pdb.GetBytes(32)
  alg.IV = pdb.GetBytes(16)
  Dim ms As New IO.MemoryStream
  Dim cs As New CryptoStream(ms, alg.CreateEncryptor, CryptoStreamMode.Write)
  cs.Write(System.Text.Encoding.Default.GetBytes(data), 0, data.Length)
  cs.Close()
  ms.Close()
  Return Convert.ToBase64String(ms.ToArray)
End Function

Private Salt As Byte() = {100, 86, 34, 53, 11, 224, 145, 123, _
                                 237, 213, 12, 124, 45, 65, 71, 127, _
                                 135, 165, 234, 164, 127, 234, 231, 211, _
                                 10, 9, 114, 234, 44, 63, 75, 12}


Function Decrypt(ByVal data As String, ByVal password As String) As String
  Dim pdb As New Rfc2898DeriveBytes(password, Salt)
  Dim alg As Rijndael = Rijndael.Create()
  alg.Key = pdb.GetBytes(32)
  alg.IV = pdb.GetBytes(16)

  Dim ms As New IO.MemoryStream
  Dim cs As New CryptoStream(ms, alg.CreateDecryptor, CryptoStreamMode.Write)
  cs.Write(Convert.FromBase64String(data), 0, Convert.FromBase64String(data).Length)
  cs.Close()
  ms.Close()
  Return System.Text.Encoding.Default.GetString(ms.ToArray)
End Function

Function EncryptWithHash(ByVal data As String, ByVal passToHash As String) As String
  Dim _hash As String = getMd5Hash(passToHash)
  Dim _result As String = Encrypt(data, _hash)
  Return _result
End Function

Function DecryptWithHash(ByVal data As String, ByVal passToHash As String) As String
  Dim _hash As String = getMd5Hash(passToHash)
  Dim _result As String = Encrypt(data, _hash)
  Return _result
End Function

Function getMd5Hash(ByVal input As String) As String
  ' Create a new instance of the MD5CryptoServiceProvider object.
  Dim md5Hasher As New MD5CryptoServiceProvider()

  ' Convert the input string to a byte array and compute the hash.
  Dim data As Byte() = md5Hasher.ComputeHash(Encoding.Default.GetBytes(input))

  ' Create a new Stringbuilder to collect the bytes
  ' and create a string.
  Dim sBuilder As New StringBuilder()

  ' Loop through each byte of the hashed data 
  ' and format each one as a hexadecimal string.
  Dim i As Integer
  For i = 0 To data.Length - 1
    sBuilder.Append(data(i).ToString("x2"))
  Next i

  ' Return the hexadecimal string.
  Return sBuilder.ToString()
End Function

我的代码中的属性有Get:

    Dim _dataC As String = ReadFile(filename)

    Dim _dataR As String = Crypt.Decrypt(_dataC, password)

    Dim _result = tmpS.ReadString(_dataR)

和设置:

    Dim _tmpS As New Custom.Serialization(Of Object)
    Dim _tmpRaw As String = _tmpS.WriteString(value)

    Dim _tmpCrypt As String = Crypt.Encrypt(_tmpRaw, password)

WriteFile(tmpPath, _tmpCrypt)

您必须定义自己的序列化,并读取/写入文件:

My.Computer.FileSystem.WriteAllText(filename, data, False)

_result = My.Computer.FileSystem.ReadAllText(FileName)