Binärdatei verschlüsseln und ausgeben
-
Hi!
Ich möchte eine Binärdatei einlesen, dann mit RC4 verschlüsseln und dann in eine andere Datei ausgeben.
Das Problem ist allerdings folgendes:
Ursprünglich liegt die Datei binär vor, also wenn ich sie im Notepad aufmache, sehe ich fast nur eckige Kästchen.
Wenn ich die Datei dann allerdings einlese, verschlüssle und gleich wieder entschlüssle und in eine andere Datei ausgebe, dann sieht die ausgegebene Datei nicht so aus, wie die Originale .. also es stehen nicht mehr lauter eckige Kästchen drinnen, sondern praktisch ASCII-Code. Anfangen tut dies in meinem Fall mit "CWS<eckiges Kästchen>ón<eckiges Kästchen>...." (ist eine SWF-Datei).
Ich möchte nun natürlich, dass die ausgegebene Datei wieder genau so wie die originale, also binär, aussieht.Der Code:
void rc4(unsigned char * ByteInput, int size, unsigned char * pwd, unsigned char * &ByteOutput){ unsigned char * temp; int i,j=0,t,tmp,tmp2,s[256], k[256]; for (tmp=0;tmp<256;tmp++){ s[tmp]=tmp; k[tmp]=pwd[(tmp % strlen((char *)pwd))]; } for (i=0;i<256;i++){ j = (j + s[i] + k[i]) % 256; tmp=s[i]; s[i]=s[j]; s[j]=tmp; } temp = new unsigned char [ size ] ; i=j=0; for (tmp=0;tmp<size;tmp++){ i = (i + 1) % 256; j = (j + s[i]) % 256; tmp2=s[i]; s[i]=s[j]; s[j]=tmp2; t = (s[i] + s[j]) % 256; if (s[t]==ByteInput[tmp]) temp[tmp]=ByteInput[tmp]; else temp[tmp]=s[t]^ByteInput[tmp]; } ByteOutput=temp; }Aufrufen tu ich es so:
unsigned char *Buffer = NULL; int size = 123; ReadFile ( "u1.swf", &Buffer, &size); // lest einfach die ganze Datei in den Buffer und gibt die Länge zurück unsigned char * message; unsigned char * pwd; unsigned char * encrypted; unsigned char * decrypted; message=Buffer; pwd=(unsigned char *)"asdf"; rc4(message,size,pwd,encrypted); rc4(encrypted,size,pwd,decrypted); FILE *pFile1 = fopen ( "u2.swf", "wb" ); fwrite(decrypted, sizeof(unsigned char), size, pFile1); fclose(pFile1);Die RC4-Funktion hab ich aus dem Internet, ich habe sie nur so verändert, dass ich ihr den Size-Paramter übergeben kann, falls mal mittendrin ein Nullcharacter is, damit er da halt nicht abbricht.
Meine Vermutung ist, dass es an der Zeile mit dem XOR liegt, ich weiß aber nicht was ich ändern muss, damit es funktioniert.
Kann mir da wer weiterhelfen?
lg
Christian
-
Schreib dir ne Testfunktion die ohne Dateien arbeitet, sondern direkt die zu verschlüssenden Daten enthält. Nimm nen Debugger und schau dir an, was passiert. Geht es immer richtig, wenn du eine Datei verschlüsselst, die nur ein Zeichen enthält? Geht es für Textdateien richtig? ...
-
if (s[t]==ByteInput[tmp]) temp[tmp]=ByteInput[tmp]; else temp[tmp]=s[t]^ByteInput[tmp]; }Ist ByteInput hier nicht uninitialisiert? Das wäre dann allerdings ein Fehler, den man durch Beachtung minimaler Coding-standards (Variablen werden immer initialisiert & erst dann definiert, wenn sie initialisiert werden können) vermeiden konnte.
-
camper schrieb:
Ist ByteInput hier nicht uninitialisiert? Das wäre dann allerdings ein Fehler, den man durch Beachtung minimaler Coding-standards (Variablen werden immer initialisiert & erst dann definiert, wenn sie initialisiert werden können) vermeiden konnte.
Das ByteInput wird doch als Parameter übergeben :p
Aber hier noch was, den Speicher von encrypted bzw decrypted musst du wieder freigeben:
temp = new unsigned char [ size ] ; ByteOutput=temp; ... rc4(message,size,pwd,encrypted); rc4(encrypted,size,pwd,decrypted);Kann sein, dass das im Code noch folgt, aber man weiß es ja nicht..
Und eines versteh ich auch noch nicht: Muss man bei dem rc4 zwei mal verschlüsseln? Du liest ja die Datei ein, verschlüsselst zwei mal und schreibst dann die neuen Daten raus. Sicher, dass das nicht nur ein mal getan werden muss?
-
edit: Blöde bezeichnungen - ich hatte einfach ByteInput und ByteOutput verwechselt - da ist optisch kaum ein Unterschied.
-
Badestrand schrieb:
Und eines versteh ich auch noch nicht: Muss man bei dem rc4 zwei mal verschlüsseln? Du liest ja die Datei ein, verschlüsselst zwei mal und schreibst dann die neuen Daten raus. Sicher, dass das nicht nur ein mal getan werden muss?
Normalerweie natürlich nur einmal, aber ich will ja nur testen ob meine Verschlüsselung funktioniert, darum verschlüssle ich den text .. und verschlüssle ihn dann gleich nochmal, um ihn wieder zu entschlüsseln (is ja ein symmetrisches verschlüsselungsverfahren).
jetzt müsste ja eigentlich der decrypted-text wieder genau dem original entsprechen .. im debugger tut er das ja auch, nur in der datei dann nicht.ich hab aber jetzt ne andere entdeckung gemacht: die ursprüngliche datei (die swf-datei) liegt in unicode vor, nach dem ver/entschlüsseln und ausgeben liegt die neue datei aber in ANSI vor.
wie kann ich die datei in unicode einlesen bzw. ausgeben?
-
m0m0 schrieb:
jetzt müsste ja eigentlich der decrypted-text wieder genau dem original entsprechen .. im debugger tut er das ja auch,
hätte mal erwähnt werden können...
-
also ich hab jetzt mal überall wo "unsigned char" gestanden is "wchar_t" hingeschrieben, das is doch ein unicode-datentyp, oder?
in der zweiten datei, in der ich den verschlüsselten und wieder entschlüsselten text ausgebe, stehen nun tatsächlich wieder binärzeichen, nur leider einige zuviel. es wird also der originaltext hingeschrieben, und hinten noch einige andere zeichen drangehängt.
Bei
fwrite(decrypted, sizeof(wchar_t), size, pFile1);steht in size zwar der selbe Wert drin, wie am Angang, es werden aber weit mehr Zeichen ausgegeben. Hat jemand eine Ahnung warum?
-
Da du die Dateien binär behandeltst, spielt Unicode
ANSI keine Rolle 
Und dass
fwrite(decrypted, sizeof(wchar_t), size, pFile1);doppelt soviel schreibt, ist kein Wunder
Schließlich werden size*sizeof(wchar_t)Bytes geschrieben stattsize*sizeof(char)Bytes.Und was du noch tun könntest: Wenn du mit dem Visual Studio arbeitest, kannst du die Anfangs- und ver-ent-schlüsselte Datei mit der Dateiendung ".bin" versehen und mit dem VS öffnen - hier kannst du dann bequem vergleichen, inwiefern die Dateien unterschiedlich sind

