Socket CipherInput/OutputStream empfängt nichts

Seikuassi

Aktives Mitglied
Hallo Forum-Nutzer,

ich habe folgenden Teilcode:
Java:
private Key initKey(){
	return new SecretKeySpec(this.AES_pwd,this.algor);
}
private final byte[]AES_pwd={x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x}; // x ersetzt durch Zahlen (16 Bytes)
private final String algor="AES";
Java:
Cipher cipher;

this.close();
if(this.type==TYPE.CLIENT){ // wenn ein Client erstellt werden soll
	this.socket=new Socket();
	this.socket.setReceiveBufferSize(this.bufferSize);
	this.socket.setSendBufferSize(this.bufferSize);
	this.socket.setSoTimeout(this.timeout);
	this.socket.connect(new InetSocketAddress(IP,this.port),this.timeout); // mit Server verbinden
	{ // Cipher fuer den Empfang von Daten initialisieren
		cipher=Cipher.getInstance(this.algor);
		cipher.init(Cipher.DECRYPT_MODE,this.initKey());
	}
	this.in=new DataInputStream(/*new CipherInputStream(*/new BufferedInputStream(this.socket.getInputStream())/*,cipher)*/); // <-- hier
	{ // Cipher fuer das Versenden von Daten initialisieren
		cipher=Cipher.getInstance(this.algor);
		cipher.init(Cipher.ENCRYPT_MODE,this.initKey());
	}
	this.out=new DataOutputStream(/*new CipherOutputStream(*/new BufferedOutputStream(this.socket.getOutputStream())/*,cipher)*/); // <-- hier
	this.isConnected=true;
	classes.Network.changeStatusIcon(true); // Status aendern
}else{ // wenn ein Server erstellt werden soll
	this.server=new ServerSocket(this.port);
	this.server.setSoTimeout(this.timeout);
	this.socket=this.server.accept(); // mit Client verbinden
	{ // Cipher fuer den Empfang von Daten initialisieren
		cipher=Cipher.getInstance(this.algor);
		cipher.init(Cipher.DECRYPT_MODE,this.initKey());
	}
	this.in=new DataInputStream(/*new CipherInputStream(*/new BufferedInputStream(this.socket.getInputStream())/*,cipher)*/); // <-- hier
	{ // Cipher fuer das Versenden von Daten initialisieren
		cipher=Cipher.getInstance(this.algor);
		cipher.init(Cipher.ENCRYPT_MODE,this.initKey());
	}
	this.out=new DataOutputStream(/*new CipherOutputStream(*/new BufferedOutputStream(this.socket.getOutputStream())/*,cipher)*/); // <-- hier
	this.isConnected=true;
	classes.Network.changeStatusIcon(true); // Status aendern
}

So (auskommentiert) funktioniert das Senden/Empfangen über das Netzwerk einwandfrei. Wenn ich allerdings den Cipher dazwischenschalte, dann wird angeblich gesendet, allerdings bei der anderen Partei nichts empfangen.
Woran liegt das?

Klar, in diesem Fall könnte man auch den SLLSocket/SLLServerSocket verwenden, aber hier muss es doch auch funktionieren, oder?

Frage:Warum empfängt die andere Partei nichts?

Danke im Voraus!

Mit freundlichen Grüßen
Seikuassi
 

Tobse

Top Contributor
Das Problem hatte ich vor langer Zeit auch mal. Meine Lösung damals war, die CipherStreams neu zu schreiben (ist nicht so schwierig). Damit hat es dann funktioniert und ich habe mich nicht weiter drum gekümmert. Was ich damals als Problemursache vermutet habe, war:

- Der CipherStream wird nicht geflushed. Wenn man das manuell macht funktionierts allerdings immernoch nicht.
- Es müssen genug Bytes für den nächsten Block im CipherStream sein, bevor das flushen funktioniert. Wenn du bereits mehr als einen Block auf den CipherStream geschrieben hast kannst du ihn flushen. Dabei gehen aber nur so viele Bytes raus, wie man ganze Blöcke daraus machen kann (z.B. Blockgröße = 15 Byte, Buffer sind 29 Byte. jetzt flushed du und es werden nur 15 von den 29 Byte aus dem Buffer geschrieben).
Das einzige, was den unvollständigen Block schreibt ist ein close().

Ich habe dann versucht, im Quellcode vom CipherOutputStream das flushen des kompletten Buffers (also wie bei close()) in flush() zu erzwingen. Wie das dann auch nicht funktioniert hat, hatte ich bereits doppelt so viel Zeit mit dem
Problem der Java CipherStreams verbracht, als mich das selbst schreiben dann gekostet hat.


P.S.: Wenn dich meine Lösung interessiert, hier findest du den Sourcecode: WISPER - Download (Package com.wisper.backend)
 

Seikuassi

Aktives Mitglied
Hallo Tobse,

danke für deine Hilfe. Was ist an dem folgenden Code falsch?
main.java:
Java:
Cipher cipher=Cipher.getInstance("AES/CBC/PKCS5Padding");

cipher.init(Cipher.ENCRYPT_MODE,new SecretKeySpec(pwd,"AES"));
try(CipherOutputStream out=new CipherOutputStream(new BufferedOutputStream(new FileOutputStream("./Test.txt")),cipher)){
	out.write("Test".getBytes(StandardCharsets.ISO_8859_1));
}
CipherOutputStream.java:
Java:
class CipherOutputStream extends FilterOutputStream{
	public CipherOutputStream(OutputStream out,Cipher cipher){
		super(out);
		this.cipher=cipher;
	}
	// --- Klassen --- //
	
	// --- Methoden --- //
	/** Schliesst den Stream. **/
	@Override public void close()
	throws IOException{
		this.flush();
		super.close();
		return;
	}
	/** Schreibt alle Bytes unverzueglich in den Stream. **/
	@Override public void flush()
	throws IOException{
		if(b.size()>0){
			try{
				super.write(this.cipher.doFinal(this.b.toByteArray()));
				super.flush();
				this.b.reset();
			}catch(Exception exc){
				throw new IOException(exc.getMessage());
			}
		}
		return;
	}
	@Override public void write(byte[]b)
	throws IOException{
		this.b.write(b);
		return;
	}
	@Override public void write(int b)
	throws IOException{
		this.b.write(b);
		return;
	}
	@Override public void write(byte[]b,int off,int len)
	throws IOException{
		this.b.write(b,off,len);
		return;
	}
	// --- Variablen --- //
	private ByteArrayOutputStream b=new ByteArrayOutputStream(1024);
	private Cipher cipher;
	// --- Aufzaehlungen --- //
	
}
Ich habe deine Lösung schon angeschaut, doch wo ist bei mir das Problem?
Die Methode doFinal(byte[]b) encrypted (in diesem Fall) doch alle restlichen Bytes mit, oder?

Bei mir wird in die Datei "./Test.txt" nichts geschrieben (0 Bytes).

Danke im Voraus!

Mit freundlichen Grüßen
Seikuassi
 

Seikuassi

Aktives Mitglied
Ich nochmal.

Also, Problem gelöst. Man muss nur den CipherOutputStream überschreiben:
Java:
class CipherOutputStream extends javax.crypto.CipherOutputStream{
	public CipherOutputStream(OutputStream out,Cipher cipher){
		super(out,cipher);
		this.cipher=cipher;
	}
	// --- Klassen --- //
	
	// --- Methoden --- //
	@Override public void flush()
	throws IOException{
		try{
			this.cipher.doFinal();
		}catch(Exception exc){
			throw new IOException(exc.getMessage());
		}
		super.flush();
		return;
	}
	// --- Variablen --- //
	private Cipher cipher;
	// --- Aufzaehlungen --- //
	
}
Dann funktioniert folgender Code:
Java:
Cipher cipher=Cipher.getInstance(algor);

