Java FileOutputStream

sianon

Lt. Junior Grade
🎅Rätsel-Elite ’24
Registriert
Jan. 2008
Beiträge
309
Guten Abend,

ich bastel gerade an einer RSA Verschlüsselung, wobei die Verschlüsselung an sich funktioniert. Unglücklicherweise komm ich mit dem FileOutputStream bzw. ObjectOutputStream noch nicht wirklich zu Recht. Hier ein vereinfachter Auszug aus meiner toFile Methode aus der mein Problem aber klar werden sollte:

Code:
		RSAOutputStream output = new RSAOutputStream(new ObjectOutputStream(new FileOutputStream(filename)),exponent,modulo);
		
	        output.writeChar('S');
		
		output.close();

Anmerkung: writeChar() ist in RSAOutputStream nicht mit dem writeChar der Klasse ObjectOutputStream zu verwechseln. Char 'S' wird hier nur zum Testen benutzt!

In RSAOuputStream.writeChar(char c) wird der übergebene Character zunächst verschlüsselt (was auch funktioniert) und dann mit ObjectOutputStream.writeChar(VerschlüsselterChar) in den ObjectOutputStream geschrieben.
Der RSAOutputStream bekommt dabei im Konstruktor einen ObjectOutputStream übergeben, der wie (s.o.) ( new ObjectOutputStream(new FileOutputStream(filename))) heißt. Mit der Methode writeChar auf diesen Stream angewendet, müsste ich folglich in die Datei "filename" schreiben können, oder habe ich das falsch verstanden?

In meiner verdammten Output-Datei erhalte ich aber nur hässliche Kästen oder chinesisch oder irgendwelche anderen seltsamen Zeichen.

Woran liegt das?

P.S.: Tut mir Leid, dass ich nicht mehr Code posten kann, aber wenn nachher ein Kommilitone die gleiche Lösung abgibt wie ich gibts Punktabzug. Es handelt sich wahrscheinlich sowieso eher um ein generelles Verständnisproblem bezüglich der Benutzung der Streams.

Mit freundlichen Grüßen,
sianon
 
Zuletzt bearbeitet:
Ist es nicht Sinn der Sache, dass man kryptische Zeichen in der Output Datei erhält? Schließlich willst du verschlüsseln...
 
logisch kommt da nur "Grütze" raus.. ein Objectstream schreibt doch auch nur Bytecode.

Wenn du eine lesbare Ausgabe (und sei sie halt verschlüsselt) haben möchtest, würde ich einen PrintWriter verwenden. Dann aber auch passend dazu einen FileWriter, keinen Stream.

Allgemein: Streams = "Byte-Ströme", Writer = Zeichenketten
 
Zuletzt bearbeitet:
So wie du es beschreibst komm ich zur gleichen Aussage wie #2 ... Versuch doch mal die Datei wieder einzulesen und dabei zu entschlüsseln und dann guckst du ob der entschlüsselte Inhalt = S ist ;)
 
@Redirion: Sorry, aber deine Begründung ist Murks... Also Byte-Code ist das, was der Java-Compiler ausspuckt...

Und eine Text-Datei ist genauso ein Byte-Strom... (bzw kann so behandelt werden)
 
"So wie du es beschreibst komm ich zur gleichen Aussage wie #2 ... Versuch doch mal die Datei wieder einzulesen und dabei zu entschlüsseln und dann guckst du ob der entschlüsselte Inhalt = S ist "

Ich weiß ja was das verschlüsselte Zeichen für S ist. Nur schreibt er dieses Zeichen nicht in mein Textdokument.

Beispiel: Sei das verschlüsselte Äquivalent zu S = ó. Nach ObjectOutputStream.writeChar(ó) finde ich dieses ó aber nicht in meiner Textdatei wieder, sondern nur unverständlichen Quatsch. Für ObjectOutputStream muss man sich den Stream denken der über FileOutputStream auf die Datei zugreift. (Erzeugt durch: new ObjectOutputStream(new FileOutputStream(filename)))
 
