4 Stimmen

Verschlüsseln und Entschlüsseln von Dateien mit OpenSSL in .NET

Ich verwende die OpenSSL Crypto-Bibliothek in meinem C#-Projekt, um Dateien zu verschlüsseln/entschlüsseln. Hier ist mein Code :

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

Als Ergebnis habe ich diese Ausnahme erhalten:

Verschiebung und Länge lagen außerhalb des Arrays oder die Anzahl ist größer als die Anzahl der Elemente ab dem Index bis zum Ende der Quellensammlung.

Als ich die Werte von Argument 1 und 2 von 100 auf 64 (bin immer noch byte[100]) geändert habe, hat es funktioniert, die Datei wurde verschlüsselt und entschlüsselt, aber die Größe der entschlüsselten Datei war größer als die Originaldatei und enthielt am Ende der Textdatei 1 oder 2 zusätzliche Zeilen.

3voto

Rup Punkte 32603

Ich kenne die Bibliothek nicht, aber ein Problem hier ist, dass du Chunks von 100 Bytes mit einer 256-Bit-Blockgröße von 32 Bytes verschlüsselst. Deine Chunks sollten Vielfache von 32 Bytes sein. Die zusätzlichen Bytes am Ende der Datei runden wahrscheinlich einfach den letzten Block auf 32 Bytes auf.

Wie in Philips Antwort erwähnt, ist die wahrscheinliche Ursache für den Absturz die fest codierte 100 im Write. Die Crypt-Funktion gibt wahrscheinlich 32, 64 oder 96 Bytes aus dem letzten Block zurück, den sie verschlüsselt, was alles weniger als 100 ist. (Im Fall von 100 Bytes funktioniert, ist es wahrscheinlich, dass deine Daten auf 128 Byte aufgefüllt und verschlüsselt werden, so dass du die letzten 28 Bytes des letzten Blocks verlierst, wenn du nur 100 schreibst.)

Außerdem

  1. Du übergibst ein IV im ECB-Modus - das brauchst du nicht
  2. Indem du Crypt wiederholt aufrufst, führst du vermutlich für jedes 100 Byte die Schlüsselkonfiguration durch. Das ist ineffizient; du musst dies nur einmal zu Beginn der Verschlüsselung tun. Du solltest nach einer Möglichkeit suchen, die Klasse mit dem Schlüssel zu initialisieren (und IV in anderen Modi), dann Blöcke von Daten auf einmal zu verschlüsseln, anstatt jedes Mal Crypt mit dem Schlüssel aufzurufen. Ich weiß nicht, was das in dieser Bibliothek sein könnte, aber es sollte existieren. Wie es jetzt ist, kannst du auch CBC oder ähnliche Modi nicht verwenden, da du das IV alle 100 Bytes schreibst anstatt einmal und den letzten Block nicht zwischen benachbarten 100-Byte-Blöcken verkettet.
  3. Wenn du Crypt verwenden möchtest, warum nicht einfach die Datei auf einmal in den Speicher laden? Mir ist klar, dass das nicht auf Gigabyte von Daten skaliert, aber es ist wahrscheinlich in deinem normalen Anwendungsfall möglich. Oder wähle zumindest eine viel größere Datenmenge, z.B. 256k. Allerdings wirst du immer noch mit der wiederholten Schlüsselkonfiguration / dem unterbrochenen CBC konfrontiert sein, wenn du über einen Block hinausgehst.

1voto

Philip Rieck Punkte 31977

Wenn Sie 100 in Ihren Aufruf von fIn.Read(...) angeben, sagen Sie "Lese bis zu 100 Bytes" - beachten Sie, dass die tatsächliche Anzahl von Bytes unterschiedlich sein kann; Sie sollten den Rückgabewert verwenden, um zu ermitteln, wie viele tatsächlich gelesen wurden.

Und beim Aufruf von fOut.Write gehen Sie davon aus, dass die Ausgabe von cc.Crypt(bin, key, iv, true) genau 100 Bytes beträgt, was keine gültige Annahme ist. Beachten Sie auch, dass Sie immer alle 100 Bytes von bin verschlüsseln, auch wenn Sie nur 1 aus Ihrer Datei gelesen haben. Wenn Sie weniger als 100 gelesen haben, verschlüsseln Sie alles, was in bin "übrig geblieben" ist (wahrscheinlich 0en, es sei denn, sie wurden zuvor verwendet).

Korrigieren Sie diese Längenprobleme, und Sie sollten auf dem richtigen Weg sein. Etwas wie:

while (rdlen < totlen)
{
    len = fIn.Read(bin, 0, 100);         
    // beachten Sie, dass wir hier alle von "bin" verschlüsseln, möglicherweise möchten Sie nur
    // "len" Bytes verschlüsseln...
    byte[] encrypted = cc.Crypt(bin, key, iv, true);
    fOut.Write(encrypted, 0, encrypted.Length);                 
    rdlen = rdlen + len;
}

0 Stimmen

D'oh, kann nicht glauben, dass ich das verpasst habe. +1, wenn ich morgen meine Stimmen zurückbekomme. Ich würde noch weiter gehen und rdlen verlieren: die Schleife beenden, wenn len <= 0 nach dem Lesen. Dennoch lasse ich meine Antwort für die Schlüsselkonfiguration und Blockgrößenpunkte stehen, von denen ich glaube, dass sie immer noch gültig sind.

0 Stimmen

Tatsächlich - gute Punkte zum Schlüsselaufbau und zur Blockgröße; +1. Ich würde die Schleife auch im "echten" Code ändern, aber ich habe versucht, den Unterschied zum Beispielcode aus der Frage zu minimieren.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X