cipher.init(Cipher.ENCRYPT_MODE,new SecretKeySpec(pwd,"AES"),new IvParameterSpec(iv));
try(CipherOutputStream out=new CipherOutputStream(new FileOutputStream("./Test.txt"),cipher)){
	out.write("Test".getBytes(StandardCharsets.ISO_8859_1));
}
cipher=Cipher.getInstance(algor);
cipher.init(Cipher.DECRYPT_MODE,new SecretKeySpec(pwd,"AES"),new IvParameterSpec(iv));
try(ByteArrayOutputStream b=new ByteArrayOutputStream();
CipherInputStream in=new CipherInputStream(new FileInputStream("./Test.txt"),cipher)){
	in.transferTo(b);
	System.out.println(b.toString("ISO-8859-1"));
}
Ausgabe:
Code:
Test
Dateiausgabe (Test.txt):
Code:
1I“~s1j&^gÎ@†*

Danke nochmal und schönen Abend noch!
 

Seikuassi

Aktives Mitglied
Ups, kleiner Fehler. Funktioniert doch nicht...:oops:
Die Lösung oben funktioniert nur, weil close() aufgerufen wird.

Wo ist jetzt das Problem in meiner Lösung (Beitrag #3)?

Danke im Voraus!
 

Tobse

Top Contributor
Ups, kleiner Fehler. Funktioniert doch nicht...:oops:
Die Lösung oben funktioniert nur, weil close() aufgerufen wird.

Wo ist jetzt das Problem in meiner Lösung (Beitrag #3)?

Danke im Voraus!

Exakt das gleiche habe ich damals auch getan, um das Problem mit close() zu umgehen. Und auch bei mir hat es nicht gefruchtet.
Ich kann dir leider nicht sagen, woran das liegt; es gibt keinen logischen grund dafür (die Kryptographie erlaubt es dank Padding voll und ganz, unvollständige Blöcke zu verarbeiten).
 
Zuletzt bearbeitet:

Seikuassi

Aktives Mitglied
Hallo nochmal,

im Endeffekt geht es darum, Daten zu verschlüsseln und danach per Socket zu versenden.
Es gibt ja die SSLSocket-Klasse (javax.net.ssl.SSLSocket) um eben dies zu tun. Allerdings bin ich dort noch nicht so richtig gut drin.
Ich möchte Daten verschlüsseln, ohne dabei ein Zertifikat bzw. eine externe Datei zu speichern/verwenden.

Ich möchte im Prinzip mit AES 128 Bit verschlüsseln. Der Schlüssel soll mit einem Byte-Array (bsp. 16 Byte) initialisiert werden, den der Programmierer im Programm selbst bestimmen kann.
Java:
ServerSocketFactory sf=SSLServerSocketFactory.getDefault();
final SSLServerSocket socket=(SSLServerSocket)sf.createServerSocket(1024);

System.out.println(Arrays.toString(socket.getSupportedCipherSuites()));
System.out.println(Arrays.toString(socket.getEnabledCipherSuites()));
socket.setEnabledCipherSuites(new String[] {"SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA"});
new Thread(){
	public void run() {
		try{
			Socket client=socket.accept();
			
			client.getOutputStream().write("Hello World\n".getBytes("ASCII"));
		client.close();
	}catch (IOException ioe){}
}
}.start();
Thread.sleep(2000);
SSLSocket client=(SSLSocket) SSLSocketFactory.getDefault().createSocket("localhost", 1024);
client.setEnabledCipherSuites(new String[] {"SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA"});
InputStream in=client.getInputStream();
byte[] data=new byte[1024];
int len=in.read(data);
System.out.println(new String(data, 0, len));
Hier scheint alles zu klappen - das Programm funktioniert. Wie kann ich allerdings die Verschlüsselung wählen (DES,AES,RSA etc.)? "_anon_" sagt ja nur aus, dass kein Zertifikat benötigt wird.
Wonach verschlüsselt jetzt das Programm??

Danke im Voraus!

Mit freundlichen Grüßen

Seikuassi
 

Tobse

Top Contributor
Es steht ja dort: SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA

SSL: SSL Protokoll
DH: Schlüsselaustausch über das Diffie-Hellman Protokoll
DES40_CBC: DES im CBC-Modus, Schlüsselgröße 40bit
SHA: Ein Algorithmus aus der SHA-Gruppe für den MAC.

Das ist nicht AES und es verwendet auch nicht den Schlüssel, den der Programmieren festlegt. Der Algorithmus, den du da angegeben hast, kann man sehr leicht über Cryptoanalyse brechen.
 

Seikuassi

Aktives Mitglied
Hallo Tobse,

danke für die schnelle Antwort.
Wenn ich das also richtig verstanden habe, dann werden Zufallschlüssel erzeugt, die eben mit dem Diffie-Hellman-Protokoll beiden Parteien bekannt gemacht wird bzw. zur Verfügung gestellt werden.
Ich muss mich also nicht um die Schlüsselgenerierung kümmern, richtig?

Und wie müsste jetzt dann ein AES oder RSA-"String" aussehen? Gibt es da eine Referenz im Internet (Link)?

Danke nochmal!
 

Tobse

Top Contributor
Wenn ich das also richtig verstanden habe, dann werden Zufallschlüssel erzeugt, die eben mit dem Diffie-Hellman-Protokoll beiden Parteien bekannt gemacht wird bzw. zur Verfügung gestellt werden.
Im Grunde ja. Beide Parteien einigen sich auf einen zufälligen Schlüssel.

Ich muss mich also nicht um die Schlüsselgenerierung kümmern, richtig?
Nicht direkt. Aber ohne Authentifizierung (über ein RSA oder DSA Zertifikat) ist die Verbindung schwer anfällig für eine MITM Attacke.

Und wie müsste jetzt dann ein AES oder RSA-"String" aussehen? Gibt es da eine Referenz im Internet (Link)?
Das weiss ich jetzt nicht auswendig. Aber die Doku zum SSLSocket dürfe da aufschlussreich sein.
 

Seikuassi

Aktives Mitglied
Hallo nochmal,

habe ein Problem mit dem SSLSocket.
Java:
public void connect(String IP){
	try{
		this.close(); // schliesst Socket, falls dieser noch nicht geschlossen wurde
		if(this.type==TYPE.CLIENT){ // wenn ein Client erstellt werden soll
			this.socket=(SSLSocket)SSLSocketFactory.getDefault().createSocket();
			{ // Client konfigurieren
				this.socket.setReceiveBufferSize(this.bufferSize);
				this.socket.setSendBufferSize(this.bufferSize);
				this.socket.setSoTimeout(this.timeout);
				this.socket.setEnabledCipherSuites(new String[] {"TLS_DH_anon_WITH_AES_128_CBC_SHA256"});
			}
			this.socket.connect(new InetSocketAddress(IP,this.port),this.timeout); // mit Server verbinden
			this.in=new DataInputStream(new BufferedInputStream(this.socket.getInputStream()));
			this.out=new DataOutputStream(new BufferedOutputStream(this.socket.getOutputStream()));
			this.isConnected=true;
			classes.Network.changeStatusIcon(true); // Status aendern
		}else{ // wenn ein Server erstellt werden soll
			this.server=(SSLServerSocket)SSLServerSocketFactory.getDefault().createServerSocket(this.port);
			{ // Server konfigurieren
				this.server.setSoTimeout(this.timeout);
				this.server.setEnabledCipherSuites(new String[] {"TLS_DH_anon_WITH_AES_128_CBC_SHA256"});
			}
			this.socket=(SSLSocket)this.server.accept(); // mit Client verbinden
			this.in=new DataInputStream(new BufferedInputStream(this.socket.getInputStream()));
			this.out=new DataOutputStream(new BufferedOutputStream(this.socket.getOutputStream()));
			this.isConnected=true;
			classes.Network.changeStatusIcon(true); // Status aendern
		}
		this.files=new ArrayList<>(5);
		this.rec=new Receiver();
		this.tran=new Transmitter();
		this.rec.start(); // Receiver starten
		this.tran.start(); // Transmitter starten
	}catch(Exception exc){
		exc.printStackTrace();
		this.isConnected=false;
	}finally{
		if(this.server!=null){
			try{
				this.server.close();
			}catch(IOException exc){}
			this.server=null;
		}
	}
	return;
}
Wenn ich jetzt per
Java:
out.writeUTF("EXIT");
out.flush();
eine Nachricht schicke, dann kommt bei der anderen Partei nichts an (die per readUTF() Nachrichten abfangen sollte).
Verwende ich allerdings einen normalen Socket bzw. ServerSocket, dann funktioniert das ganze.

Ist etwa SSLSocket auch an einer Blockgröße gebunden?

Danke im Voraus!

Mit freundlichen Grüßen
Seikuassi
 

Seikuassi

Aktives Mitglied
Hallo Tobse,

mein Receiver (Thread wird im Post #11 in der Zeile 33 gestartet) prueft in einer while-Schleife mithilfe von available(), ob neue Bytes anliegen. Danach sollte der Befehl mithilfe von readUTF() eigentlich ausgelesen werden.
Allerdings habe ich schon in anderen Foren gesehen, dass available() bei einem SSLSocket immer 0 zurückgibt (stimmt - habe es überprüft). Und readUTF() wie schon gesagt empfängt auch nichts...

So langsam bin ich ratlos, was das sichere Versenden von Daten über Sockets mithilfe von Java angeht...:(
 

Seikuassi

Aktives Mitglied
Hallo nochmal,

habe jetzt den DataOutputStream erweitert. Mit ihm versuche ich alle "Befehle" (EXIT,FILE,ABORT etc.) zu verschicken.
Java:
public class CipherDataOutputStream extends DataOutputStream{
	public CipherDataOutputStream(OutputStream out,byte[]pwd)
	throws Exception{
		super(out);
		this.cipher=Cipher.getInstance("AES/CBC/PKCS5Padding");
		this.cipher.init(Cipher.DECRYPT_MODE,new SecretKeySpec(pwd,"AES"),new IvParameterSpec(new byte[]{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}));
	}
	// --- Klassen --- //
	
	// --- Methoden --- //
	/** Sendet Daten und encrypted diese vorher. **/
	public void encrypt(byte[]b)
	throws BadPaddingException,IllegalBlockSizeException,IOException{
		this.writeInt(this.cipher.getOutputSize(b.length));
		this.write(this.cipher.doFinal(b));
		return;
	}
	/** Sendet Daten aus einem InputStream und encrypted diese vorher. **/
	public void encrypt(InputStream in)
	throws BadPaddingException,IllegalBlockSizeException,IOException{
		int size=this.cipher.getOutputSize(in.available());
		
		this.writeInt(size);
		try(ByteArrayOutputStream b=new ByteArrayOutputStream(size)){
			in.transferTo(b);
			this.write(this.cipher.doFinal(b.toByteArray())); // <-- Fehler !
		}
		return;
	}
	// --- Variablen --- //
	private Cipher cipher;
	// --- Aufzaehlungen  --- //
	
}
Hier ist die dazugehörige CipherDataInputStream-Klasse:
Java:
public class CipherDataInputStream extends DataInputStream{
	public CipherDataInputStream(InputStream in,byte[]pwd)
	throws Exception{
		super(in);
		this.cipher=Cipher.getInstance("AES/CBC/PKCS5Padding");
		this.cipher.init(Cipher.ENCRYPT_MODE,new SecretKeySpec(pwd,"AES"),new IvParameterSpec(new byte[]{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}));
	}
	// --- Klassen --- //
	
	// --- Methoden --- //
	/** Empfaengt encryptete Daten. **/
	public byte[]decrypt()
	throws BadPaddingException,IllegalBlockSizeException,IOException{
		try(ByteArrayOutputStream b=new ByteArrayOutputStream()){
			for(int i=0;i<this.readInt();i++){
				b.write(this.read());
			}
			return this.cipher.doFinal(b.toByteArray());
		}
	}
	/** Empfaengt encryptete Daten und schreibt diese in den OutputStream. **/
	public void decrypt(OutputStream out)
	throws BadPaddingException,IllegalBlockSizeException,IOException{
		try(ByteArrayOutputStream b=new ByteArrayOutputStream()){
			for(int i=0;i<this.readInt();i++){
				b.write(this.read());
			}
			out.write(this.cipher.doFinal(b.toByteArray()));
			return;
		}
	}
	// --- Variablen --- //
	private Cipher cipher;
	// --- Aufzaehlungen  --- //
	
}
Beim Versenden einer Datei erhalte ich beim encrypten folgenden Fehler:
Code:
javax.crypto.IllegalBlockSizeException: Input length must be multiple of 16 when decrypting with padded cipher
	at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:922)
	at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:833)
	at com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:436)
	at javax.crypto.Cipher.doFinal(Cipher.java:2165)
	at classes.network.security.CipherDataOutputStream.encrypt(CipherDataOutputStream.java:48)
	at classes.network.NetworkManager$Transmitter.run(NetworkManager.java:139)
Ich dachte das Padding "füllt" alle restlichen Bytes auf (wie bei Base64)?
Wo liegt jetzt der Fehler?

Danke im Voraus!

Mit freundlichen Grüßen
Seikuassi
 

Tobse

Top Contributor
Du hast den Cipher als DECRYPT_MODE initialisiert. Fürs entschlüsseln brauchst du natürlich vollständige, 16-byte Blöcke.
 
Zuletzt bearbeitet:

Seikuassi

Aktives Mitglied
:oops: peinlicher Fehler. Okay, jetzt klappt alles!
Ich versuche evtl. später nochmal den kompletten Code vom CipherDataInputStream und CipherDataOutputStream zu schicken.
 

Seikuassi

Aktives Mitglied
CipherDataInputStream:
Java:
public class CipherDataInputStream extends DataInputStream{
	public CipherDataInputStream(InputStream in,byte[]pwd)
	throws InvalidAlgorithmParameterException,InvalidKeyException,NoSuchAlgorithmException,NoSuchPaddingException{
		super(in);
		this.cipher=Cipher.getInstance("AES/CBC/PKCS5Padding");
		this.cipher.init(Cipher.DECRYPT_MODE,new SecretKeySpec(pwd,"AES"),new IvParameterSpec(new byte[]{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}));
	}
	// --- Klassen --- //
	
	// --- Methoden --- //
	/** Empfaengt encryptete Daten. **/
	public byte[]decrypt()
	throws BadPaddingException,IllegalBlockSizeException,IOException{
		try(ByteArrayOutputStream b=new ByteArrayOutputStream()){
			for(int i=0;i<this.readInt();i++){
				b.write(this.read());
			}
			return this.cipher.doFinal(b.toByteArray());
		}
	}
	/** Empfaengt encryptete Daten und schreibt diese in den OutputStream. **/
	public void decrypt(OutputStream out)
	throws BadPaddingException,IllegalBlockSizeException,IOException{
		try(ByteArrayOutputStream b=new ByteArrayOutputStream()){
			for(int i=0;i<this.readInt();i++){
				b.write(this.read());
			}
			out.write(this.cipher.doFinal(b.toByteArray()));
			out.flush();
			return;
		}
	}
	/** Liest eine Zeichenkette und entschluesselt diese vorher. **/
	public String readDecryptedUTF()
	throws IOException{
		try{
			return new String(this.cipher.doFinal(super.readUTF().getBytes(StandardCharsets.ISO_8859_1)),StandardCharsets.ISO_8859_1);
		}catch(Exception exc){
			throw new IOException(exc.getMessage());
		}
	}
	// --- Variablen --- //
	private Cipher cipher;
	// --- Aufzaehlungen  --- //
	
}
CipherDataOutputStream:
Java:
public class CipherDataOutputStream extends DataOutputStream{
	public CipherDataOutputStream(OutputStream out,byte[]pwd)
	throws InvalidAlgorithmParameterException,InvalidKeyException,NoSuchAlgorithmException,NoSuchPaddingException{
		super(out);
		this.cipher=Cipher.getInstance("AES/CBC/PKCS5Padding");
		this.cipher.init(Cipher.ENCRYPT_MODE,new SecretKeySpec(pwd,"AES"),new IvParameterSpec(new byte[]{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}));
	}
	// --- Klassen --- //
	
	// --- Methoden --- //
	/** Sendet Daten und encrypted diese vorher. **/
	public void encrypt(byte[]b)
	throws BadPaddingException,IllegalBlockSizeException,IOException{
		this.writeInt(this.cipher.getOutputSize(b.length));
		this.write(this.cipher.doFinal(b));
		this.flush();
		return;
	}
	/** Sendet Daten aus einem InputStream und encrypted diese vorher. **/
	public void encrypt(InputStream in)
	throws BadPaddingException,IllegalBlockSizeException,IOException{
		int size=this.cipher.getOutputSize(in.available());
		
		this.writeInt(size);
		try(ByteArrayOutputStream b=new ByteArrayOutputStream(size)){
			in.transferTo(b);
			this.write(this.cipher.doFinal(b.toByteArray()));
			this.flush();
		}
		return;
	}
	/** Schreibt eine Zeichenkette und verschluesselt diese vorher. **/
	public void writeEncryptedUTF(String str)
	throws IOException{
		try{
			super.writeUTF(new String(this.cipher.doFinal(str.getBytes(StandardCharsets.ISO_8859_1)),StandardCharsets.ISO_8859_1));
			return;
		}catch(Exception exc){
			throw new IOException(exc.getMessage());
		}
	}
	// --- Variablen --- //
	private Cipher cipher;
	// --- Aufzaehlungen  --- //
	
}
Danke nochmal!
 

Seikuassi

Aktives Mitglied
Und hallo nochmal,

ich hoffe das wird hier keine Never-ending-story :D.
Ich habe jetzt doch versucht alle Primitiven zu verwenden, die der DataInput-/DataOutputStream verarbeiten kann.

CipherDataInputStream:
Java:
public class CipherDataInputStream implements AutoCloseable,DataInput{
	public CipherDataInputStream(InputStream in,byte[]pwd)
	throws InvalidAlgorithmParameterException,InvalidKeyException,NoSuchAlgorithmException,NoSuchPaddingException{
		this.in=in;
		this.cipher=Cipher.getInstance("AES/CBC/PKCS5Padding");
		this.cipher.init(Cipher.DECRYPT_MODE,new SecretKeySpec(pwd,"AES"),new IvParameterSpec(new byte[]{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}));
	}
	// --- Klassen --- //
	
	// --- Methoden --- //
	/** Gibt die Anzahl der zu lesenden Bytes an. **/
	public int available()
	throws IOException{
		return this.in.available();
	}
	/** Schliesst den Stream. **/
	@Override public void close()
	throws IOException{
		this.in.close();
		return;
	}
	/** Liest Bytes, decrypted diese vorher und schreibt diese in den OutputStream. **/
	public void read(OutputStream out)
	throws IOException{
		for(int count=this.readInt();count>0;count--){
			out.write(this.in.read());
		}
		out.flush();
		return;
	}
	/** Liest ein Boolean und decrypted diesen vorher. **/
	@Override public boolean readBoolean()
	throws IOException{
		byte[]b=new byte[this.cipher.getBlockSize()];
		
		for(int i=0;i<b.length;i++){
			b[i]=(byte)this.in.read();
		}
		try(DataInputStream in=new DataInputStream(new ByteArrayInputStream(this.cipher.doFinal(b)))){
			return in.readBoolean();
		}catch(Exception exc){
			throw new IOException(exc.getMessage());
		}
	}
	/** Liest ein Byte und entschluesselt diesen vorher. **/
	@Override public byte readByte()
	throws IOException{
		byte[]b=new byte[this.cipher.getBlockSize()];
		
		for(int i=0;i<b.length;i++){
			b[i]=(byte)this.in.read();
		}
		try(DataInputStream in=new DataInputStream(new ByteArrayInputStream(this.cipher.doFinal(b)))){
			return in.readByte();
		}catch(Exception exc){
			throw new IOException(exc.getMessage());
		}
	}
	/** Liest einen Short und entschluesselt diesen vorher. **/
	@Override public char readChar()
	throws IOException{
		byte[]b=new byte[Character.BYTES*this.cipher.getBlockSize()];
		
		for(int i=0;i<b.length;i++){
			b[i]=(byte)this.in.read();
		}
		try(DataInputStream in=new DataInputStream(new ByteArrayInputStream(this.cipher.doFinal(b)))){
			return in.readChar();
		}catch(Exception exc){
			throw new IOException(exc.getMessage());
		}
	}
	/** Liest einen Double und entschluesselt diesen vorher. **/
	@Override public double readDouble()
	throws IOException{
		byte[]b=new byte[Double.BYTES*this.cipher.getBlockSize()];
		
		for(int i=0;i<b.length;i++){
			b[i]=(byte)this.in.read();
		}
		try(DataInputStream in=new DataInputStream(new ByteArrayInputStream(this.cipher.doFinal(b)))){
			return in.readDouble();
		}catch(Exception exc){
			throw new IOException(exc.getMessage());
		}
	}
	/** Liest einen Float und verschluesselt diesen vorher. **/
	@Override public float readFloat()
	throws IOException{
		byte[]b=new byte[Float.BYTES*this.cipher.getBlockSize()];
		
		for(int i=0;i<b.length;i++){
			b[i]=(byte)this.in.read();
		}
		try(DataInputStream in=new DataInputStream(new ByteArrayInputStream(this.cipher.doFinal(b)))){
			return in.readFloat();
		}catch(Exception exc){
			throw new IOException(exc.getMessage());
		}
	}
	@Override public void readFully(byte[]b)
	throws UnsupportedOperationException{
		throw new UnsupportedOperationException("readFully(byte[]) is not supported.");
	}
	@Override public void readFully(byte[]b,int off,int len)
	throws UnsupportedOperationException{
		throw new UnsupportedOperationException("readFully(byte[],int,int) is not supported.");
	}
	/** Liest einen Integer und entschluesselt diesen vorher. **/
	@Override public int readInt()
	throws IOException{
		byte[]b=new byte[Integer.BYTES*this.cipher.getBlockSize()];
		
		for(int i=0;i<b.length;i++){
			b[i]=(byte)this.in.read();
		}
		try(DataInputStream in=new DataInputStream(new ByteArrayInputStream(this.cipher.doFinal(b)))){
			return in.readInt();
		}catch(Exception exc){
			throw new IOException(exc.getMessage());
		}
	}
	@Override public String readLine()
	throws UnsupportedOperationException{
		throw new UnsupportedOperationException("readLine() is not supported.");
	}
	/** Liest einen Long und entschluesselt diesen vorher. **/
	@Override public long readLong()
	throws IOException{
		byte[]b=new byte[Long.BYTES*this.cipher.getBlockSize()];
		
		for(int i=0;i<b.length;i++){
			b[i]=(byte)this.in.read();
		}
		try(DataInputStream in=new DataInputStream(new ByteArrayInputStream(this.cipher.doFinal(b)))){
			return in.readLong();
		}catch(Exception exc){
			throw new IOException(exc.getMessage());
		}
	}
	/** Liest einen Short und entschluesselt diesen vorher. **/
	@Override public short readShort()
	throws IOException{
		byte[]b=new byte[Short.BYTES*this.cipher.getBlockSize()];
		
		for(int i=0;i<b.length;i++){
			b[i]=(byte)this.in.read();
		}
		try(DataInputStream in=new DataInputStream(new ByteArrayInputStream(this.cipher.doFinal(b)))){
			return in.readShort();
		}catch(Exception exc){
			throw new IOException(exc.getMessage());
		}
	}
	/** Liest ein vorzeichenloses Byte und entschluesselt dieses vorher. **/
	@Override public int readUnsignedByte()
	throws IOException{
		byte[]b=new byte[Integer.BYTES*this.cipher.getBlockSize()];
		
		for(int i=0;i<b.length;i++){
			b[i]=(byte)this.in.read();
		}
		try(DataInputStream in=new DataInputStream(new ByteArrayInputStream(this.cipher.doFinal(b)))){
			return in.readUnsignedByte();
		}catch(Exception exc){
			throw new IOException(exc.getMessage());
		}
	}
	/** Liest ein vorzeichenloses Short und entschluesselt dieses vorher. **/
	@Override public int readUnsignedShort()
	throws IOException{
		byte[]b=new byte[Integer.BYTES*this.cipher.getBlockSize()];
		
		for(int i=0;i<b.length;i++){
			b[i]=(byte)this.in.read();
		}
		try(DataInputStream in=new DataInputStream(new ByteArrayInputStream(this.cipher.doFinal(b)))){
			return in.readUnsignedShort();
		}catch(Exception exc){
			throw new IOException(exc.getMessage());
		}
	}
	/** Liest eine Zeichenkette und entschluesselt diese vorher. **/
	@Override public String readUTF()
	throws IOException{
		try{
			byte[]b=new byte[this.readShort()*this.cipher.getBlockSize()];
			
			for(int i=0;i<b.length;i++){
				b[i]=(byte)this.in.read();
			}
			return new String(b,StandardCharsets.ISO_8859_1);
		}catch(Exception exc){
			exc.printStackTrace();
			throw new IOException(exc.getMessage());
		}
	}
	/** Ueberspringt eine Anzahl von Bytes. **/
	@Override public int skipBytes(int count)
	throws IOException{
		return(int)this.in.skip(count);
	}
	// --- Variablen --- //
	private Cipher cipher;
	private InputStream in;
	// --- Aufzaehlungen  --- //
	
}
CipherDataOutputStream:
Java:
public class CipherDataOutputStream implements AutoCloseable,DataOutput,Flushable{
	public CipherDataOutputStream(OutputStream out,byte[]pwd)
	throws InvalidAlgorithmParameterException,InvalidKeyException,NoSuchAlgorithmException,NoSuchPaddingException{
		this.out=out;
		this.cipher=Cipher.getInstance("AES/CBC/PKCS5Padding");
		this.cipher.init(Cipher.ENCRYPT_MODE,new SecretKeySpec(pwd,"AES"),new IvParameterSpec(new byte[]{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}));
	}
	// --- Klassen --- //
	
	// --- Methoden --- //
	/** Schliesst den Stream. **/
	@Override public void close()
	throws IOException{
		this.dout.close();
		this.out.flush();
		this.out.close();
		return;
	}
	/** Schreibt alle restlichen Bytes in den Stream. **/
	@Override public void flush()
	throws IOException{
		this.out.flush();
	}
	/** Sendet Daten und encrypted diese vorher. **/
	@Override public void write(byte[]b)
	throws IOException{
		try{
			this.writeInt(this.cipher.getOutputSize(b.length));
			this.out.write(this.cipher.doFinal(b));
			return;
		}catch(Exception exc){
			throw new IOException(exc.getMessage());
		}
	}
	/** Sendet ein Byte und encrypted diese vorher. **/
	@Override public void write(int b)
	throws IOException{
		this.writeByte((byte)b);
	}
	/** Sendet Daten und encrypted diese vorher. **/
	@Override public void write(byte[]b,int off,int len)
	throws IOException{
		try{
			this.writeInt(this.cipher.getOutputSize(len));
			this.out.write(this.cipher.doFinal(b,off,len));
		}catch(Exception exc){
			throw new IOException(exc.getMessage());
		}
		return;
	}
	/** Sendet Daten aus einem InputStream und encrypted diese vorher. **/
	public void write(InputStream in)
	throws IOException{
		try{
			int size=this.cipher.getOutputSize(in.available());
			
			this.writeInt(size);
			try(ByteArrayOutputStream b=new ByteArrayOutputStream(size)){
				in.transferTo(b);
				this.out.write(this.cipher.doFinal(b.toByteArray()));
			}
			this.out.flush();
		}catch(Exception exc){
			throw new IOException(exc.getMessage());
		}
		return;
	}
	/** Schreibt ein Boolean und verschluesselt diesen vorher. **/
	@Override public void writeBoolean(boolean v)
	throws IOException{
		try{
			this.dout.writeBoolean(v);
			this.out.write(this.cipher.doFinal(this.b.toByteArray()));
		}catch(Exception exc){
			throw new IOException(exc.getMessage());
		}finally{
			this.b.reset();
		}
	}
	/** Schreibt ein Byte und verschluesselt diesen vorher. **/
	@Override public void writeByte(int v)
	throws IOException{
		try{
			this.dout.writeByte(v);
			this.out.write(this.cipher.doFinal(this.b.toByteArray()));
		}catch(Exception exc){
			throw new IOException(exc.getMessage());
		}finally{
			this.b.reset();
		}
	}
	/** Schreibt Bytes und verschluesselt diese vorher. **/
	@Override public void writeBytes(String str)
	throws IOException{
		try{
			this.dout.writeBytes(str);
			this.out.write(this.cipher.doFinal(this.b.toByteArray()));
		}catch(Exception exc){
			throw new IOException(exc.getMessage());
		}finally{
			this.b.reset();
		}
	}
	/** Schreibt einen Character und verschluesselt diesen vorher. **/
	@Override public void writeChar(int v)
	throws IOException{
		try{
			this.dout.writeChar(v);
			this.out.write(this.cipher.doFinal(this.b.toByteArray()));
		}catch(Exception exc){
			throw new IOException(exc.getMessage());
		}finally{
			this.b.reset();
		}
	}
	/** Schreibt Chars und verschluesselt diese vorher. **/
	@Override public void writeChars(String str)
	throws IOException{
		try{
			this.dout.writeChars(str);
			this.out.write(this.cipher.doFinal(this.b.toByteArray()));
		}catch(Exception exc){
			throw new IOException(exc.getMessage());
		}finally{
			this.b.reset();
		}
	}
	/** Schreibt einen Double und verschluesselt diesen vorher. **/
	@Override public void writeDouble(double v)
	throws IOException{
		try{
			this.dout.writeDouble(v);
			this.out.write(this.cipher.doFinal(this.b.toByteArray()));
		}catch(Exception exc){
			throw new IOException(exc.getMessage());
		}finally{
			this.b.reset();
		}
	}
	/** Schreibt einen Float und verschluesselt diesen vorher. **/
	@Override public void writeFloat(float v)
	throws IOException{
		try{
			this.dout.writeFloat(v);
			this.out.write(this.cipher.doFinal(this.b.toByteArray()));
		}catch(Exception exc){
			throw new IOException(exc.getMessage());
		}finally{
			this.b.reset();
		}
	}
	/** Schreibt einen Integer und verschluesselt diesen vorher. **/
	@Override public void writeInt(int v)
	throws IOException{
		try{
			this.dout.writeInt(v);
			this.out.write(this.cipher.doFinal(this.b.toByteArray()));
		}catch(Exception exc){
			throw new IOException(exc.getMessage());
		}finally{
			this.b.reset();
		}
	}
	/** Schreibt einen Long und verschluesselt diesen vorher. **/
	@Override public void writeLong(long v)
	throws IOException{
		try{
			this.dout.writeLong(v);
			this.out.write(this.cipher.doFinal(this.b.toByteArray()));
		}catch(Exception exc){
			throw new IOException(exc.getMessage());
		}finally{
			this.b.reset();
		}
	}
	/** Schreibt einen Short und verschluesselt diesen vorher. **/
	@Override public void writeShort(int v)
	throws IOException{
		try{
			this.dout.writeShort(v);
			this.out.write(this.cipher.doFinal(this.b.toByteArray()));
		}catch(Exception exc){
			throw new IOException(exc.getMessage());
		}finally{
			this.b.reset();
		}
	}
	/** Schreibt eine Zeichenkette und verschluesselt diese vorher. **/
	@Override public void writeUTF(String str)
	throws IOException{
		try{
			this.writeShort(str.length());
			this.dout.writeBytes(str);
			this.out.write(this.cipher.doFinal(this.b.toByteArray()));
			return;
		}catch(Exception exc){
			throw new IOException(exc.getMessage());
		}
	}
	// --- Variablen --- //
	private ByteArrayOutputStream b=new ByteArrayOutputStream(1024);
	private Cipher cipher;
	private DataOutputStream dout=new DataOutputStream(b);
	private OutputStream out;
	// --- Aufzaehlungen  --- //
	
}
Wie man sieht, versuche ich alle Daten zu verschlüsseln.
Leider nicht ohne Probleme (wer hätte das gedacht :(). Ich erhalte bei readUTF() bzw. bei deren readShort() folgenden Fehler:
Code:
java.io.IOException: Given final block not properly padded
	at classes.network.security.CipherDataInputStream.readShort(CipherDataInputStream.java:178)
	at classes.network.security.CipherDataInputStream.readUTF(CipherDataInputStream.java:213)
	at classes.network.NetworkManager$Receiver.run(NetworkManager.java:51)
Wo liegt diesmal der Fehler?
 

Tobse

Top Contributor
Das sieht für mich stark danach aus, als ob du die Daten nicht richtig einließt. "Not properly padded" heisst so viel wie: das Padding war nach dem Entschlüsseln nicht valide (dem könnte also auch eine BadPaddingException vorrausgegangen sein).
 

Seikuassi

Aktives Mitglied
Okay, hab den Fehler gefunden - die Berechnung der Größe beim Empfangen war falsch.
Hier nun der richtige Code:

CipherDataInputStream:
Java:
public class CipherDataInputStream implements AutoCloseable,DataInput{
	public CipherDataInputStream(InputStream in,byte[]pwd)
	throws InvalidAlgorithmParameterException,InvalidKeyException,NoSuchAlgorithmException,NoSuchPaddingException{
		this.in=in;
		this.cipher=Cipher.getInstance("AES/CBC/PKCS5Padding");
		this.cipher.init(Cipher.DECRYPT_MODE,new SecretKeySpec(pwd,"AES"),new IvParameterSpec(new byte[]{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}));
	}
	// --- Klassen --- //
	
	// --- Methoden --- //
	/** Gibt die Anzahl der zu lesenden Bytes an. **/
	public int available()
	throws IOException{
		return this.in.available();
	}
	/** Schliesst den Stream. **/
	@Override public void close()
	throws IOException{
		this.in.close();
		return;
	}
	/** Liest Bytes, decrypted diese vorher und schreibt diese in den OutputStream. **/
	public void read(OutputStream out)
	throws IOException{
		byte[]b=new byte[(this.readInt()/this.cipher.getBlockSize()+1)*this.cipher.getBlockSize()];
		
		for(int i=0;i<b.length;i++){
			b[i]=(byte)this.in.read();
		}
		try{
			out.write(this.cipher.doFinal(b));
			out.flush();
		}catch(Exception exc){
			throw new IOException(exc.getMessage());
		}
		return;
	}
	/** Liest ein Boolean und decrypted diesen vorher. **/
	@Override public boolean readBoolean()
	throws IOException{
		byte[]b=new byte[(1/this.cipher.getBlockSize()+1)*this.cipher.getBlockSize()];
		
		for(int i=0;i<b.length;i++){
			b[i]=(byte)this.in.read();
		}
		try(DataInputStream in=new DataInputStream(new ByteArrayInputStream(this.cipher.doFinal(b)))){
			return in.readBoolean();
		}catch(Exception exc){
			throw new IOException(exc.getMessage());
		}
	}
	/** Liest ein Byte und entschluesselt diesen vorher. **/
	@Override public byte readByte()
	throws IOException{
		byte[]b=new byte[(1/this.cipher.getBlockSize()+1)*this.cipher.getBlockSize()];
		
		for(int i=0;i<b.length;i++){
			b[i]=(byte)this.in.read();
		}
		try(DataInputStream in=new DataInputStream(new ByteArrayInputStream(this.cipher.doFinal(b)))){
			return in.readByte();
		}catch(Exception exc){
			throw new IOException(exc.getMessage());
		}
	}
	/** Liest einen Short und entschluesselt diesen vorher. **/
	@Override public char readChar()
	throws IOException{
		byte[]b=new byte[(Character.BYTES/this.cipher.getBlockSize()+1)*this.cipher.getBlockSize()];
		
		for(int i=0;i<b.length;i++){
			b[i]=(byte)this.in.read();
		}
		try(DataInputStream in=new DataInputStream(new ByteArrayInputStream(this.cipher.doFinal(b)))){
			return in.readChar();
		}catch(Exception exc){
			throw new IOException(exc.getMessage());
		}
	}
	/** Liest einen Double und entschluesselt diesen vorher. **/
	@Override public double readDouble()
	throws IOException{
		byte[]b=new byte[(Double.BYTES/this.cipher.getBlockSize()+1)*this.cipher.getBlockSize()];
		
		for(int i=0;i<b.length;i++){
			b[i]=(byte)this.in.read();
		}
		try(DataInputStream in=new DataInputStream(new ByteArrayInputStream(this.cipher.doFinal(b)))){
			return in.readDouble();
		}catch(Exception exc){
			throw new IOException(exc.getMessage());
		}
	}
	/** Liest einen Float und verschluesselt diesen vorher. **/
	@Override public float readFloat()
	throws IOException{
		byte[]b=new byte[(Float.BYTES/this.cipher.getBlockSize()+1)*this.cipher.getBlockSize()];
		
		for(int i=0;i<b.length;i++){
			b[i]=(byte)this.in.read();
		}
		try(DataInputStream in=new DataInputStream(new ByteArrayInputStream(this.cipher.doFinal(b)))){
			return in.readFloat();
		}catch(Exception exc){
			throw new IOException(exc.getMessage());
		}
	}
	@Override public void readFully(byte[]b)
	throws UnsupportedOperationException{
		throw new UnsupportedOperationException("readFully(byte[]) is not supported.");
	}
	@Override public void readFully(byte[]b,int off,int len)
	throws UnsupportedOperationException{
		throw new UnsupportedOperationException("readFully(byte[],int,int) is not supported.");
	}
	/** Liest einen Integer und entschluesselt diesen vorher. **/
	@Override public int readInt()
	throws IOException{
		byte[]b=new byte[(Integer.BYTES/this.cipher.getBlockSize()+1)*this.cipher.getBlockSize()];
		
		for(int i=0;i<b.length;i++){
			b[i]=(byte)this.in.read();
		}
		try(DataInputStream in=new DataInputStream(new ByteArrayInputStream(this.cipher.doFinal(b)))){
			return in.readInt();
		}catch(Exception exc){
			throw new IOException(exc.getMessage());
		}
	}
	@Override public String readLine()
	throws UnsupportedOperationException{
		throw new UnsupportedOperationException("readLine() is not supported.");
	}
	/** Liest einen Long und entschluesselt diesen vorher. **/
	@Override public long readLong()
	throws IOException{
		byte[]b=new byte[(Long.BYTES/this.cipher.getBlockSize()+1)*this.cipher.getBlockSize()];
		
		for(int i=0;i<b.length;i++){
			b[i]=(byte)this.in.read();
		}
		try(DataInputStream in=new DataInputStream(new ByteArrayInputStream(this.cipher.doFinal(b)))){
			return in.readLong();
		}catch(Exception exc){
			throw new IOException(exc.getMessage());
		}
	}
	/** Liest einen Short und entschluesselt diesen vorher. **/
	@Override public short readShort()
	throws IOException{
		byte[]b=new byte[(Short.BYTES/this.cipher.getBlockSize()+1)*this.cipher.getBlockSize()];
		
		System.out.println("readShort():"+b.length);
		for(int i=0;i<b.length;i++){
			b[i]=(byte)this.in.read();
		}
		try(DataInputStream in=new DataInputStream(new ByteArrayInputStream(this.cipher.doFinal(b)))){
			return in.readShort();
		}catch(Exception exc){
			throw new IOException(exc.getMessage());
		}
	}
	/** Liest ein vorzeichenloses Byte und entschluesselt dieses vorher. **/
	@Override public int readUnsignedByte()
	throws IOException{
		byte[]b=new byte[(Integer.BYTES/this.cipher.getBlockSize()+1)*this.cipher.getBlockSize()];
		
		for(int i=0;i<b.length;i++){
			b[i]=(byte)this.in.read();
		}
		try(DataInputStream in=new DataInputStream(new ByteArrayInputStream(this.cipher.doFinal(b)))){
			return in.readUnsignedByte();
		}catch(Exception exc){
			throw new IOException(exc.getMessage());
		}
	}
	/** Liest ein vorzeichenloses Short und entschluesselt dieses vorher. **/
	@Override public int readUnsignedShort()
	throws IOException{
		byte[]b=new byte[(Integer.BYTES/this.cipher.getBlockSize()+1)*this.cipher.getBlockSize()];
		
		for(int i=0;i<b.length;i++){
			b[i]=(byte)this.in.read();
		}
		try(DataInputStream in=new DataInputStream(new ByteArrayInputStream(this.cipher.doFinal(b)))){
			return in.readUnsignedShort();
		}catch(Exception exc){
			exc.printStackTrace();
			throw new IOException(exc.getMessage());
		}
	}
	/** Liest eine Zeichenkette und entschluesselt diese vorher. **/
	@Override public String readUTF()
	throws IOException{
		try{
			byte[]b=new byte[(this.readShort()/this.cipher.getBlockSize()+1)*this.cipher.getBlockSize()];
			
			System.out.println("readUTF():"+b.length);
			for(int i=0;i<b.length;i++){
				b[i]=(byte)this.in.read();
			}
			System.out.println(new String(this.cipher.doFinal(b),StandardCharsets.ISO_8859_1));
			return new String(this.cipher.doFinal(b),StandardCharsets.ISO_8859_1);
		}catch(Exception exc){
			exc.printStackTrace();
			throw new IOException(exc.getMessage());
		}
	}
	/** Ueberspringt eine Anzahl von Bytes. **/
	@Override public int skipBytes(int count)
	throws IOException{
		return(int)this.in.skip(count);
	}
	// --- Variablen --- //
	private Cipher cipher;
	private InputStream in;
	// --- Aufzaehlungen  --- //
	
}
CipherDataOutputStream:
Java:
public class CipherDataOutputStream implements AutoCloseable,DataOutput,Flushable{
	public CipherDataOutputStream(OutputStream out,byte[]pwd)
	throws InvalidAlgorithmParameterException,InvalidKeyException,NoSuchAlgorithmException,NoSuchPaddingException{
		this.out=out;
		this.cipher=Cipher.getInstance("AES/CBC/PKCS5Padding");
		this.cipher.init(Cipher.ENCRYPT_MODE,new SecretKeySpec(pwd,"AES"),new IvParameterSpec(new byte[]{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}));
	}
	// --- Klassen --- //
	
	// --- Methoden --- //
	/** Schliesst den Stream. **/
	@Override public void close()
	throws IOException{
		this.dout.close();
		this.out.flush();
		this.out.close();
		return;
	}
	/** Schreibt alle restlichen Bytes in den Stream. **/
	@Override public void flush()
	throws IOException{
		this.out.flush();
	}
	/** Sendet Daten und encrypted diese vorher. **/
	@Override public void write(byte[]b)
	throws IOException{
		try{
			this.writeInt(b.length);
			this.out.write(this.cipher.doFinal(b));
			return;
		}catch(Exception exc){
			throw new IOException(exc.getMessage());
		}
	}
	/** Sendet ein Byte und encrypted diese vorher. **/
	@Override public void write(int b)
	throws IOException{
		this.writeByte((byte)b);
	}
	/** Sendet Daten und encrypted diese vorher. **/
	@Override public void write(byte[]b,int off,int len)
	throws IOException{
		try{
			this.writeInt(len);
			this.out.write(this.cipher.doFinal(b,off,len));
		}catch(Exception exc){
			throw new IOException(exc.getMessage());
		}
		return;
	}
	/** Sendet Daten aus einem InputStream und encrypted diese vorher. **/
	public void write(InputStream in)
	throws IOException{
		try{
			this.writeInt(in.available());
			try(ByteArrayOutputStream b=new ByteArrayOutputStream(in.available())){
				in.transferTo(b);
				this.out.write(this.cipher.doFinal(b.toByteArray()));
			}
			this.out.flush();
		}catch(Exception exc){
			throw new IOException(exc.getMessage());
		}
		return;
	}
	/** Schreibt ein Boolean und verschluesselt diesen vorher. **/
	@Override public void writeBoolean(boolean v)
	throws IOException{
		try{
			this.dout.writeBoolean(v);
			this.out.write(this.cipher.doFinal(this.b.toByteArray()));
		}catch(Exception exc){
			throw new IOException(exc.getMessage());
		}finally{
			this.b.reset();
		}
	}
	/** Schreibt ein Byte und verschluesselt diesen vorher. **/
	@Override public void writeByte(int v)
	throws IOException{
		try{
			this.dout.writeByte(v);
			this.out.write(this.cipher.doFinal(this.b.toByteArray()));
		}catch(Exception exc){
			throw new IOException(exc.getMessage());
		}finally{
			this.b.reset();
		}
	}
	/** Schreibt Bytes und verschluesselt diese vorher. **/
	@Override public void writeBytes(String str)
	throws IOException{
		try{
			this.dout.writeBytes(str);
			this.out.write(this.cipher.doFinal(this.b.toByteArray()));
		}catch(Exception exc){
			throw new IOException(exc.getMessage());
		}finally{
			this.b.reset();
		}
	}
	/** Schreibt einen Character und verschluesselt diesen vorher. **/
	@Override public void writeChar(int v)
	throws IOException{
		try{
			this.dout.writeChar(v);
			this.out.write(this.cipher.doFinal(this.b.toByteArray()));
		}catch(Exception exc){
			throw new IOException(exc.getMessage());
		}finally{
			this.b.reset();
		}
	}
	/** Schreibt Chars und verschluesselt diese vorher. **/
	@Override public void writeChars(String str)
	throws IOException{
		try{
			this.dout.writeChars(str);
			this.out.write(this.cipher.doFinal(this.b.toByteArray()));
		}catch(Exception exc){
			throw new IOException(exc.getMessage());
		}finally{
			this.b.reset();
		}
	}
	/** Schreibt einen Double und verschluesselt diesen vorher. **/
	@Override public void writeDouble(double v)
	throws IOException{
		try{
			this.dout.writeDouble(v);
			this.out.write(this.cipher.doFinal(this.b.toByteArray()));
		}catch(Exception exc){
			throw new IOException(exc.getMessage());
		}finally{
			this.b.reset();
		}
	}
	/** Schreibt einen Float und verschluesselt diesen vorher. **/
	@Override public void writeFloat(float v)
	throws IOException{
		try{
			this.dout.writeFloat(v);
			this.out.write(this.cipher.doFinal(this.b.toByteArray()));
		}catch(Exception exc){
			throw new IOException(exc.getMessage());
		}finally{
			this.b.reset();
		}
	}
	/** Schreibt einen Integer und verschluesselt diesen vorher. **/
	@Override public void writeInt(int v)
	throws IOException{
		try{
			this.dout.writeInt(v);
			this.out.write(this.cipher.doFinal(this.b.toByteArray()));
		}catch(Exception exc){
			throw new IOException(exc.getMessage());
		}finally{
			this.b.reset();
		}
	}
	/** Schreibt einen Long und verschluesselt diesen vorher. **/
	@Override public void writeLong(long v)
	throws IOException{
		try{
			this.dout.writeLong(v);
			this.out.write(this.cipher.doFinal(this.b.toByteArray()));
		}catch(Exception exc){
			throw new IOException(exc.getMessage());
		}finally{
			this.b.reset();
		}
	}
	/** Schreibt einen Short und verschluesselt diesen vorher. **/
	@Override public void writeShort(int v)
	throws IOException{
		try{
			System.out.println("writeShort:"+this.cipher.getOutputSize(Short.BYTES));
			this.dout.writeShort(v);
			this.out.write(this.cipher.doFinal(this.b.toByteArray()));
		}catch(Exception exc){
			throw new IOException(exc.getMessage());
		}finally{
			this.b.reset();
		}
	}
	/** Schreibt eine Zeichenkette und verschluesselt diese vorher. **/
	@Override public void writeUTF(String str)
	throws IOException{
		try{
			this.writeShort(str.length());
			System.out.println("writeUTF():"+this.cipher.getOutputSize(str.length()));
			this.dout.writeBytes(str);
			this.out.write(this.cipher.doFinal(this.b.toByteArray()));
			return;
		}catch(Exception exc){
			throw new IOException(exc.getMessage());
		}finally{
			this.b.reset();
		}
	}
	// --- Variablen --- //
	private ByteArrayOutputStream b=new ByteArrayOutputStream(1024);
	private Cipher cipher;
	private DataOutputStream dout=new DataOutputStream(b);
	private OutputStream out;
	// --- Aufzaehlungen  --- //
	
}
Man beachte vor allen Dingen die Zeile 26 oder 70. Dort steht die Berechnung der Größe des Byte-Arrays.

Puh, endlich geschafft...:)
 

Seikuassi

Aktives Mitglied
Puh, endlich geschafft...
Denkste, Puppe. :)

