Правильное использование/хранение C# Rijndael IV

После полудня,

Так что я довольно новичок во всех этих методах и способах шифрования. Я только что начал создавать реализацию шифрования. Теперь мой метод шифрования и дешифрования, кажется, работает нормально. Пока я не прочитал, я ужасно потерпел неудачу из-за использования Hardcoded IV в классе RijndaelManaged.

Я везде читаю, что лучше (и безопаснее), чтобы IV каждого зашифрованного файла был уникально сгенерирован в «время шифрования» и сохранен в начале/начале файла, где остальные зашифрованные байты сохраняются непосредственно после этого. (если я правильно это понимаю)

Мне было очень трудно понять мою проблему, потому что каждый раз, когда я шифрую файл, я пишу IV в первые 16 байтов (как предложил класс, MSDN, Google и некоторые люди на этом форуме) файла и сразу после этого я записываю остальные зашифрованные байты в файловый поток. (IV сохраняется в виде открытого текста.. Или хорошо незашифрованные байты ‹ Также это нормально?)

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

Кажется, это не удается. Я проверил, я думаю, что, возможно, где-то делаю какую-то школьную ошибку: потому что я не могу прочитать те же 16 байтов из зашифрованного файла, когда хочу его расшифровать.

Это код, который я использую для обработки файлов ДО шифрования (а не самого шифрования)


using (RijndaelManaged RM = new RijndaelManaged())
using (FileStream StreamIN = new FileStream(FileIN, FileMode.Open, FileAccess.Read))
using (FileStream StreamOUT = new FileStream(FileOUT, FileMode.Append, FileAccess.Write))
{
    //Setup Variable ChunkSize and The Total bytes Read into the streams
    int ChunkSize = 1024 * 1024 * 32; 

    RM.GenerateIV();

    foreach (var item in RM.IV)
    {
        Console.Write("[ " + item + "] ");
    }

    StreamOUT.Seek(0, SeekOrigin.Begin);
    StreamOUT.Write(RM.IV, 0, RM.IV.Length);
    StreamOUT.Seek(RM.IV.Length, SeekOrigin.Begin);

    int TotalBytesRead = 0;                       

    //File Buffer Implementation
    for (long i = 0; i < StreamIN.Length; i += ChunkSize)
    {
        //ChunkData byte array determined by ChunkSize
        byte[] ChunkData = new byte[ChunkSize];
        //Current Bytes Read from the IN Stream
        int BytesRead = 0;
        while ((BytesRead = StreamIN.Read(ChunkData, 0, ChunkSize)) > 0)
        {
            //Call Encryption from local Class

            Console.WriteLine("Bytes Read: {0}", TotalBytesRead += BytesRead);

            ChunkData = Crypt.Encrypt(ChunkData, KeyBytes, RM.IV);

            //Write byte array to File
            StreamOUT.Write(ChunkData, 0, BytesRead);
        }
    }
}

И это мой код для обработки файлов ДО расшифровки (не самой расшифровки)

using (RijndaelManaged RM = new RijndaelManaged())
using (FileStream StreamIN = new FileStream(FileIN, FileMode.Open, FileAccess.Read))
using (FileStream StreamOUT = new FileStream(FileOUT, FileMode.Append, FileAccess.Write))
{
    //Setup Variable ChunkSize and The Total bytes Read into the streams
    int ChunkSize = 1024 * 1024 * 32; 


    StreamIN.Seek(0, SeekOrigin.Begin);
    int Read = StreamIN.Read(RM.IV, 0, 16);
    StreamIN.Seek(RM.IV.Length, SeekOrigin.Begin);

    int TotalBytesRead = 0;

    foreach (var item in RM.IV)
    {
        Console.Write("[ " + item + "] ");
    }

    //File Buffer Implementation
    for (long i = 0; i < StreamIN.Length; i += ChunkSize)
    {
        //ChunkData byte array determined by ChunkSize
        byte[] ChunkData = new byte[ChunkSize];
        //Current Bytes Read from the IN Stream
        int BytesRead = 0;

        while ((BytesRead = StreamIN.Read(ChunkData, 0, ChunkSize)) > 0)
        {

            Console.WriteLine("Bytes Read: {0}", TotalBytesRead += BytesRead);                                

            //Call Decryption from local Class
            ChunkData = Crypt.Decrypt(ChunkData, KeyBytes, RM.IV);

            //Write byte Array to file
            StreamOUT.Write(ChunkData, 0, BytesRead);
        }
    }
}

