Java: Verschlüsselung mit Beispiel (Quickstart)

Java VerschlüsselungEgal ob WhatsApp, Sony Playstation Network oder Twitter alle haben ihre Schwierigkeiten mit der Sicherheit. Dabei ist es sooo einfach in Java Nachrichten oder Streams zu verschlüsseln. Um nicht jedes Mal das Rad neu zu erfinden, habe ich mir eine Klasse „EasyCrypt“ geschrieben. Diese Klasse kapselt die Ver- und Entschlüsslung von Strings und Streams. Einzig die Schlüsselerzeugung und -verwaltung muss man selbst managen.
In meinem Beispiel zeige ich die Ver- und Entschlüsselung von einem String mit AES und RSA.

 

Nur AES und nichts weiter!

Keine Lust dir die ganze Klasse anzuschauen? Hier ist ein sehr kurzer Beitrag der nur das Thema „AES“ behandelt!

 

Die Klasse „EasyCrypt“

import java.io.InputStream;
import java.io.OutputStream;
import java.security.Key;

import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.CipherOutputStream;

import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

/**
 * @author Alexander Gr
 * @see http://blog.axxg.de
 *
 */
public class EasyCrypt {
	
	private Key key = null;
	private String verfahren = null;

	/**
	 * @param Key verwendeter Schluessel
	 * @param verfahren bestimmt das verwendete Verschluesselungsverfahren "RSA", "AES", ....
	 * @throws Exception
	 */
	public EasyCrypt(Key k, String verfahren) throws Exception {
		this.key = k;
		this.verfahren = verfahren;
	}

	/**Verschluesselt einen Outputstream
	 * @param os Klartext-Outputstream
	 * @return verschluesselter Outputstream
	 * @throws Exception
	 */
	public OutputStream encryptOutputStream(OutputStream os) throws Exception {
		// integritaet pruefen
		valid();
		
		// eigentliche Nachricht mit RSA verschluesseln
		Cipher cipher = Cipher.getInstance(verfahren);
		cipher.init(Cipher.ENCRYPT_MODE, key);
		os = new CipherOutputStream(os, cipher);
		
		return os;
	}

	/** Entschluesselt einen Inputstream
	 * @param is verschluesselter Inputstream
	 * @return Klartext-Inputstream
	 * @throws Exception
	 */
	public InputStream decryptInputStream(InputStream is) throws Exception {
		// integritaet pruefen
		valid();
		
		// Daten mit AES entschluesseln
		Cipher cipher = Cipher.getInstance(verfahren);
		cipher.init(Cipher.DECRYPT_MODE, key);
		is = new CipherInputStream(is, cipher);

		return is;
	}

	/** Verschluesselt einen Text in BASE64
	 * @param text Klartext
	 * @return BASE64 String
	 * @throws Exception
	 */
	public String encrypt(String text) throws Exception {
		// integritaet pruefen
		valid();
		
		// Verschluesseln
		Cipher cipher = Cipher.getInstance(verfahren);
		cipher.init(Cipher.ENCRYPT_MODE, key);
		byte[] encrypted = cipher.doFinal(text.getBytes());

		// bytes zu Base64-String konvertieren
		BASE64Encoder myEncoder = new BASE64Encoder();
		String geheim = myEncoder.encode(encrypted);
		
		return geheim;
	}

	/** Entschluesselt einen BASE64 kodierten Text
	 * @param geheim BASE64 kodierter Text
	 * @return Klartext
	 * @throws Exception
	 */
	public String decrypt(String geheim) throws Exception {
		// integritaet pruefen
		valid();
		
		// BASE64 String zu Byte-Array
		BASE64Decoder myDecoder = new BASE64Decoder();
		byte[] crypted = myDecoder.decodeBuffer(geheim);		
		 
		// entschluesseln
		Cipher cipher = Cipher.getInstance(verfahren);
		cipher.init(Cipher.DECRYPT_MODE, key);
		byte[] cipherData = cipher.doFinal(crypted);
		return new String(cipherData);
	}
	
	//++++++++++++++++++++++++++++++
	// Validierung
	//++++++++++++++++++++++++++++++
	
	private boolean valid() throws Exception{
		if(verfahren == null){
			throw new NullPointerException("Kein Verfahren angegeben!");
		}
		
		if(key == null){
			throw new NullPointerException("Keinen Key angegeben!");
		}
		
		if(verfahren.isEmpty()){
			throw new NullPointerException("Kein Verfahren angegeben!");
		}
		
		return true;
	}
	
	//++++++++++++++++++++++++++++++
	// Getter und Setter
	//++++++++++++++++++++++++++++++
	
	public Key getKey() {
		return key;
	}

	public void setKey(Key key) {
		this.key = key;
	}

	public String getVerfahren() {
		return verfahren;
	}

	public void setVerfahren(String verfahren) {
		this.verfahren = verfahren;
	}
}

 

