2011-02-23 1 views
1

Я совершенно новичок в C# и шифровании, поэтому, пожалуйста, проявляйте терпение со мной. Я хочу сохранить некоторые двоичные данные («объекты» - фактически в основном только части объектов, поэтому я не могу/не использовать сериализацию, BinaryWriter и т. Д.), И я хочу зашифровать его в памяти, а затем записать его с помощью FileStream , Сначала я хотел использовать какой-то Xor, но я не знал, что так легко сломаться, теперь я изменил код, чтобы использовать Aes.Как encrpyt/расшифровать данные в кусках?

Дело в том, что у меня будут некоторые относительно большие файлы, и довольно часто мне нужно будет только изменить или прочитать как 32 байта данных. Таким образом, я должен быть способен шифровать только один фрагмент данных, а также способен расшифровать только нужные фрагменты данных. Пока я пришел только со следующим решением.

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

Вот код для шифрования & экономией:

 //setup file stream for saving data 
     FileStream fStream = new FileStream(fileName, FileMode.OpenOrCreate, FileAccess.Write, FileShare.Read, 1024, false); 

     //setup encryption (AES) 
     SymmetricAlgorithm aes = Aes.Create(); 
     byte[] key = { 145, 12, 32, 245, 98, 132, 98, 214, 6, 77, 131, 44, 221, 3, 9, 50 }; 
     byte[] iv = { 15, 122, 132, 5, 93, 198, 44, 31, 9, 39, 241, 49, 250, 188, 80, 7 }; 
     aes.Padding = PaddingMode.None; 
     ICryptoTransform encryptor = aes.CreateEncryptor(key, iv); 

     foreach(....) 
     { 
      //data manipulation 

      //encryption 
      MemoryStream m = new MemoryStream(); 
      using (Stream c = new CryptoStream(m, encryptor, CryptoStreamMode.Write)) 
       c.Write(data, 0, data.Length); 
      byte[] original = new byte[32]; 
      original = m.ToArray(); 
      fStream.Write(original, 0, original.Length); 
     } 

Ключ и IV жестко закодирована только для того, чтобы легче отладки и решения проблем, как только это будет работать, я изменю ключ пути и IV генерируется.

Вот код для чтения & дешифрования: FileStream fStream = новый FileStream (имя_файла, FileMode.Open, FileAccess.Read, FileShare.Read, 4096, ложь);

  //setup encryption (AES) 
      SymmetricAlgorithm aes = Aes.Create(); 
      byte[] key = { 145, 12, 32, 245, 98, 132, 98, 214, 6, 77, 131, 44, 221, 3, 9, 50 }; 
      byte[] iv = { 15, 122, 132, 5, 93, 198, 44, 31, 9, 39, 241, 49, 250, 188, 80, 7 }; 
      aes.Padding = PaddingMode.None; 

      //reading 
      while (numBytesToRead > 0) 
      { 
       byte[] original = new byte[32]; 
       byte[] data = new byte[32]; 
       int len = fStream.Read(original, 0, 32); 

       //error checking ... 

       //decryption 
       ICryptoTransform decryptor = aes.CreateDecryptor(key, iv); //this is a slow operation 
       MemoryStream m = new MemoryStream(); 
       using (Stream c = new CryptoStream(m, decryptor, CryptoStreamMode.Write)) 
        c.Write(original, 0, original.Length); 
       data = m.ToArray(); 

       //data manipulation ... 
      } 

Хорошо, что я считаю очень неэффективным создание дешифратора в цикле. Будет довольно много данных. Если я создаю его перед входом в цикл, то я не могу правильно расшифровать и изменить шифрование (объявить поток шифрования и поток памяти до цикла), но тогда я не могу шифровать/дешифровать только желаемый фрагмент данных. Также не так много файлов, которые требовали бы случайного чтения/записи. Например, в некоторых файлах я хочу читать с определенной позиции до конца файла, что может быть довольно много.

Ваше мнение по этому вопросу? Есть ли лучший способ достичь этого? Может быть, другой алгоритм шифрования (в начале я хотел использовать какой-то xor, но я узнал, что очень легко «взломать»)?

p.s. Я хочу зашифровать в памяти, и я должен использовать поисковые потоки.

+0

Я предполагаю, что вы хотите другой режим шифрования, такие как XTS. – CodesInChaos

ответ

1

Если вы хотите получить полный произвольный доступ, ECB - это путь (как рекомендует earlier answer). Вам не нужно будет воссоздавать поток шифрования для каждого блока, потому что он не использует IV и шифрование блока не переставляет поток (в отличие от большинства других режимов, где криптотекст зависит от предыдущих блоков или положения блока в поток). Википедия имеет nice illustration (изображение ciphertux) одной из проблем с этим режимом.

Если ваш файл логически состоит из более крупных блоков (например, записей базы данных или секторов диска на виртуальных дисках), вы должны рассмотреть возможность их шифрования как единиц. В режиме CBC вы должны генерировать новый случайный IV для каждого фрагмента каждый раз, когда вы его записываете, и храните его в блоке (таким образом, используя дополнительные 32 байта памяти на кусок), и вам нужно будет переписать весь фрагмент, даже если однобайтовые изменения, но безопасность будет намного лучше.

1

Вы можете использовать режим шифрования ECB (CipherMode.ECB). Другие режимы шифрования возвращают шифр и/или обычный текст в следующий блок текста для шифрования/дешифрования. Это обеспечивает большую безопасность, поскольку повторные части зашифрованы по-другому. Однако для этого требуется, чтобы весь поток был расшифрован.

В режиме электронной кодовой книги (ECB) каждый блок зашифровывается индивидуально, поэтому вы можете реализовать произвольный доступ на границах блоков шифрования. Тем не менее, ЕЦБ вводит уязвимости, особенно когда обычный текст повторяется. See here

0

Мне просто дали совет об использовании GCM вместо ECB. ECB, как вы, вероятно, знаете, не очень безопасный способ сделать это, и я в настоящее время реализую прототип с использованием Bouncy Castle API (проверьте эту тему: https://stackoverflow.com/a/10366194/637783).

0

Если вы хотите расшифровать поблочно вы должны держать последние 8 байт и использовать его в качестве IV для следующего блока

while ((count = fileRead.Read(read, 0, 16)) > 0) 
       { 
        if (transed > 0) 
         aes.IV = read; 
        transed += count; 
        ... 
       }