2016-11-08 5 views
0

Редактировать: resolved - проблема была функцией дешифрования. Исправленную функцию дешифрования можно найти в ответе ниже.C# Rijndael Управляемое шифрование и дешифрование иногда не удается

Я провел последний день на работе, пытаясь выяснить, где я ошибся с этой реализацией AES. Мы должны иметь возможность шифровать/расшифровывать большие файлы, чтобы я использовал потоки файлов и записывал на диск каждый фрагмент. AES является требованием, как это должно работать с существующей системой, написанной в Java, которая использует AES/CBC/PKCS5Padding (который, насколько я знаю, что эквивалентно pkcs7/CBC)

Эта реализация работает наиболее файлов , Однако есть несколько файлов, в которых отсутствуют последние 5 байтов необработанных данных. Файл будет дешифровать без ошибок, однако хэш не соответствует, а недостающие байты представляют собой комбинацию реальных данных и завершающих нулей.

Следует отметить, что эти потоки gzip до и после шифрования (код внизу).

Шифрование

public static void AesEncrypt(byte[] keyBytes, byte[] ivBytes, Stream dataStream, FileStream outStream) 
    { 
     RijndaelManaged symmetricKey = new RijndaelManaged(); 
     symmetricKey.Mode = CipherMode.CBC; 
     symmetricKey.Padding = PaddingMode.PKCS7; 
     symmetricKey.BlockSize = 128; 
     symmetricKey.KeySize = 256; 

     const int chunkSize = 4096;//1024 * 1024 * 10; 

     using (ICryptoTransform encryptor = symmetricKey.CreateEncryptor(keyBytes, ivBytes)) 
     { 
      using (CryptoStream cryptoStream = new CryptoStream(outStream, encryptor, CryptoStreamMode.Write)) 
      { 
       while (dataStream.Position != dataStream.Length) 
       { 
        long remainingBytes = dataStream.Length - dataStream.Position; 
        var buffer = chunkSize > remainingBytes ? new byte[(int)remainingBytes] : new byte[chunkSize]; 

        dataStream.Read(buffer, 0, buffer.Length); 
        cryptoStream.Write(buffer, 0, buffer.Length); 
        cryptoStream.Flush(); 
       } 
       cryptoStream.FlushFinalBlock(); 
      } 
     } 
     symmetricKey.Clear(); 
    } 

дешифрование

public static void AesDecrypt(byte[] keyBytes, byte[] ivBytes, Stream dataStream, FileStream outStream) 
    { 
     RijndaelManaged symmetricKey = new RijndaelManaged(); 
     symmetricKey.Mode = CipherMode.CBC; 
     symmetricKey.Padding = PaddingMode.PKCS7; 
     symmetricKey.BlockSize = 128; 
     symmetricKey.KeySize = keyBytes.Length == 32 ? 256 : 128; 

     const int chunkSize = 4096; 

     using (ICryptoTransform decryptor = symmetricKey.CreateDecryptor(keyBytes, ivBytes)) 
     { 
      using (CryptoStream cryptoStream = new CryptoStream(dataStream, decryptor, CryptoStreamMode.Read)) 
      { 
       while (dataStream.Position != dataStream.Length) 
       { 
        long remainingBytes = dataStream.Length - dataStream.Position; 
        var buffer = chunkSize > remainingBytes 
         ? new byte[(int) remainingBytes] 
         : new byte[chunkSize]; 

        cryptoStream.Read(buffer, 0, buffer.Length); 
        outStream.Write(buffer, 0, buffer.Length); 
        outStream.Flush(); 
       } 
       //cryptoStream.FlushFinalBlock(); // Was throwing an exception 
      } 
     } 
     symmetricKey.Clear(); 
    } 

Compression (До шифрования)

public static void StreamCompress(Stream dataStream, FileStream outStream) 
    { 
     dataStream.Position = 0; 
     outStream.Position = 0; 

     const int chunkSize = 4096; 
     using (GZipStream gzs = new GZipStream(outStream, CompressionMode.Compress)) 
     { 
      while (dataStream.Position != dataStream.Length) 
      { 
       long remainingBytes = dataStream.Length - dataStream.Position; 
       var buffer = chunkSize > remainingBytes ? new byte[(int)remainingBytes] : new byte[chunkSize]; 
       dataStream.Read(buffer, 0, buffer.Length); 
       gzs.Write(buffer, 0, buffer.Length); 
       gzs.Flush(); 
      } 
     } 
    } 

декомпрессия (После расшифровки)

public static void StreamDecompress(Stream dataStream, FileStream outStream) 
    { 
     byte[] buffer = new byte[4096]; 
     dataStream.Position = 0; 
     using (GZipStream gzs = new GZipStream(dataStream, CompressionMode.Decompress)) 
     { 
      for (int r = -1; r != 0; r = gzs.Read(buffer, 0, buffer.Length)) 
       if (r > 0) outStream.Write(buffer, 0, r); 
     } 
} 

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

Любая помощь была бы принята с благодарностью.

+1

'Stream.Read()' возвращает 'int ', указывающий количество прочитанных байтов. Хотя это может не решить вашу проблему, я настоятельно рекомендую использовать это возвращаемое значение, чтобы определить, сколько байтов было * на самом деле * прочитано и поэтому должно быть записано на ваш вывод, а не предполагать, что буфер всегда был полностью заполнен. Например: «var bytesRead = inStream.Read (buffer, 0, buffer.Length); outStream.Write (буфер, 0, bytesRead); '. – Iridium

+0

Или просто используйте 'Stream.CopyTo' – CodesInChaos

+0

Спасибо за ответ! Я добавил переменную 'bytesRead' и использую ее во всех, кроме метода декомпрессии, который уже делал это. К сожалению, это не решило проблему - я все еще смотрю на это :( – newuser

ответ

0

Проблема была в том, как я расшифровывал данные. Я неправильно использовал CryptoStream. Обновленная функция расшифровки ниже, если кто-то заинтересован.

public static void AesDecrypt(byte[] keyBytes, byte[] ivBytes, Stream dataStream, FileStream outStream) 
    { 
     dataStream.Position = 0; 
     outStream.Position = 0; 

     RijndaelManaged symmetricKey = new RijndaelManaged(); 
     symmetricKey.Mode = CipherMode.CBC; 
     symmetricKey.Padding = PaddingMode.PKCS7; 
     symmetricKey.BlockSize = 128; 
     symmetricKey.KeySize = keyBytes.Length == 32 ? 256 : 128; 

     const int chunkSize = 4096; 

     using (ICryptoTransform decryptor = symmetricKey.CreateDecryptor(keyBytes, ivBytes)) 
     { 
      using (CryptoStream cryptoStream = new CryptoStream(outStream, decryptor, CryptoStreamMode.Write)) 
      { 

       while (dataStream.Position != dataStream.Length) 
       { 
        long remainingBytes = dataStream.Length - dataStream.Position; 
        var buffer = chunkSize > remainingBytes 
         ? new byte[(int) remainingBytes] 
         : new byte[chunkSize]; 

        var bytesRead = dataStream.Read(buffer, 0, buffer.Length); 
        cryptoStream.Write(buffer, 0, bytesRead); 
       } 
       cryptoStream.FlushFinalBlock(); 
      } 
     } 
     symmetricKey.Clear(); 
    }