-
Lies doch nur mal die Datei ein und speicher sie wieder. ohne verlschüsseln
-
einlesen und ohne verschlüsseln gleich wieder rausschreiben hat vorher schon funktioniert, bevor ich das mit dem wchar_t geändert hab.
doppelt soviel gibt er jetzt auch nicht mehr aus .. allerdings scheint das ganze nur bei kleinen dateien zu funktionieren. keine ahnung warum. wenn ich ne 5 kb datei nehme, funktionierts ohne probleme. bei einer 90 kb datei steht in der ausgabedatei ein paar tausend mal das selbe zeichen (sieht wie ein komisches i aus).
und wie ichs mit einer datei mit einer größe von ca. 30 kbs probiert hab, hats beim ausführen einen fehler gegeben in der zeile
if (s[t]==ByteInput[tmp])t war bei ca. 80 und tmp bei ein paar tausend, aber noch lange nicht bei size, also irgendwo mitten drinnen. warum hier ein fehler geworfen wurde versteh ich aber nicht. selbst wenn ByteInput[20000] oder was das war NULL gewesen wäre, müsste doch der vergleich ob s[t] gleich null ist funktionieren und keinen fehler erzeugen, der das programm abbricht. wie gesagt, ich verstehs grad nicht.
-
m0m0 schrieb:
selbst wenn ByteInput[20000] oder was das war NULL gewesen wäre, müsste doch der vergleich ob s[t] gleich null ist funktionieren und keinen fehler erzeugen, der das programm abbricht.
Naja, ByteInput[xx] kann nicht NULL zurückgeben. Zeig doch mal deine
ReadFile ( "u1.swf", &Buffer, &size)-Methode.
-
void ReadFile ( char *Filename, wchar_t **Buffer , int *size) { FILE *pFile = fopen ( Filename, "rb" ); if( pFile != NULL ) { fseek ( pFile, 0, SEEK_END ); *size = ftell ( pFile ); *Buffer = (wchar_t *) malloc ( *size ); fseek ( pFile, 0, SEEK_SET ); fread ( *Buffer, sizeof(wchar_t), *size, pFile ); } fclose ( pFile ); }
-
wchar_t sind doch immer 2 Bytes. Ich glaub da gibts Probleme, wenn die Dateigröße nicht durch 2 Teilbar ist.
-
C&P-Programmierung ... und so furchtbar viel (=alles) C drin...
fread ( *Buffer, sizeof(wchar_t), *size, pFile );das ist jedenfalls unsinn (es sei denn, es ist gerade mal sizeof(wchar_t)==1).
-
Davon mal abgesehen das wir hier im C++-Teil sind ... guck dir nochmal den RC4A-Algo an ... http://de.wikipedia.org/wiki/RC4 hast nen Fehler drin ...
-
Interessante Sache, dieser RC4! Wikipedia nennt ihn ja sogar "sicher"

