C # Шифровать сериализованный файл перед записью на диск - PullRequest
15 голосов
/ 03 мая 2011

Допустим, у моей программы есть класс под названием «customer», а класс customer является сериализуемым, поэтому я могу читать и записывать его на диск. Класс customer содержит конфиденциальную информацию, которую я хочу зашифровать. Единственный способ, которым я знаю, как сохранить файл в безопасности, - это:

1-Сериализация файла на диск

2 - снова открыть и загрузить файл

3-Шифровать файл

4-перезаписать файл на диск

Это бы сработало, но есть риск, что файл может быть перехвачен в его незашифрованном состоянии, и, кроме того, это действительно неэффективно.

Вместо этого я хотел бы:

1-Создать файл в памяти

2-Шифровать файл в памяти

3 - запись зашифрованного файла на диск

Возможно ли это? Если это как? Заранее спасибо.

Ответы [ 4 ]

33 голосов
/ 03 мая 2011

Вы можете использовать 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);
}
25 голосов
/ 03 мая 2011

Помимо проблем, выраженных в комментариях, если все, что вы спрашиваете, - это как работать с байтами в памяти и записывать их в файл только один раз, просто сначала сериализуйте ваш объект в поток памяти. Зашифруйте эти байты и запишите их в файл.

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);
}
0 голосов
/ 04 мая 2011

Я бы создал класс для сериализации, который предлагает свойство. чтение его (с указанием имени файла) возвращает десериализованные объекты, запись в него (также с указанием имени файла) сериализует объект. Я добавил второе свойство с паролем String. При его использовании вы можете зашифровать строку сериализованного объекта и 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)
0 голосов
/ 03 мая 2011

Вполне возможно,

Допустим, ваш класс выглядит как

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

Вы можете зашифровать данные, хранящиеся в свойствах объекта так customer.Name = 'ABC' может стать customer.Name = 'WQW' что-то в этом роде

, чем сериализовать его.

При десериализации, когда вам нужно показать данные, вы должны расшифровать их, прежде чем показывать данные пользователю

надеюсь, что это поможет

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...