Я думаю, это все? Кроме того, «Консоль» и другие бесполезные вызовы сделаны только для того, чтобы помочь мне проверить и выяснить проблему на данный момент. Я использую Visual Studios 2010 и пытаюсь реализовать класс RijndaelManaged.

Методы шифрования/дешифрования передаются FileChunks (массив байтов) с моим ключом и IV, и они возвращают массив байтов (зашифрованный), который сохраняется в потоке.

Надеюсь, мой вопрос понятен? Если нет, я попытаюсь объяснить лучше, я читал везде в поисках помощи по этой конкретной проблеме, но большинство других вопросов, размещенных здесь, выходят за рамки моей компетенции.

Я действительно был бы признателен за любую помощь, я уверен, что где-то делаю клоунскую ошибку.

Спасибо!!


person Medismal    schedule 21.10.2012    source источник
comment
Вау, кто-то, кто хочет правильно использовать IV. Какое редкое зрелище.   -  person CodesInChaos    schedule 21.10.2012
comment
Я подозреваю, что проблемная строка int Read = StreamIN.Read(RM.IV, 0, 16);. RM.IV возвращает вам массив байтов, который вы заполняете, но для установки IV этому свойству должно быть назначено значение. Поэтому было бы лучше прочитать явно выделенный массив, а затем установить RM.IV равным массиву.   -  person anton.burger    schedule 21.10.2012
comment
Итак, вы видите разные IV в шифровании и дешифровании? Уточните подробнее: полностью или частично отличается, сколько байт в расшифровщике? Каково значение int Read ?   -  person Henk Holterman    schedule 21.10.2012
comment
@shambulator: Согласно вашему предложению, я явно назначил RM.IV байтам чтения. Это устранило проблему, с которой я столкнулся! Я благодарю вас за ваше время!. Пожалуйста, наслаждайтесь приятным вечером/днем/что угодно :D   -  person Medismal    schedule 21.10.2012
comment
@HenkHolterman: До исправления IV были совершенно другими. Согласно отображению IV перед шифрованием и перед дешифрованием с помощью консольных вызовов foreach, у них даже не было совпадения одного байта. Но проблема устранена. Еще раз спасибо!   -  person Medismal    schedule 21.10.2012
comment
@Medismal Рад, что это решило проблему! Написал ответ и добавил некоторые подробности.   -  person anton.burger    schedule 22.10.2012


Ответы (1)


Согласно давним рекомендациям по фреймворку , похоже, что SymmetricAlgorithm.IV было написано, чтобы не возвращать внутренний массив. Это означает, что он возвращает вам копию, поэтому последующие изменения не отражаются в экземпляре RijndaelManaged.

// Effectively reading the persisted value into a temporary array
// and throwing away the temporary.
int Read = StreamIN.Read(RM.IV, 0, 16);

Чтобы зафиксировать изменение и установить для IV постоянное значение, вам нужно фактически явно установить свойство IV, а не просто изменить значение, которое оно вернуло ранее.

byte[] persistedIv = new byte[16];
StreamIN.Read(persistedIv, 0, persistedIv.Length);
RM.IV = persistedIv;
person anton.burger    schedule 21.10.2012
comment
Теперь я вижу свою ошибку, еще раз спасибо. Я должен был иметь право не реализовывать это как таковое - но я полностью упустил это из виду и начал обвинять другие возможные источники .. +1! - person Medismal; 22.10.2012