Die letzten Wochen ging es heiß her: Nicht nur die Temperaturen in Deutschland waren extrem, sondern auch die Enthüllung von PRISM und co. Dabei entscheidet jeder selbst, welche Dienste er nutzt und was er verschlüsseln will. Auf dem Markt gibt es viele verschiedene Technologien, wie zum Beispiel:
Heute zeige ich kurz und knapp, wie man eine AES-Verschlüsselung mit Java realisiert.
Das A und O einer symmetrischen Verschlüsselung ist der Schlüssel. Dabei gibt es viele verschiedene Wege einen Schlüssel zu generieren. Eine Möglichkeit ist das Generieren eines zufälligen Keys (Habe ich hier beschrieben und den Schlüssel in eine Datei geschrieben) oder man generiert sich einen Key aus einem String/Text.
// Das Passwort bzw der Schluesseltext String keyStr = "geheim"; // byte-Array erzeugen byte[] key = (keyStr).getBytes("UTF-8"); // aus dem Array einen Hash-Wert erzeugen mit MD5 oder SHA MessageDigest sha = MessageDigest.getInstance("SHA-256"); key = sha.digest(key); // nur die ersten 128 bit nutzen key = Arrays.copyOf(key, 16); // der fertige Schluessel SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES");
Die meiste Arbeit ist bereits getan – mit dem Schlüssel kann man nun beliebige Texte verschlüsseln:
// der zu verschl. Text String text = "Das ist der Text"; // Verschluesseln Cipher cipher = Cipher.getInstance("AES"); cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec); byte[] encrypted = cipher.doFinal(text.getBytes()); // bytes zu Base64-String konvertieren (dient der Lesbarkeit) BASE64Encoder myEncoder = new BASE64Encoder(); String geheim = myEncoder.encode(encrypted); // Ergebnis System.out.println(geheim);
Das Ganze kann man natürlich auch umdrehen:
// der verschl. Text String geheim = "jcZyVG7CAfD+FQ9gAkhbfwzRD+tpKxeq8GRh+ub/uuc="; // BASE64 String zu Byte-Array konvertieren BASE64Decoder myDecoder2 = new BASE64Decoder(); byte[] crypted2 = myDecoder2.decodeBuffer(geheim); // Entschluesseln Cipher cipher2 = Cipher.getInstance("AES"); cipher2.init(Cipher.DECRYPT_MODE, secretKeySpec); byte[] cipherData2 = cipher2.doFinal(crypted2); String erg = new String(cipherData2); // Klartext System.out.println(erg);
package axxg; import java.security.MessageDigest; import java.util.Arrays; import javax.crypto.Cipher; import javax.crypto.spec.SecretKeySpec; import sun.misc.BASE64Decoder; import sun.misc.BASE64Encoder; public class AxxGBlog { /** * @param args * @throws Exception */ public static void main(String[] args) throws Exception { // Das Passwort bzw der Schluesseltext String keyStr = "geheim"; // byte-Array erzeugen byte[] key = (keyStr).getBytes("UTF-8"); // aus dem Array einen Hash-Wert erzeugen mit MD5 oder SHA MessageDigest sha = MessageDigest.getInstance("SHA-256"); key = sha.digest(key); // nur die ersten 128 bit nutzen key = Arrays.copyOf(key, 16); // der fertige Schluessel SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES"); // der zu verschl. Text String text = "Das ist der Text"; // Verschluesseln Cipher cipher = Cipher.getInstance("AES"); cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec); byte[] encrypted = cipher.doFinal(text.getBytes()); // bytes zu Base64-String konvertieren (dient der Lesbarkeit) BASE64Encoder myEncoder = new BASE64Encoder(); String geheim = myEncoder.encode(encrypted); // Ergebnis System.out.println(geheim); // BASE64 String zu Byte-Array konvertieren BASE64Decoder myDecoder2 = new BASE64Decoder(); byte[] crypted2 = myDecoder2.decodeBuffer(geheim); // Entschluesseln Cipher cipher2 = Cipher.getInstance("AES"); cipher2.init(Cipher.DECRYPT_MODE, secretKeySpec); byte[] cipherData2 = cipher2.doFinal(crypted2); String erg = new String(cipherData2); // Klartext System.out.println(erg); } }
Copyright © 2013 AxxG – Alexander Gräsel
Die meiste Arbeite <-Rechtschreibfehler 😉
Danke für die Korrektur:)
No prob. Super Seite. Habe das ganze heute einmal ausprobiert.Bin begeistert. Frohe Weihnachten.
Vielen Dank für deinen Beitrag. Um das Beispiel aber in der Realtität verwenden zu können möchte ich eine Klasse mit zwei Funktionen encrypt und decrypt schreiben. Ich frage mich nun ob das SecretKeySpec Objekt bei beiden das Gleiche sein muss, was ja aber in der Praxis nicht unbedingt machbar ist, da vielleicht die Entschlüsselung in einem viel späteren Zeitpunkt auftritt und das SecretKeySpec Objekt nicht verfügbar ist. Kannst du mir weiterhelfen? Ich frage dich das, weil ich es eben selber schon getestet habe und da bekam ich nicht bei der Entschlüsselung nicht mehr den Ursprungstext zurück..
Toller Artikel, vielen Danke dafür :).
@Raphael.
Das SecretKeySpec Objekt wird ja mithilfe des Strings keyStr, welcher vorher in das key array umgewandelt wird, erzeugt.
Du kannst das SecretKeySpec Objekt also ruhig neu erzeugen, musst dabei nur den selben keyStr benutzen. 🙂
Viele Grüße
Hey Eric,
danke für die Beantwortung der Frage. Über Weihnachten ist die leider untergegangen:-(
Hey, echt coole Anleitung! Es hat mir sehr weitergeholfen!
Allerdings gab es bei mir Probleme mit den BASE64Encoder und -Decoder Klassen. Er hat sie nicht gefunden (kann auch sein, dass ich einen Fehler gemacht habe, ich bin in Java ziemlich neu). Für alle die aber auch darüber stolpern sollten, ich konnte aus der java.util.Base64 Klasse mittels Base64.Encoder myEncoder = Base64.getEncoder() ein Objekt erzeugen.
Eine kleine Frage hätte ich noch, vielleicht weiß da jemand eine gute Lösung. Zur Zeit wird der Schlüssel für die Verschlüsselung noch im Quelltext gespeichert. Das ist an sich ja schon ziemlich unsicher, da man den Bytecode jederzeit wieder zu Klartext zurückkonvertierten kann. Gibt es einen Weg den Schlüssel ohne riesigen Aufwand zu sichern?
Hey Bastian,
schön, dass dir mein Beitrag gefällt:)
@Base64
Das Problem habe ich schon hier beschrieben;-)
http://blog.axxg.de/java-kodierung-base64/
@Speicherung des Keys
Das ist immer das größte Problem. Die Lösung: Es gibt keine Pauschallösung:-/
+ Auf Android hat man die Möglichkeit den Key in einem sicheren Speicherbereich des Prozessors oder im security Element abzulegen.
+ Auf Windows und co kann man den AES Schlüssel per RSA/SSL auf den Client zur Laufzeit übertragen und mit Hardware-Spec’s verschlüsseln.
+ Man kann den Schlüssel aus einer Zeitvorgabe oder einen Key generieren
+ etc…….
Such dir was aus;-)
ACHTUNG! Hier wird die AES-Chiffre im ECB-Modus gezeigt! Das ist höchst fahrlässig und unsicher!
Bitte lesen: https://de.wikipedia.org/wiki/Electronic_Code_Book_Mode
Weiter oben wird dann einfach auch ein Schlüssel per MD5 erzeugt. Man mag meinen, dass man da ja auch kein Hash zb. für Benutzeranmeldungen in ne Datenbank bringen will und das ausreiche. Falsch! Ein starker Hash zb. per PBKDF2 und ausreichend gesalzen ist auch hier essenziell! Stichwort: Brute-Forcing mit Wörterbuch! Mit MD5 geht das rasend schnell!
Ich hoffe, dass das jeder liest, der diese Seite besucht. Ich selbst bin auch kein Kryptograph, aber das hier ist offensichtlich.
Hey Fabian,
erstmal danke für deinen Kommentar.
zu 1. ECB-Modus
Der Beitrag richtet sich an Anfänger, die noch nichts mit AES gemacht haben. Daher gilt: je einfach desto besser. Wer einen anderen Modus nutzen will, kann gerne die Zeile 38 durch
Cipher.getInstance(„AES/CBC/NoPadding“);
ersetzen;-)
2. der Schlüssel
Siehe Oben;-) Ich zeige eine einfache Möglichkeit – mehr nicht, aber ich habe mal das Beispiel gegen SHA ersetzt….
Wie kann ich mit dem o.g. Code statt einem Text einen Ordner verschlüsseln? Z.B. E:/Beispielordner1