Binärdatei lesen und neu erstellen

3r4g0n

Grünschnabel
Hallo,
Ich versuche eine Binäredatei zu lesen und dann wieder zu erstellen so das sie ausführbar ist.
Ich habe schon rausgefunden wie ich sie lese:

PHP:
<?php

    $filename ="d.exe";
      $fp = fopen($filename, 'rb');
        $content = fread($fp, filesize($filename));
        fclose($fp);
        for($i=0;$i < strlen($content);$i++)
                {
                for($b=0;$b<8;$b++)
                        {
                        echo (((1 << $b) & ord($content[$i])) > 0)?'1':'0';
                        }
                }
?>

aber noch nicht gefunden wie ich sie wieder Erstelle, so das sie auch wieder ausführbar ist.
Was ich probiert habe war derzeitig eher kontraproduktiv oder er hat es mir in eine datei geschrieben welche ich dann per editor öffnen konnte und mir das angezeigt hat was schon beim echo gekommen ist.

Danke für eure Hilfe
MfG Eragon
 
Nein, ich brauche die Datei als String da ich die Verschlüsseln will. Ich möchte sie natürlich auch wieder entschlüsseln können und dann als korrekt ausführbare Datei speichern.
 
Gut, dann ist das Einlesen zuerst einmal sehr schlecht, weil es nur bei kleinen Dateien funktioniert.
Alternatives Gerüst:
PHP:
$filenamein ="d.exe";

//wenn d.exe durch die verschlüsselte Version ersetzt
//werden soll, zuerst einmal tempnam() verwenden
$filenameout ="d.exe.enc";

$filein = fopen($filenamein, 'rb');
$fileout = fopen($filenameout, 'wb');

//Prüfen ob beide Dateien geöffnet werden konnten, ggf.
//Fehlerbehandlung und die evt. offene eine Datei wieder schließen

$size = filesize($filenamein);
$pos = 0;
while ($pos < $size)
{
	$currentsize = (($size-$pos)>=4096) ? 4096 : ($size-$pos);
	$content = fread($filein, $currentsize);

	//Daten von $content mit Länge $currentsize verschlüsseln

	fwrite($fileout, $content, $currentsize);
	$pos += $currentsize;
}


fclose($filein);
fclose($fileout);

//wenn d.exe durch die verschlüsselte Version ersetzt werden soll,
//mit rename und unlink alte Datei weg und die Verschlüsselte da hin schieben
Sachen zum Ergänzen/Anpassen sind sind Kommentare.

Und wenn das keine praxisfremde Schulaufgabe ist, die eine einfache aber unsichere
"Verschlüsselungs"-Methode vorschreibt, schau dir AES inkl. Padding an (bzw. die
PHP-Funktionen, die AES schon implementiert haben). Je nach Bedarf zusätzlich RSA,
SHA3 etc.etc.
 
Danke,
Hab das ganze jetzt so gelöst:
PHP:
<?php
$filenamein = "d.exe";
$filenameout = "d2.exe";
$filenameout2 = "d22.exe";
$filein = fopen($filenamein, 'rb');
$fileout = fopen($filenameout, 'wb');
$fileout2 = fopen($filenameout2, 'wb');
$size = filesize($filenamein);
$pos = 0;
while ($pos < $size)
{
    $currentsize = (($size-$pos)>=4096) ? 4096 : ($size-$pos);
    $content = fread($filein, $currentsize);
    $iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
    $iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
    $encrypt = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, "passwortpasswort", $content, MCRYPT_MODE_ECB, $iv);
    fwrite($fileout, $encrypt, $currentsize);
    $decrypt = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, "passwortpasswort", $encrypt, MCRYPT_MODE_ECB, $iv);
    fwrite($fileout2, $decrypt, $currentsize);

    $pos += $currentsize;
}
fclose($filein);
fclose($fileout);
fclose($fileout2);
?>

Verbesserungsvorschläge (außer Fehlerbehandlung)?
 
Die dritte Datei ($fileout2) ist wohl nur zum prüfen da, obs funktioniert?
Sonst versteh ich den Sinn nicht ganz.

Beim Blockmodus hab ich etwas auszusetzen:

a) ECB ist aus Sicherheitsgründen nicht zu empfehlen.
Wenn man nur immer die ganze Datei ver/entschlüsselt und sonst keine ungewöhnlichen Anforderungen hat bietet sich CBC an. Der Nachteil davon ist eben, dass man bei einer komplett verschlüsselten Datei nicht beliebige Teile davon einzeln entschlüsseln kann, sondern nur alles zusammen
(genauer gesagt alles zwischen Dateianfang und dem letzten zu lesenden Byte muss entschlüsselt werden. Wenn man nur das letzte Byte von einer 100GB-Datei will kann das dauern.)

b) Wenn trotz allem ECB eingesetzt wird ist der IV unnötig (nicht wirklich falsch, aber sinnlos)
 
Die dritte Datei ($fileout2) ist wohl nur zum prüfen da, obs funktioniert?
Sonst versteh ich den Sinn nicht ganz.
Jep, war nur zum Prüfen da und wäre halt meine Entschlüsselfunktion.

Nehme nun CBC.
Der Nachteil davon ist eben, dass man bei einer komplett verschlüsselten Datei nicht beliebige Teile davon einzeln entschlüsseln kann, sondern nur alles zusammen
(genauer gesagt alles zwischen Dateianfang und dem letzten zu lesenden Byte muss entschlüsselt werden. Wenn man nur das letzte Byte von einer 100GB-Datei will kann das dauern.)
Es muss ja so oder so alles entschlüsselt werden damit die datei wieder sinn ergibt. Inwieweit ist ECB unsicher?

Wenn trotz allem ECB eingesetzt wird ist der IV unnötig (nicht wirklich falsch, aber sinnlos)
Was müsste ich ändern? Einfach nur IV löschen?
 
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)
 
$iv=substr($encrypt,strlen($encrypt)-$iv_size);
Wenn ich das rauslasse funktionierts, samt decrypt funktion. Ansonsten funktioniert die Decrypt funktion nicht mehr.

Das Passwort war natürlich nur Testen. Wenn ein Passwort zu Kurz oder zu Lang ist einfach nen paar zeichen hinzufügen oder Entfernen oder wie Komme ich sonst auf die nötige Länge?
 
Wie schon geschrieben ist die Zeile bei Encrypt/Decrypt unterschiedlich.

Bei AES mit 256bit-Key (wie von dir verwendet) muss der Key 256 bit haben, also 32 Byte.
Deiner hat 16 (hoffentlich, abhängig vom Charset. Sonst wirds nochv erwirrter).

Und auch wenns die passende Länge hat sind normale Buchstaben sehr schlecht.
http://de.wikipedia.org/wiki/Entropie_(Informationstheorie)
Nocheinmal, ein Wert von einem kryptographisch tauglichen Pseudozufallsgenerator ist das Mindeste.
 
Zurück