2016-11-08 202 views
0

編輯:解決 - 問題是解密函數。更正的解密函數可以在下面的答案中找到。c#RijndaelManaged加密和解密有時會失敗

我花了最後一天的時間試圖找出我在這個AES實現中出錯的地方。我們需要能夠加密/解密大文件,因此我使用了文件流並將每個塊寫入磁盤。 AES是一個要求,因爲這需要與使用AES/CBC/PKCS5Padding(其中據我所知,相當於PKCS7/CBC)用Java編寫的現有系統工作

此實現適用於文件。然而,有幾個文件丟失了原始數據的最後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(); 
    } 

壓縮(在此之前加密)

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(buffer,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(); 
    }