Naja, jedenfalls hab ich ihn einfach mal programmiert, ist ja zum Glück recht simpel:
void Rc4( const char* input, char* output, unsigned int size, const char* key ) { unsigned int keylen = strlen(key); unsigned char s[256]; for ( int i=0; i<256; i++ ) s[i] = i; for ( int i=0, j=0; i<256; i++ ) { j = (j + s[i] + key[i%keylen]) % 256; unsigned char c = s[i]; s[i] = s[j]; s[j] = c; } for ( int i=0, j=0, k=0; k<size; k++ ) { i = (i+1) % 256; j = (j+s[i]) % 256; unsigned char zufall = s[ (s[i]+s[j])%256 ]; output[k] = zufall ^ input[k]; unsigned char c = s[i]; s[i] = s[j]; s[j] = c; } }und etwas gekürzt, muss nicht unbedingt stimmen, sollte aber (:D):
void Rc4( const char* input, char* output, unsigned int size, const char* key ) { uint keylen = strlen(key); unsigned char s[256]; for ( int z=0; z<256; ++z ) s[z] = z; unsigned char j = 0; for ( int z=0; z<256; ++z ) { j += s[z] + key[z%keylen]; swap( s[z], s[j] ); } j = 0; unsigned char i = 0; for ( unsigned int k=0; k<size; ++k ) { j += s[++i]; unsigned char idx = s[i] + s[j]; output[k] = s[idx] ^ input[k]; swap( s[i], s[j] ); } }