Mir sind grad noch zwei (oder eigentlich drei) Probleme aufgefallen

War gestern/heute wohl wieder mal zu müde...
Aber zuerst zu den Fragen:
Warum ECB schlecht ist:
EIn wichtiger Grund: Alle 16-Byte-Blöcke von den Gesamtdaten werden unabhängig voneinander verschlüsselt, damit ergeben mehrere gleiche Klartextblöcke auf gleiche verschlüsselte Blöcke bzw. man kann also Wiederholungen erkennen. Klingt zuerst harmlos, aber als Beispiel folgendes Bild:
http://upload.wikimedia.org/wikipedia/commons/5/56/Tux.jpg im ECB-Modus verschlüsselt und wieder als Bild anzuzeigen versucht ergibt
http://upload.wikimedia.org/wikipedia/commons/f/f0/Tux_ecb.jpg . Man erkennt noch immer, was es ist...
Bei Text kann man zB. mithilfe von Häufigkeitsmessungen raten, was drin ist (weil der Buchstabe E in Deutsch xy mal häufiger ist als Y, und deswegen viele gleiche Blöcke wohl eher E als Y sind.
Ist natürlich vereinfacht beschrieben, aber vom Prinzip her kann man solche und ähnliche Methoden einsetzen
Um den IV zu entfernen, falls man ECB verwendet: Die Zeilen, die $iv_size und $iv erstellen, komplett weg,
und bei mcrypt_encrypt / mcrypt_decrypt den letzten Parameter ($iv) ersatzlos weglöschen.
Die Sache mit dem Alles-entschlüsseln: Wenn dein Anwendungsfall sowieso immer alles zusammen entschlüsselt
gibts kein Problem. Nur "wenn" man manchmal auch nur Teile der Datei haben will kann CBC zum Nachteil werden
(aber es gibt mehr außer ECB/CBC. Kein Grund, ECB zu verwenden).
Problem 1a: Der IV wird zurzeit ja in jedem Schleifendurchgang neu erstellt.
Das sollte nur einmal für die ganze Datei sein, wobei der IV für die nächsten Schleifendurchgänge bei AES/CBC die letzten 16 Byte gerade verschlüsselten Block sind. Also ca. so für Verschlüsseln:
PHP:
<?php
$filenamein = "d.exe";
$filenameout = "d2.exe";
$filein = fopen($filenamein, 'rb');
$fileout = fopen($filenameout, 'wb');
$size = filesize($filenamein);
$pos = 0;
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC); //von der schleife rausgeholt
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND); //von der schleife rausgeholt
while ($pos < $size)
{
$currentsize = (($size-$pos)>=4096) ? 4096 : ($size-$pos);
$content = fread($filein, $currentsize);
$encrypt = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, "passwortpasswort", $content, MCRYPT_MODE_CBC, $iv);
$iv = substr($encrypt, strlen($encrypt) - $iv_size); //neu
fwrite($fileout, $encrypt, $currentsize);
$pos += $currentsize;
}
fclose($filein);
fclose($fileout);
?>
Die drei geänderten/neuen Zeilen haben Kommentare.
Die neue Zeile braucht substr von den verschlüsselten Daten, hier eben der Output von mcrypt_encrypt.
Beim Entschlüssen muss das angepasst werden, weil der Output von mcrypt_decrypt ja die Klartextversion wäre.
Problem 1b (weil ich mir nicht sicher bin, ob es dir klar ist):
Hier im Testlauf wurde ja die selbe $iv-Variable für Ver- und Entschlüsseln verwendet. Das ist in Ordnung. Wenn das Entschlüsseln aber irgendwann zeitlich/codemäßig unabhängig vom Verschlüsseln gemacht wird ist die Frage, wo man fürs Entschlüsseln den IV hernimmt. Er muss nämlich gleich sein wie beim Verschlüsseln. Beim Verschlüsseln wird irgendein zufälliger IV generiert, aber der muss mit den Daten gespeichert und beim Entschlüsseln dann verwendet werden.
Problem 2: "passwortpasswort" oder Ähnliches ist ein sehr schlechter Schlüssel:
a) 128bit statt der geforderten 256bit (mcrypt paddet das ganz nett mit 0, statt sich zu beschweren, leider)
b) Effektiv nur 44 statt 256 bit stark weil Entropie
c) Sehr gutes Ziel für Listen von bekannten Wörtern
d) und und und...
Ein guter Key sollte eine möglichst zufällige Bit/Bytefolge sein. (Und es ist bewiesen, dass ein "zufällig" auf der Tastatur herumtippender Mensch keine wirkliche Zufälligkeit erzeugt. Überlass das dem Computer)