【问题标题】:C# Encrypt serialized file before writing to diskC#在写入磁盘之前加密序列化文件
【发布时间】:2011-08-17 17:10:10
【问题描述】:

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

1-将文件序列化到磁盘

2-重新打开并加载文件

3-加密文件

4-重写文件到磁盘

这可行,但存在文件在未加密状态下可能被截获的风险,而且这确实效率低下。

相反,我想:

1-在内存中创建文件

2-加密内存中的文件

3-将加密文件写入磁盘

这可能吗?如果是怎么回事?提前致谢。

【问题讨论】:

  • 哦,当然。加密从来都不是完美的。我只想做我能做的,并且把它做好。这不是充分的证据,但我必须尝试不是吗?
  • 这主要是推测性的。在我设计 C# 中实际可能的程序流程之外,我想知道这是否可能。如果不在加密文件中,您将如何安全地存储数据。程序无法持续运行,计算机偶尔会关闭,所以我不能将其保存在内存中?还有什么方法?
  • @Ramhound - 这不是我受雇做的事情或任何事情,所以就像我说的那样,这都是推测性的。为方便起见,客户类包含姓名、信用卡号、到期日期。理想情况下,我将只实现一些通用的东西。
  • @Ram(继续,提前进入)它也不会在服务器上运行。我的思路是,这将与 db 一样安全。如果有人只是要抓取文件,它可能无法通过正常方式读取。
  • @b1nary.atr0phy - 不要粗鲁。

标签: c# serialization encryption


【解决方案1】:

您可以在将类序列化为文件的同时使用 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);
}

【讨论】:

  • 这简直太棒了。我也不知道这些流。非常感谢您的帮助!
  • 您不关闭流有什么原因吗?你可能应该用 try-catch 包裹你的 FileStream(path, FileMode.Open, FileAccess.Read) 行来处理任何 FileNotFoundExceptions。
  • 我已更新代码以将 var cryptoStream 放入 using 语句中。不言而喻,错误处理在生产代码中是必要的。
【解决方案2】:

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

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);
}

【讨论】:

  • 太完美了。我什至不知道 MemoryStreams 的存在。这是我(假设的)问题的确切解决方案。非常非常感谢。
【解决方案3】:

很有可能,

假设你的班级看起来像

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

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

比序列化它。

在反序列化时,当您必须显示数据时,您必须在向用户显示数据之前对其进行解密

希望对你有所帮助

【讨论】:

    【解决方案4】:

    我会创建一个提供属性的序列化类。读取它(给出一个文件名)返回反序列化的对象,写入它(也给出一个文件名)序列化对象。 我添加了带有字符串密码的第二个属性。使用它时,您可以加密序列化的对象字符串和写入磁盘或从它读取时 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)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-10-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-02-07
      • 2020-02-06
      • 2015-11-23
      • 2011-12-14
      相关资源
      最近更新 更多