Java Probleme bei Benutzung von AES256 Streams

Killkrog

Lt. Junior Grade
Registriert
Jan. 2006
Beiträge
354
Hallo Jungs und Mädels!

Ich beschäftige mich gerade mit Verschlüsselung und habe dazu zwei Streams geschrieben. Einmal einen OutputStream, der beim Schreiben verschlüsselt, und einen InputStream, der beim Lesen entschlüsselt.

Nun habe ich in einem kleinen Testprogram einen Klartextverschlüsselt und anschließend wieder entschlüsselt. Problem hier ist, dass zwar korrekt entschlüsselt wird, aber nicht vollständig!

Ich denke der Code sollte selbsterklärend sein, da auf das Nötigste beschränkt. Falls nicht, einfach Bescheid geben!

Danke schonmal für eure Hilfe!

AESInputStream.java
Code:
public class AESInputStream extends InputStream {

	private final InputStream stream;

	public AESInputStream(InputStream stream, byte[] aesKey) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException {
		Cipher c = Cipher.getInstance("AES");
		c.init(Cipher.DECRYPT_MODE, new SecretKeySpec(aesKey, "AES"));
		this.stream = new CipherInputStream(stream, c);
	}

	public int read() throws IOException {
		return stream.read();
	}
}

AESOutputStream .java
Code:
public class AESOutputStream extends OutputStream {

	private final OutputStream stream;

	public AESOutputStream(OutputStream stream, byte[] aesKey) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException {
		Cipher c = Cipher.getInstance("AES");
		c.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(aesKey, "AES"));
		this.stream = new CipherOutputStream(stream, c);
	}

	public void write(int b) throws IOException {
		stream.write(b);
	}
}

AesTest.java (beinhaltet main-Methode)
Code:
public class AesTest {

	public AesTest() throws Throwable {

		// generate random 256 bit key
		final byte[] aesKey = new byte[256 >> 3];
		int len = aesKey.length;
		for (int i = 0; i < len; i++) {
			aesKey[i] = (byte) ((int) (Math.random() * 256) - 128);
		}

		final String textToEncrypt = "Ich bin ein Text, der chiffriert werden soll.";

		// encrypt text
		ByteArrayOutputStream target = new ByteArrayOutputStream();
		transferData(new ByteArrayInputStream(textToEncrypt.getBytes()), new AESOutputStream(target, aesKey));
		byte[] encryptedData = target.toByteArray();
		System.out.println("Chiffrierter Text: " + new String(encryptedData));

		// decrypt text
		target = new ByteArrayOutputStream();
		transferData(new AESInputStream(new ByteArrayInputStream(encryptedData), aesKey), target);
		System.out.println("Dechiffrierter Text: " + target.toString());
		
		// Ausgabe >>> "Dechiffrierter Text: Ich bin ein Text"
	}

	public static void main(String[] args) throws Throwable {
		new AesTest();
	}

	private void transferData(InputStream is, OutputStream os) throws Throwable {
		int len, bufferSize = 1024;
		byte[] buffer = new byte[bufferSize];
		while ((len = is.read(buffer, 0, bufferSize)) != -1) {
			os.write(buffer, 0, len);
		}
		is.close();
		os.close();
	}
}
 
Selbsterklärend ja, aber nicht ohne Fragen aufzuwerfen...
Wie groß ist der chiffrierte Text denn?
 
Typische Ausgabe (nicht immer gleich wegen zufälligem Key):
Code:
Chiffrierter Text: ��S�_�$R`�s:q�Wn����uU��m_
Dechiffrierter Text: Ich bin ein Text
 
Also mir hätte es gereicht wenn du mir die Länge gesagt hättest des chiffrierten Textes... sollte ja schließlich mindestens 46 Bytes lang sein...

Bzw du könntest ja mal schauen, wieviel Daten "transferData" jeweils überträgt...
 
Du brauchst irgendeinen Algorithmus zum Einfügen von Padding-Bytes - PKCS5Padding sollte von Java unterstützt sein. Außerdem solltest du überlegen, noch einen Verschlüsselungsmodus wie CBC oder XTS zu verwenden (sollte ebenfalls beides von Java unterstützt sein), damit erhöht sich die Qualität der Verschlüsselung bei Blöcken größer als die Blocklänge des Verschlüsselungsalgorithmus. Dein "GetInstance()"-Aufruf sollte also in etwa so aussehen:
Code:
Cipher.getInstance("AES/CBC/PKCS5Padding");
 
Beim Verschlüsseln schreibt er 45 Bytes, beim Entschlüsseln 16.
 
Wird wie Simpson474 schildert ein Padding-Problem sein... also um die unvollständigen Blöcke aufzufüllen...
 
Habe nun folgende Änderungen am OutputStream vorgenommen:

Code:
Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");
c.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(aesKey, "AES"), new IvParameterSpec(Arrays.copyOf(aesKey, 16)));
this.stream = new CipherOutputStream(stream, c);

Beim InputStream analog dazu. Führt zum selben Ergebnis.
Ergänzung ()

Fehler gefunden.
close() Methode des CipherOutputStream ruft vom Cipher die doFinal() Methode auf.
Das tut meine Implementation nicht, darum fehlen Bytes.
 
Zurück
Oben