Die Verwendung mit AES

		try {
			// zufaelligen Schluessel erzeugen
			KeyGenerator keygen = KeyGenerator.getInstance("AES");
			keygen.init(128);
			SecretKey aesKey = keygen.generateKey();
			
			// Klasse erzeugen
			EasyCrypt ec = new EasyCrypt(aesKey, "AES");
			
			// Text ver- und entschluesseln
			String text = "Hallo AxxG-Leser";
			String geheim = ec.encrypt(text);
			String erg = ec.decrypt(geheim);
			
			System.out.println("Normaler Text:" + text);
			System.out.println("Geheimer Text:" + geheim);
			System.out.println("decrypt  Text:" + erg);		
		} catch (Exception e) {
			e.printStackTrace();
		}

Ausgabe

Normaler Text:Hallo AxxG-Leser
Geheimer Text:jEPLPYRjsY9cj+3BVv71V5GtIYTQLZXH4iRVk8JnzmM=
decrypt Text:Hallo AxxG-Leser

 

Die Verwendung mit RSA

	try {
			// zufaelligen Schluessel erzeugen
			KeyPairGenerator keygen = KeyPairGenerator.getInstance("RSA");
			keygen.initialize(1024);
			KeyPair rsaKeys = keygen.genKeyPair();
			
			// Klasse erzeugen
			EasyCrypt ecPri = new EasyCrypt(rsaKeys.getPrivate(), "RSA");
			EasyCrypt ecPub = new EasyCrypt(rsaKeys.getPublic(), "RSA");
			
			// Text ver- und entschluesseln
			String text = "Hallo AxxG-Leser";
			String geheim = ecPri.encrypt(text);
			String erg = ecPub.decrypt(geheim);
			
			System.out.println("Normaler Text:" + text);
			System.out.println("Geheimer Text:" + geheim);
			System.out.println("decrypt  Text:" + erg);		
			
			// oder 
			
			text = "Hallo AxxG-Leser";
			geheim = ecPub.encrypt(text);
			erg = ecPri.decrypt(geheim);
			
			System.out.println("Normaler Text:" + text);
			System.out.println("Geheimer Text:" + geheim);
			System.out.println("decrypt  Text:" + erg);			
		} catch (Exception e) {
			e.printStackTrace();
		}

Ausgabe

Normaler Text:Hallo AxxG-Leser
Geheimer Text:UkJIpvnaojK7Xds2i6B9hEZsql37MEnWG06ameLhN7H223dZWdLlvxJMoafBXE2klUkvumBjjIGb
RWNepHskFcsgH7L6DRHybLqJwS8QH3RVEzA/WeVI3bJWx+ADTos4Sa9E6QPFIGb2CcY4u7DKdWZh
2WqW/DkIJ13/Wn0mdLk=
decrypt Text:Hallo AxxG-Leser
Normaler Text:Hallo AxxG-Leser
Geheimer Text:W0QYY2X0GPaSNUEK7my7WEm1mzRmn29pZB8KioAhWitLcxR0yR4eOfyfnXs3whHGZ1zCGZ6ZRxgi
DcASdqn2LONDbAryyF8HzogqrsIeyDwVNpIaUTHHCeWbXPjoZ1cCQv2Ui6n2Pf9gJCStBXMirHoE
7w8BFStodwOOVzsOb34=
decrypt Text:Hallo AxxG-Leser

 

Fazit

Coole Klasse oder? Ihr könnt natürlich die Klasse weglassen oder umschreiben, aber achtet bitte auf die BASE64 Kodierung! Denn der Output von Cipher ist ein Byte-Array. Meine Meinung nach ist die Koderiung in BASE64 die eleganteste Lösung, aber ich habe auch schon andere Lösungen gesehen. Außerdem muss noch der entsprechende Schlüssel gesichert werden. Bei meinem Beispiel wird jedes Mal zufällig ein neuer Schlüssel erzeugt!

Ver- und entschlüsselt jetzt die Welt!

 

Key sichern, aber wie?

Wer nicht immer einen neuen Key erzeugen will, sollte sich unbediengt diesen Artikel von mir noch durchlesen:
Java: AES / RSA Keys lesen und schreiben (Datei)Key sichern

 

Die Quellen

 

Copyright © 2013 AxxG – Alexander Gräsel



