2016-11-08 2 views
0

Edit: gelöst - Problem war die Entschlüsselungsfunktion. Korrigierte Entschlüsselungsfunktion kann in der Antwort unten gefunden werden.C# RijndaelManaged Verschlüsselung und Entschlüsselung schlägt manchmal fehl

Ich habe den letzten Tag bei der Arbeit verbracht, um herauszufinden, wo ich mit dieser Implementierung von AES falsch gelaufen bin. Wir müssen in der Lage sein, große Dateien zu verschlüsseln/entschlüsseln, so dass ich Dateiströme verwendet habe und jedes Stück auf die Festplatte schreiben konnte. AES ist eine Anforderung, wie dies in Java geschrieben mit einem bestehenden System arbeiten muss, die AES/CBC/PKCS5Padding verwendet (die soweit ich weiß zu PKCS7/CBC entsprechen)

Diese Implementierung arbeitet für meist Dateien . Es gibt jedoch einige Dateien, in denen die letzten 5 Byte der Rohdaten fehlen. Die Datei wird ohne Fehler entschlüsselt, der Hash stimmt jedoch nicht überein und die fehlenden Bytes sind eine Kombination aus echten Daten und abschließenden Nullen.

Es ist zu beachten, dass diese Streams vor und nach der Verschlüsselung gezippt werden (Code unten).

Encryption

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

Decryption

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

Kompression (Vor der Verschlüsselung)

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

Dekomprimierung (Nach der Entschlüsselung)

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); 
     } 
} 

Ich habe durch einige andere Fragen gegangen, aber kann nicht herausfinden, warum dies nur bei einigen Dateien auftritt. Die Dateigröße, die fehlschlägt, ist 46.854.144 Bytes. Dies scheint jedoch bei größeren und kleineren Dateien zu funktionieren.

Jede Hilfe würde sehr geschätzt werden.

+1

'Stream.Read()' gibt ein 'int' zurück, das die Anzahl der gelesenen Bytes angibt. Auch wenn es Ihr Problem möglicherweise nicht löst, würde ich Ihnen dringend empfehlen, diesen Rückgabewert zu verwenden, um zu ermitteln, wie viele Bytes * tatsächlich * gelesen wurden und daher in Ihre Ausgabe geschrieben werden sollten, anstatt davon auszugehen, dass der Puffer immer vollständig gefüllt wurde. Beispiel: 'var bytesRead = inStream.Read (buffer, 0, buffer.Length); outStream.Write (Puffer, 0, BytesRead); '. – Iridium

+0

Oder einfach 'Stream.CopyTo' verwenden – CodesInChaos

+0

Danke für die Antwort! Ich habe die Variable 'BytesRead' hinzugefügt und benutze sie in allen außer der Dekomprimierungsmethode, die dies bereits getan hat. Leider hat es das Problem nicht gelöst - ich bin immer noch dabei :( – newuser

Antwort

0

Das Problem war mit der Art, wie ich die Daten entschlüsselt habe. Ich habe den CryptoStream falsch verwendet. Die aktualisierte Decrypt-Funktion ist unten, wenn jemand interessiert ist.

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(); 
    } 
Verwandte Themen