Zuletzt bearbeitet:
1668mib schrieb:
@Redirion: Sorry, aber deine Begründung ist Murks... Also Byte-Code ist das, was der Java-Compiler ausspuckt...

Und eine Text-Datei ist genauso ein Byte-Strom... (bzw kann so behandelt werden)

meine Begründung ist kein Murks.
Ich habe bisher die einzige richtige Antwort geschrieben.

diese hässlichen Kästchen oder chinesischen Zeichen sind nämlich der Bytecode, der von den Streams erzeugt wird und somit für Menschen nicht lesbar.

Streams nutzt man auch eher zur Serialisierung von Objekten.

Für lesbaren Text (das gilt auch für Hashcode zum wieder entschlüsseln): PrintWriter und FileWriter kombinieren.
 
Auch wenn es mit genannten Writern einfacher sein mag, ein Text-Dokument zu erstellen, so stellt es kein Hexenwerk dar, das auch mit einem Stream zu machen...

Oder ist das ein Bug, dass das bei mir so funktioniert?
Code:
		String s = "Hallo";
		
		byte[] content = new byte[s.length()];
		for (int i = 0; i < s.length(); i++) {
			content[i] = (byte)(s.charAt(i));
		}
		
		FileOutputStream stream = new FileOutputStream("test.txt");
		stream.write(content);
		stream.flush();
		stream.close();
 
Zuletzt bearbeitet:
Also mag sein, dass ich gerade was völlig falsch verstehe aber:

S verschlüsseln = unlesbarer chinesischer Murks
chinesischer Murks in Datei schreiben = chinesischer Murks in der Datei

....

Ich mein wenn du ein S in der Datei stehen haben willst dann solltest du es nicht verschlüsseln...?
 
Ich will schon etwas in der Datei haben was über einen Algorithmus auf das S zurückgeführt werden kann. Wo wäre sonst der Sinn?
 
Gibts die Klasse irgendwo zu ziehen btw? (ok,google 1. treffer wohl)

Und das hier ist kein Hausaufgabenforum, nur mal so am Rande erwähnt...


Edit:
Du weißt schon, dass du beim Einlesen die Inverse von exponent nehmen musst?

Code:
	final int e = 47;
		final int n = 5917;
        final int d = 1103; // inverse von e in N(n)
		
		RSAOutputStream output = new RSAOutputStream(new ObjectOutputStream(new FileOutputStream("crypt.txt")), e, n);
		
        output.writeChar('S');
	
        output.close();
        
        
        RSAInputStream input = new RSAInputStream(new ObjectInputStream(new FileInputStream("crypt.txt")), d, n);
        
        System.out.println(input.readChar());
        
        input.close();
 
Zuletzt bearbeitet:
1668mib schrieb:
Auch wenn es mit genannten Writern einfacher sein mag, ein Text-Dokument zu erstellen, so stellt es kein Hexenwerk dar, das auch mit einem Stream zu machen...

Oder ist das ein Bug, dass das bei mir so funktioniert?
Code:
		String s = "Hallo";
		
		byte[] content = new byte[s.length()];
		for (int i = 0; i < s.length(); i++) {
			content[i] = (byte)(s.charAt(i));
		}
		
		FileOutputStream stream = new FileOutputStream("test.txt");
		stream.write(content);
		stream.flush();
		stream.close();

Die Klasse String implementiert das Interface Serializable. Du kannst also mit der Methode writeObject des ObjectoutputStreams das Ding in Kombination eines FileOutputStreams wunderbar in eine Datei schreiben.
Das Ergebnis ist dann anstelle von "Hallo" aber eben "Kästchen" bzw. Chinazeugs.

Auf die gleiche Weise, kann man mit readObject dann den String wieder zurückgewinnen...

wie ich aber schon sagte.. der TE möchte eine LESBARE Datei.. so hatte ich das zumindest verstanden.