Eine kleine Änderung würde ich gerne noch machen. Es sollen nämlich statt die komplette Datei nur einzelne 8192 Byte-Blöcke encryptet (ergibt dann 8208 Bytes encryptet) und verschickt werden. Beim Empfänger werden die Blöcke dann wieder logischerweise zusammengebaut werden.

Problem: Es funktioniert nicht...:bahnhof:

Hier nochmal die überarbeitete read(OutputStream)-Methode:
Java:
/** Liest Bytes, decrypted diese vorher und schreibt diese in den OutputStream. **/
public void read(OutputStream out)
throws IOException{
	long available=(long)((this.readInt()/this.cipher.getBlockSize()+1)*this.cipher.getBlockSize());
	byte[]b=new byte[(8192/this.cipher.getBlockSize()+1)*this.cipher.getBlockSize()]; // =8208 Bytes
	int read;
	
	try{
		while(available>0L){
			read=this.in.read(b,0,Math.min((int)available,b.length));
			System.out.println(read);
			out.write(this.cipher.doFinal(b,0,read));
			available-=read;
		}
		out.flush();
	}catch(Exception exc){
		exc.printStackTrace();
		throw new IOException(exc.getMessage());
	}
	return;
}
und die write(InputStream)-Methode:
Java:
/** Sendet Daten aus einem InputStream und encrypted diese vorher. **/
public void write(InputStream in)
throws IOException{
	try{
		byte[]b=new byte[8192];
		int read;
		
		this.writeInt(in.available());
		while((read=in.read(b))!=-1){
			System.out.println(this.cipher.getOutputSize(read));
			this.out.write(this.cipher.doFinal(b,0,read));
		}
		this.out.flush();
	}catch(Exception exc){
		throw new IOException(exc.getMessage());
	}
	return;
}
Dann erhalte ich beim Sender (write(InputStream)) folgende Ausgabe:
Code:
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
7440
Und beim Empfänger:
Code:
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
8208
7728
javax.crypto.BadPaddingException: Given final block not properly padded
	at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:977)
	at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:833)
	at com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:436)
	at javax.crypto.Cipher.doFinal(Cipher.java:2223)
	at classes.network.security.CipherDataInputStream.read(CipherDataInputStream.java:59)
	at classes.network.NetworkManager$Receiver.run(NetworkManager.java:68)
