Шифрование и дешифрование файлов с использованием OpenSSL в .NET - PullRequest
4 голосов
/ 28 февраля 2011

Я использую библиотеку OpenSSL Crypto в своем проекте C # для шифрования / дешифрования файлов.Вот мой код:

byte[] key = System.Text.Encoding.ASCII.GetBytes("password");

byte[] iv = System.Text.Encoding.ASCII.GetBytes("1234");


OpenSSL.Crypto.CipherContext cc = new OpenSSL.Crypto.CipherContext(
    OpenSSL.Crypto.Cipher.AES_256_ECB);

FileStream fIn = new FileStream("C:\\file.txt", FileMode.Open, 
    FileAccess.Read);
FileStream fOut = new FileStream("C:\\encrypted.txt", FileMode.OpenOrCreate,
    FileAccess.Write);
fOut.SetLength(0);

byte[] bin = new byte[100];
long rdlen = 0;
long totlen = fIn.Length;
int len;

DateTime start = DateTime.Now;
while (rdlen < totlen)
{
    // argument 1
    len = fIn.Read(bin, 0, 100);         
    // argument 2
    fOut.Write(cc.Crypt(bin,key,iv,true),0,100);                 
    rdlen = rdlen + len;
}

fOut.Flush();  
fOut.Close();
fIn.Close();

В результате я получил это исключение:

Смещение и длина вышли за пределы массива или число больше, чем количество элементовот индекса до конца исходной коллекции.

Когда я изменил значения аргументов 1 и 2 со 100 на 64 (bin по-прежнему всегда байт [100]), он работал, файл был зашифрован ирасшифрован, но размер дешифрованного файла был больше исходного и содержал еще 1 или 2 строки в конце текстового файла.

Ответы [ 2 ]

3 голосов
/ 28 февраля 2011

Я не знаю библиотеку, но одна проблема здесь в том, что вы шифруете фрагменты размером 100 байтов с размером блока 256 бит = 32 байта.Ваши куски должны быть кратны 32 байта.Дополнительные байты в конце файла, скорее всего, просто округляют последний блок до 32 байтов.

Как и в ответе Филиппа, вероятной причиной сбоя является жестко закодированное значение 100 в записи.Функция Crypt будет извлекать один из 32, 64 или 96 байт из последнего блока, который она шифрует, и все они не имеют 100. (В случае 100-байтового варианта, который работает, есть вероятность, что ваши данные будут заполнены до 128 байт в зашифрованном виде итаким образом, вы теряете последние 28 байтов последнего блока, когда пишете только 100.)

Также

  1. вы передаете IV в режиме ECB - вы неЭто нужно
  2. , неоднократно вызывая Crypt, вы, вероятно, выполняете настройку ключа для каждых 100 байтов.Это неэффективно;вам нужно сделать это только один раз в начале шифрования.Вы должны искать способ инициализировать класс ключом (и IV в других режимах), а затем передавать ему блоки данных для шифрования сразу, вместо того, чтобы каждый раз вызывать Crypt с ключом.Я не знаю, что это будет в этой библиотеке, но она должна существовать.В его нынешнем виде вы также не можете использовать CBC или любой другой подобный режим, потому что вы будете записывать IV каждые 100 байтов, а не один раз, и не будете цеплять последний блок между смежными кусками по 100 байтов.
  3. , если хотитеиспользуйте Crypt, почему бы просто не загрузить файл в память сразу?Я понимаю, что это не будет масштабироваться до гигабайта данных, но это, вероятно, возможно в вашем обычном случае использования.Или, по крайней мере, выбрать гораздо больший размер данных, например, 256 КБ.Однако вы все равно столкнетесь с повторной установкой ключа / неработающим CBC, если вы пойдете выше одного блока.
1 голос
/ 28 февраля 2011

Когда вы указываете 100 для вашего звонка на fIn.Read(...), вы говорите «Чтение до 100 байт» - обратите внимание, что фактическое количество байт может быть другим;Вы должны использовать возвращаемое значение, чтобы определить, сколько фактически было прочитано.

И при вызове fOut.Write вы предполагаете, что вывод cc.Crypt(bin,key,iv,true) будет ровно 100 байтов, что недопустимопредположение.Также обратите внимание, что вы всегда шифруете все 100 байтов bin, даже если вы читаете только 1 из вашего файла.Если вы прочитали меньше 100, вы бы зашифровали все, что было «оставлено» в корзине (вероятно, 0 с, если не использовались ранее).

Исправьте эти проблемы длины, и вы должны быть на правильном пути.Что-то вроде:

while (rdlen < totlen)
{
    len = fIn.Read(bin, 0, 100);         
    // note that we are encrypting all of "bin" here, may want to only 
    // encrypt "len" bytes..
    byte[] encrypted = cc.Crypt(bin, key, iv, true);
    fOut.Write(encrypted, 0, encrypted.Length);                 
    rdlen = rdlen + len;
}
...