Mit Streams ist da nichts lesbar!

@TE: bitte einfach mal probieren, was ich sagte.. ;-)


Blah schrieb:
Also mag sein, dass ich gerade was völlig falsch verstehe aber:

S verschlüsseln = unlesbarer chinesischer Murks
chinesischer Murks in Datei schreiben = chinesischer Murks in der Datei

....

Ich mein wenn du ein S in der Datei stehen haben willst dann solltest du es nicht verschlüsseln...?

Bei Call of Duty 4 sahen die Spielstände verdächtig danach aus, als hätte man einfach Objecte in Bytecode in Dateien abgelegt. Für Anwender natürlich nicht modifizierbar. Das ist aber keine Verschlüsselung, sondern eher "Verschleierung".
 
Zuletzt bearbeitet:
"Gibts die Klasse irgendwo zu ziehen btw? (ok,google 1. treffer wohl)

Und das hier ist kein Hausaufgabenforum, nur mal so am Rande erwähnt... "

Ich habe niemanden darum gebeten meine Aufgabe zu lösen. Mir geht es nur um die richtige Benutzung der Streams. Die Aufgabe besteht in der Verschlüsselung.
Ergänzung ()

@Redirion: Ich teste morgen mal ob ich den Bytecode entsprechend auslesen und wiederverwerten kann. Wenn das funktioniert ist mir die Lesbarkeit egal ;-)
 
Fangen wir mal ganz am Anfang an. Beim RSA selbst. Um bei RSA Text zu verschlüsseln wird dieser in Zahlen umgewandelt, speziell deren Darstellung in UTF-8 oder ASCII. So wird aus einem S eine 83. Diese 83 wird nun durch den Algorithmus verschlüsselt und ergibt z.B. eine 6. Diese 6 wird in die Datei geschrieben und ergibt in einem Texteditor das Steuerungszeichen "ACK", was im Bereich der nicht textuellen Zeichen ist und Blödsinn (für den Menschen) ergibt. Die Lösung besteht nun darin, es sich in einem Hex Editor anzuschauen.
 
@Redirion:Wie soll das verschlüsselte denn überhaupt lesbar sein? oO

Und wie du an meinem Beispiel siehst kann man auch mit Streams alles lesbar machen... wenn man denn will...

Hab übrigens oben nen edit gemacht, Fehler liegt zu 99,9% darin, dass beim Lesen nicht die multiplikative Inverse zum Exponent verwendet wurde...
 
1668mib schrieb:
@Redirion:Wie soll das verschlüsselte denn überhaupt lesbar sein? oO

Und wie du an meinem Beispiel siehst kann man auch mit Streams alles lesbar machen... wenn man denn will...

Hab übrigens oben nen edit gemacht, Fehler liegt zu 99,9% darin, dass beim Lesen nicht die multiplikative Inverse zum Exponent verwendet wurde...

also laut Wikipedia ist das Verschlüsselungsergebnis bei RSA eine Zahlenfolge.

Also z.B. soetwas: 219611

ohne passende Schlüssel kommt man auch trotz der lesbaren Zahl nicht darauf, was hier verschlüsselt wurde...

wenn du allerdings das Ergebnis der Verschlüsselung bei Java mit einem Stream in eine Datei speicherst, landet soetwas in deiner Datei: [][][][][][]
für einen Menschen nicht lesbar, und daher schwer nachvollziehbar, ob nun auch das richtige in die Datei geschrieben wurde...

Mit einem PrintWriter würde die lesbare Zahl zwar in der Datei landen, aber sie wäre ja dennoch das Ergebnis der Verschlüsselung
 
Ja aber mit einem PrintWriter können die Klassen halt nicht zusammenarbeiten... aber es wäre auch echt idiotisch, auf das Problem einzugehen und sich wirklich mal Gedanken zu machen als irgendwelchen theoretischen Unsinn zu labern...

