In dieser Antwort gehe ich auf das Hauptthema "Einfaches Java AES-Verschlüsselungs- / Entschlüsselungsbeispiel" und nicht auf die spezifische Debugging-Frage ein, da ich denke, dass dies den meisten Lesern zugute kommt.
Dies ist eine einfache Zusammenfassung meines Blogposts über AES-Verschlüsselung in Java. Ich empfehle daher, ihn vor der Implementierung durchzulesen. Ich werde jedoch weiterhin ein einfaches Beispiel zur Verfügung stellen und einige Hinweise geben, worauf zu achten ist.
In diesem Beispiel werde ich die authentifizierte Verschlüsselung im Galois / Counter-Modus oder im GCM- Modus verwenden. Der Grund dafür ist, dass Sie in den meisten Fällen Integrität und Authentizität in Kombination mit Vertraulichkeit wünschen (lesen Sie mehr im Blog ).
AES-GCM-Tutorial zur Verschlüsselung / Entschlüsselung
Hier sind die Schritte zum Ver- / Entschlüsseln mit AES-GCM mit der Java Cryptography Architecture (JCA) . Nicht mit anderen Beispielen mischen , da subtile Unterschiede Ihren Code völlig unsicher machen können.
1. Schlüssel erstellen
Da es von Ihrem Anwendungsfall abhängt, gehe ich vom einfachsten Fall aus: einem zufälligen geheimen Schlüssel.
SecureRandom secureRandom = new SecureRandom();
byte[] key = new byte[16];
secureRandom.nextBytes(key);
SecretKey secretKey = SecretKeySpec(key, "AES");
Wichtig:
2. Erstellen Sie den Initialisierungsvektor
Ein Initialisierungsvektor (IV) wird verwendet, so dass derselbe geheime Schlüssel unterschiedliche Chiffretexte erzeugt .
byte[] iv = new byte[12]; //NEVER REUSE THIS IV WITH SAME KEY
secureRandom.nextBytes(iv);
Wichtig:
3. Mit IV und Schlüssel verschlüsseln
final Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
GCMParameterSpec parameterSpec = new GCMParameterSpec(128, iv); //128 bit auth tag length
cipher.init(Cipher.ENCRYPT_MODE, secretKey, parameterSpec);
byte[] cipherText = cipher.doFinal(plainText);
Wichtig:
- Verwenden Sie ein 16-Byte / 128-Bit- Authentifizierungs-Tag (zur Überprüfung der Integrität / Authentizität).
- Das Authentifizierungs-Tag wird automatisch an den Chiffretext angehängt (in der JCA-Implementierung).
- Da sich GCM wie eine Stream-Verschlüsselung verhält, ist kein Auffüllen erforderlich
- Verwenden Sie diese
CipherInputStream
Option, wenn Sie große Datenmengen verschlüsseln
- Möchten Sie, dass zusätzliche (nicht geheime) Daten überprüft werden, wenn sie geändert wurden? Möglicherweise möchten Sie hier die zugehörigen Daten mit
cipher.updateAAD(associatedData);
More verwenden.
3. Serialisieren Sie zu einer einzelnen Nachricht
Fügen Sie einfach IV und Chiffretext hinzu. Wie oben erwähnt, muss die IV nicht geheim sein.
ByteBuffer byteBuffer = ByteBuffer.allocate(iv.length + cipherText.length);
byteBuffer.put(iv);
byteBuffer.put(cipherText);
byte[] cipherMessage = byteBuffer.array();
Optional mit Base64 codieren, wenn Sie eine Zeichenfolgendarstellung benötigen. Verwenden Sie entweder die integrierte Implementierung von Android oder Java 8 (verwenden Sie nicht den Apache Commons Codec - es ist eine schreckliche Implementierung). Die Codierung wird verwendet, um Byte-Arrays in eine Zeichenfolgendarstellung zu "konvertieren", um sie ASCII-sicher zu machen, z.
String base64CipherMessage = Base64.getEncoder().encodeToString(cipherMessage);
4. Entschlüsselung vorbereiten: Deserialisieren
Wenn Sie die Nachricht codiert haben, dekodieren Sie sie zuerst in ein Byte-Array:
byte[] cipherMessage = Base64.getDecoder().decode(base64CipherMessage)
Wichtig:
5. Entschlüsseln
Initialisieren Sie die Verschlüsselung und stellen Sie die gleichen Parameter wie bei der Verschlüsselung ein:
final Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
//use first 12 bytes for iv
AlgorithmParameterSpec gcmIv = new GCMParameterSpec(128, cipherMessage, 0, 12);
cipher.init(Cipher.DECRYPT_MODE, secretKey, gcmIv);
//use everything from 12 bytes on as ciphertext
byte[] plainText = cipher.doFinal(cipherMessage, 12, cipherMessage.length - 12);
Wichtig:
- vergessen Sie nicht , hinzuzufügen zugehörige Daten mit ,
cipher.updateAAD(associatedData);
wenn Sie es während der Verschlüsselung hinzugefügt.
Ein funktionierendes Code-Snippet finden Sie in dieser Übersicht.
Beachten Sie, dass die neuesten Android- (SDK 21+) und Java- (7+) Implementierungen AES-GCM haben sollten. Ältere Versionen können es fehlen. Ich wähle immer noch diesen Modus, da er einfacher zu implementieren ist und nicht nur effizienter als der ähnliche Modus von Encrypt-then-Mac (z. B. AES-CBC + HMAC ). In diesem Artikel erfahren Sie, wie Sie AES-CBC mit HMAC implementieren .