Как зашифровать / расшифровать данные в чанках? - PullRequest
1 голос
/ 23 февраля 2011

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

Дело в том, что у меня будут относительно большие файлы идовольно часто мне нужно всего лишь изменить или прочитать как 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 = newFileStream (fileName, FileMode.Open, FileAccess.Read, FileShare.Read, 4096, 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;

            //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, но я обнаружил, что его очень легко «взломать»)?

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

Ответы [ 4 ]

1 голос
/ 23 февраля 2011

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

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

1 голос
/ 23 февраля 2011

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

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

0 голосов
/ 29 июня 2017

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

while ((count = fileRead.Read(read, 0, 16)) > 0)
                {
                    if (transed > 0)
                        aes.IV = read;
                    transed += count;
                    ...
                }
0 голосов
/ 07 сентября 2012

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

...