Frage:Warum wird die falsche Anzahl von Bytes geliefert?

Danke im Voraus!

Mit freundlichen Grüßen
Seikuassi
 

Seikuassi

Aktives Mitglied
Hallo,

habe die Lösung gefunden.
CipherInputStream, read(OutputStream):
Java:
public void read(OutputStream out)
throws IOException{
	int available;
	byte[]b=new byte[(8192/this.cipher.getBlockSize()+1)*this.cipher.getBlockSize()];
	int read;
	
	try{
		while((available=this.readInt())!=-1){
			// this.in.read(b,0,available); <-- funktioniert nicht - wartet nicht alle Bytes ab
			for(int i=0;i<available;i++){
				b[i]=(byte)this.in.read();
			}
			out.write(this.cipher.doFinal(b,0,available));
		}
		out.flush();
	}catch(Exception exc){
		throw new IOException(exc.getMessage());
	}
	return;
}
CipherOutputStream, write(InputStream):
Java:
/** Sendet Daten aus einem InputStream und encrypted diese vorher. **/
public void write(InputStream in)
throws IOException{
	try{
		byte[]b=new byte[8192];
		int read;
		
		while((read=in.read(b))!=-1){
			this.writeInt(this.cipher.getOutputSize(read)); // Blockgroesse senden
			this.out.write(this.cipher.doFinal(b,0,read));
		}
		this.writeInt(-1); // Dateiende signalisieren
		this.out.flush();
	}catch(Exception exc){
		throw new IOException(exc.getMessage());
	}
	return;
}
In Zeile 10 bei der read-Methode funktioniert die Funktion read(byte[],int,int) nicht - er liest zu wenig Bytes ein und so kann der Cipher die Datei nicht decrypten. Warum blockiert die Methode nicht solange, bis alle Bytes (=available) eingelesen wurden?