Und nochmal auch für dich zum Mitschreiben: Auch mit jeden Stream lassen sich Dateien erzeugen, die problemlos von Menschen erzeugt werden können (wenn man denn will!). Darauf wurde aber bei der Implementierung der RSAOutputStream/RSAInputStream-Klassen gar kein Wert gelegt, es hat auch keinen Mehrwert...

Die Klassen sind im Übrigen so implementiert, dass BigInteger-Objekte - wie du wenigstens richtig sagst - serialisiert gespeichert werden. Das hat aber auch einen guten Grund... Bei RSA werden i.d.R. sehr große Primzahlen eingesetzt (idealerweise ~1024-Bit-Zahlen, die in einem Modul von ~2048 Bit resultieren...). Da macht das Speichern von Zahlen in Klartext nunmal nicht wirklich viel Sinn, weil wieviel Zeichen stehen denn für eine Ziffer?

123 => sind das nun drei Zahlen? Sind das 2 Zahlen? Welche zwei? Ist das eine Zahl?
Ist die erste Zahl "12" und die zweite "3"? Die erste "1" und die zweite "23"? Kann ja alles sein...
 
Zuletzt bearbeitet:
"Diese 83 wird nun durch den Algorithmus verschlüsselt und ergibt z.B. eine 6. Diese 6 wird in die Datei geschrieben und ergibt in einem Texteditor das Steuerungszeichen "ACK", was im Bereich der nicht textuellen Zeichen ist und Blödsinn (für den Menschen) ergibt. Die Lösung besteht nun darin, es sich in einem Hex Editor anzuschauen. "

Die 6 wird bei uns noch zu einem char gecastet.
 
@simon: Du hast meinen Edit oben nicht beachtet oder?

a) es macht gar keinen Sinn das verschlüsselte so zu speichern wie du es gerne hättest (Begründung siehe in #17)
b) hast du beim Einlesen auch die inverse Multiplikative vom Exponent verwendet?
 
1.) Ja klar siehst du dann nur Datensalat. Wenn du die Datei ganz normal lesen könntest, wäre der Verschlüsselungsalgorithmus ja etwas sinnlos ;)

2.) Tu dir den Gefallen und verwende keinen ObjectOutputStream. Abgesehen von einigen wenigen Spezialfällen, die vielleicht existieren ist das nur eine einzige Quelle von Bauchschmerzen, spätestens wenn du die Software dann auch wirklich einsetzen willst und warten musst.

3.) Beim Verwenden von Streams muss man beachten, dass die meisten Verschlüsselungsalgorithmen keine streambasierte Verarbeitung ermöglichen. Man kann nur einen gesamten Datenblock entgegen nehmen und dann nachher verschlüsseln. Die ganzen Cryptostreams lösen das Problem meistens mit einem internen Cache, die die Daten blockweise verschlüsselt und in den darunterliegenden Stream schreibt und wartet, bis Close aufgerufen wird. Das funktioniert ganz gut bei Dateien aber spätestens wenn man übers Netzwerk Daten austauschen will (und gerade da werden Verschlüsselungsalgorithmen hauptsächlich eingesetzt), wird einem das zum Verhängnis. Man schreibt in den NetworkStream rein, aber auf der anderen Seite kommt nicht alles an, bis man die Verbindung schließt.
Weiters sollte dir bewusst sein, dass ein High Level Stream ein ausschließliches Benutzungsrecht auf seinen Low Level Stream hat. Es ist nicht mehr möglich unverschlüsselte Daten über diesen Stream zu schreiben. So ist es nicht möglich einen unverschlüsselten Dateiheader zu schreiben, der festlegt, um welchen Algorithmus es sich überhaupt handelt. Eine verschlüsselte Übertragung sollte immer so gestaltet sein, dass man den Algorithmus jederzeit ändern kann, falls dieser geknackt werden sollte, aber die bestehenden Dateien muss man ja schon noch auslesen können ;)
Ich empfehle hier stattdessen gleich ein ein Protokoll zu entwickeln, wenn du das wirklich einsetzen willst, indem du festlegst, was du übertragen willst. Ich habe das bisher so gemacht:

a) 4 Bytes Little Endian Länge der verschlüsselten Übertragung in Bytes (damit weiß der Auslesende, wie viel er lesen muss)
b) 4 Bytes Little Endian Länger der Nettodaten in Bytes (ist oft von Vorteil bei manchen Implementierungen von Algorithmen und in den meisten Fällen nicht wirklich ein Sicherheitsproblem. Wenn man ein kritisches Passwort übertragen will, dann muss man das eben mit 0ern auffüllen)
c) Verschlüsselte Daten

Ich lese dann die Verschlüsselten Daten mit einem normalen Stream aus und wandle dann verschlüsselten Daten um. Das schaut je nach Programmiersprache anders aus.

4.) RSA ist nicht zum Ver- und Entschlüsseln von Daten geeignet. Manche Implementierungen lassen hier sogar nur eine bestimmte Menge an Daten zu. RSA ist ein asymetrischer Algorithmus zum sicheren Austausch von symetrischen Schlüsseln. Wenn du Dateien verschlüsseln willst, dann nimm DES oder noch besser wenn vorhanden AES.

Willst du Daten verschlüsselt übers Netzwerk verschicken und der Schlüssel auf der anderen Seite nicht bekannt sein, so sollten die Daten symetrisch verschlüsselt werden (z.B. AES) und nur der Schlüssel mit RSA übertragen werden (genau dafür ist RSA da).

Dies sieht so aus:

a) Sender sendet seinen öffentlichen RSA Key (unverschlüsselt, da ja öffentlich)
b) Empfänger generiert einen AES (bzw. DES) Key und verschlüsselt diesen mit dem RSA Key
c) Sender liest die Daten und entschlüsselt den DES Key mit seinem privaten RSA Key
d) Sender schickt seine Daten verschlüsselt mit diesem Schlüssel

Damit lassen sich auch in einer unverschlüsselten Übertragung kurze verschlüsselte Sequenzen einbinden (z.B. für Passwörter)

Edit:

5.) Wenn du einen String schreibst, dann musst du dir IMMER darüber im Klaren sein in welcher Codierung. Deshalb ist die Serialisierung von String auch kompletter Schwachsinn. Der String weiß nicht, ob er als UTF8, lokaler Kodierung (Windows 1252) oder als 16-Bit Unicode gespeichert werden soll.

6.) Ein Verschlüsselungsalgorithmus sollte nie einzelne Bytes verschlüsseln. Wenn z.B. aus 83 immer 7 wird, lassen sich die Daten ziemlich schnell mit einer Known Plaintext Attacke rekonstruieren, wenn man das Protokoll kennt. Da muss die Schlüssellänge wesentlich höher sein, damit das etwas bringt.
Bei RSA ist das besonder kritisch, da dieser nur darauf passiert, dass die Entschlüsselungszeit mehr oder weniger exponentiell mit der Schlüssellänge wächst. Wenn du nur einen 1Byte Schlüssel hast, dann ist dieser schnell geknackt. Übliche Längen liegen hier bei ca. 2048 Bits. Mit 64Bits oder darunter hält der nicht einmal annähernd so lange wie eine symetrische Verschlüsselung wie DES oder AES.

7.) Bei RSA sollte man sich auch ums Padding Gedanken machen. Da gibt es mehrere Standards, aber frag mich nicht auswendig, wie der Algorithmus genau geht. Das Hauptproblem am normalen RSA Algorithmus ist, dass sich manche Daten sonst nicht verschlüsseln lassen. 0 und 1 bleiben immer 0 bzw. 1 egal wie oft man diese potentiert. Wenn man als wichtige Daten nur einen Boolean als geheime Information zurück schickt, kann das ganz schön in die Hose gehen.
 
Zuletzt bearbeitet:

Ähnliche Themen

Zurück
Oben