11 Antworten : “Java: Verschlüsselung mit Beispiel (Quickstart)”

  1. Bastian sagt:

    Super Anleitung. Habe aber noch eine Frage dazu:

    Um die Verschlüsselung für den Austausch zwischen mehreren Systemen zu verwenden, muss der Key aber irgendwie gespeichert werden können. Wie kann man das realisieren?

    Gruß Bastian

  2. m sagt:

    diese Base64 Decodierung und Encodierung macht auf Android große Probleme :/ kann man die nicht irgendwie weglassen… dabei hast du alles so gut Codiert und sogar ein ausführ Beispiel gezeigt echt Schade….

  3. Lars sagt:

    Tag, ich bin ziemlich neu in Java und habe leider nicht verstanden wie ich den Key festlegen kann. Ich würde mich über eine Antwort freuen 😀

    • Hey Lars,
      Es gibt viele verschiedene Wege einen Schlüssel zu erzeugen.
      Man kann zum Beispiel einen zufälligen Schlüssel erzeugen
      // zufaelligen Schluessel erzeugen
      KeyGenerator keygen = KeyGenerator.getInstance(„AES“);
      keygen.init(128);
      SecretKey aesKey = keygen.generateKey();

      oder man kann aus einem String einen Schlüssel erzeugen:
      // Das Passwort bzw der Schluesseltext
      String keyStr = „geheimesPasswort“;
      // byte-Array erzeugen
      byte[] key = (keyStr).getBytes(„UTF-8“);
      // aus dem Array einen Hash-Wert erzeugen mit MD5 oder SHA
      MessageDigest sha = MessageDigest.getInstance(„MD5“);
      key = sha.digest(key);
      // nur die ersten 128 bit nutzen
      key = Arrays.copyOf(key, 16);
      // der fertige Schluessel
      SecretKey aesKey = new SecretKeySpec(key, „AES“);

      Ich hoffe, dass das dir weiterhilft:)

      Viele Grüße
      Alexander

  4. Pascal sagt:

    Hey,

    ich bin wirklich sehr begeistert von diesem Beitrag! Übersichtlich, knapp und leicht zu verstehen.

    Eine Sache wundert mich jedoch ….
    Bei dem RSA Verfahren wird doch mit dem PubKey verschlüsselt und mit dem PrivKey wieder entschlüsselt.

    Im Code:
    String text = „Hallo AxxG-Leser“;
    String geheim = ecPri.encrypt(text);
    String erg = ecPub.decrypt(geheim);

    Wieso funktioniert das auch?

    Gruß

    • Pascal sagt:

      Nachtrag:

      text = „Hallo AxxG-Leser“;
      geheim = ecPub.encrypt(text);
      erg = ecPri.decrypt(geheim);

      So hätte ich es auch gemacht. Aber warum geht beides?

      • Alexander sagt:

        Das ist eine gute Frage. Aber die eigentliche Frage ist doch: was ist der Unterschied zwischen den beiden Keys? Und genau das ist der Punkt, es gibt Keinen^^
        Generell funktioniert RSA ja so, dass zwei Primzahlen „a“ und „b“ ein vielfaches Produkt „c“ bilden. Der eine Schlüssel besteht aus „ac“ und der andere aus „bc“. Daher ist es egal was der Privat- und was der Public-Schlüssel ist. Nur zur Vereinfachung des Verfahrens wurden die Schlüssel sogenannt. ABER zur ENTSCHLÜSSELUNG brauchst du unbedingt den anderen Schlüssel…….

  5. Christopher Hahnen sagt:

    Hi Alexander,

    evtl. sollte man hier beim verschlüsseln eines Textes Mittels RSA noch sagen, dass die Zeichenlänge limitiert ist.

    Ich habe mir dein Tutorial durch gelesen und finde es sehr einfach zu verstehen, wenn man sich das erste mal mit dieser Materie befasst! Coole Sache!

    So und nochmal auf das oben genannte Problem zu kommen.

    Ich möchte eine Text Datei mittels RSA verschlüsseln. Allerdings ist die länge des Textes limitiert. Es hängt entsprechend davon ab, wie lang der Schlüssel ist.

    Mehr dazu habe ich auf StackOverflow gefunden.

    http://stackoverflow.com/questions/10007147/getting-a-illegalblocksizeexception-data-must-not-be-longer-than-256-bytes-when

    Dort wird empfohlen, bei einem langen Text, diesen zu erst via AES zu verschlüsseln und dann anschließend mit RSA.

    Vielen Dank für dein Tutorial =)

    Liebe Grüße
    Xearox

    • Christopher Hahnen sagt:

      Muss mich korrigieren.
      Der Text wird mit AES verschlüsselt und der AES Key mit RSA Verschlüsselt.

      Anschließend kann man den verschlüsselten AES Key mit dem verschlüsselten Text versendet werden. Der Empfänger kann nun den AES Key mit seinem RSA Key entschlüsseln und dann anschließend kann der Text Entschlüsselt werden.

      @Alexander, falls es eine einfachere und kürzere Methode geben sollte, wäre ich Dankbar, wenn du diesen als Beitrag schreiben könntest =)

      • Hey Christopher,
        danke für den Kommentar und die Ergänzung:)
        Ich werde nach meiner Masterarbeit mal einen Artikel über die Performance von Verschlüsselungsalgorithmen schreiben und dich „zitieren“:)

Trackbacks/Pingbacks

  1. Java: AES / RSA Keys lesen und schreiben (Datei) | AxxG Blog - [...] hat Bastian, ein AxxG Blog Leser, einen sehr interessanten Kommentar unter meinen Beitrag “Java: Verschlüsselung mit Beispiel (Quickstart)” hinterlassen.…

Kommentar verfassen