Danke im Voraus!

Mit freundlichen Grüßen
Seikuassi
 
Zuletzt bearbeitet:

Tobse

Top Contributor
Die Methode int read(byte[] buffer, int offset, int length) ist so definiert, dass sie bis zu length bytes aus dem Stream liest und sie ab offset nach buffer schreibt. Die Rückgabe ist die Zahl der tatsächlich gelesenen Bytes.

Java SE 7 Javadoc: InputStream#read hat gesagt.:
Reads up to len bytes of data from the input stream into an array of bytes.


int available() hingegen ist so definiert, dass man sich nicht auf den Rückgabewert verlassen soll:

Java SE 7 Javadoc: InputStream#available hat gesagt.:
Returns an estimate of the number of bytes that can be read (or skipped over) [...]

Wenn du auf eine fixe anzahl an Bytes angewiesen bist (ich hatte den selben Spaß mit meinem Base64InputStream/Base64OutputStream) kommst du um einen weiteren Buffer nicht rum.
 
Zuletzt bearbeitet:
Ähnliche Java Themen
  Titel Forum Antworten Datum
T OutputStream kommt nicht an Netzwerkprogrammierung 18
L Socket Wie kann ich checken ob ein User eine Nachricht per Outputstream an den Server gesendet hat? Netzwerkprogrammierung 1
S FTP OutputStream Timed out Netzwerkprogrammierung 2
D Socket Socket OutputStream leeren? Netzwerkprogrammierung 3
C Inhalt einer .JPG Datei in einen OutputStream schreiben? Netzwerkprogrammierung 10
E Socket Outputstream - chunks groeße bestimmen. Netzwerkprogrammierung 3
T Socket ObjectIn/OutputStream Netzwerkprogrammierung 3
A Socket BufferedReader.readLine() blockiert bis ein im Socket OutputStream was gesendet wird ... Netzwerkprogrammierung 9
M Socket InputStream sendet ausgaben von OutputStream zurück Netzwerkprogrammierung 2
D Inputstream to Outputstream Netzwerkprogrammierung 3
T Outputstream Byte-Array senden Netzwerkprogrammierung 2
H Input-/OutputStream Frage Netzwerkprogrammierung 6
O Mehrere Datei per DataInput/OutputStream über Socket Netzwerkprogrammierung 12
P Probleme mit OutputStream Netzwerkprogrammierung 7
M Verbindung über Proxy// Problem mit Outputstream bei URLConn Netzwerkprogrammierung 5
PAX Outputstream von anderem Thread verwenden lassen Netzwerkprogrammierung 5
T Filter für Input UND OutputStream Netzwerkprogrammierung 4
Y Inhalt aus Textfield in OutputStream packen Netzwerkprogrammierung 4
bummerland Cookies über OutputStream senden Netzwerkprogrammierung 2
T server empfängt nur 1 Buchstaben vom String Netzwerkprogrammierung 1
J Java Server empfängt php inhalt nicht Netzwerkprogrammierung 1
D UDP Client empfängt nichts Netzwerkprogrammierung 2
L Socket Client empfängt nicht Netzwerkprogrammierung 6
P Socket Client empfängt nur eigene Text-Eingaben Netzwerkprogrammierung 30
I Chat-Client empfängt nichts vom Server Netzwerkprogrammierung 3
G TCP server empfängt falsche Werte !?!? Netzwerkprogrammierung 2
lacyuu Warum empfängt mein Stream keinen Input? Netzwerkprogrammierung 4
I Socket empfängt null Netzwerkprogrammierung 3

Ähnliche Java Themen

Neue Themen


Oben