Teilen Sie die password
(a char[]
) und salt
(a - byte[]
8 Bytes, die von a ausgewählt wurden, um ein SecureRandom
gutes Salz zu erhalten - das nicht geheim gehalten werden muss) mit dem Empfänger außerhalb des Bandes. Um dann aus diesen Informationen einen guten Schlüssel abzuleiten:
/* Derive the key, given password and salt. */
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
KeySpec spec = new PBEKeySpec(password, salt, 65536, 256);
SecretKey tmp = factory.generateSecret(spec);
SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");
Die magischen Zahlen (die irgendwo als Konstanten definiert werden könnten) 65536 und 256 sind die Anzahl der Schlüsselableitungsiterationen bzw. die Schlüsselgröße.
Die Schlüsselableitungsfunktion wird iteriert, um einen erheblichen Rechenaufwand zu erfordern. Dies verhindert, dass Angreifer schnell viele verschiedene Kennwörter ausprobieren können. Die Anzahl der Iterationen kann abhängig von den verfügbaren Rechenressourcen geändert werden.
Die Schlüsselgröße kann auf 128 Bit reduziert werden, was immer noch als "starke" Verschlüsselung angesehen wird, aber es gibt keinen großen Sicherheitsspielraum, wenn Angriffe entdeckt werden, die AES schwächen.
Bei Verwendung eines geeigneten Blockverkettungsmodus kann derselbe abgeleitete Schlüssel zum Verschlüsseln vieler Nachrichten verwendet werden. Bei der Verschlüsselungsblockverkettung (CBC) wird für jede Nachricht ein zufälliger Initialisierungsvektor (IV) erzeugt, der einen anderen Verschlüsselungstext ergibt, selbst wenn der Klartext identisch ist. CBC ist möglicherweise nicht der sicherste Modus, der Ihnen zur Verfügung steht (siehe AEAD unten). Es gibt viele andere Modi mit unterschiedlichen Sicherheitseigenschaften, aber alle verwenden eine ähnliche zufällige Eingabe. In jedem Fall sind die Ausgaben jeder Verschlüsselungsoperation der Chiffretext und der Initialisierungsvektor:
/* Encrypt the message. */
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secret);
AlgorithmParameters params = cipher.getParameters();
byte[] iv = params.getParameterSpec(IvParameterSpec.class).getIV();
byte[] ciphertext = cipher.doFinal("Hello, World!".getBytes("UTF-8"));
Speichern Sie die ciphertext
und die iv
. Bei der Entschlüsselung wird das SecretKey
auf genau die gleiche Weise neu generiert, wobei das Kennwort mit denselben Salt- und Iterationsparametern verwendet wird. Initialisieren Sie die Verschlüsselung mit diesem Schlüssel und den mit der Nachricht gespeicherten Initialisierungsvektor:
/* Decrypt the message, given derived key and initialization vector. */
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(iv));
String plaintext = new String(cipher.doFinal(ciphertext), "UTF-8");
System.out.println(plaintext);
Java 7 enthielt API- Unterstützung für AEAD-Verschlüsselungsmodi , und der in OpenJDK- und Oracle-Distributionen enthaltene "SunJCE" -Anbieter implementiert diese ab Java 8. Einer dieser Modi wird dringend anstelle von CBC empfohlen. Es schützt die Integrität der Daten sowie deren Privatsphäre.
A java.security.InvalidKeyException
mit der Meldung „Unzulässige Tastengröße oder Standardparameter“ bedeutet , dass die Kryptografie - Stärke ist begrenzt; Die Richtliniendateien mit unbegrenzter Stärke befinden sich nicht am richtigen Speicherort. In einem JDK sollten sie unter platziert werden${jdk}/jre/lib/security
Basierend auf der Problembeschreibung scheint es, dass die Richtliniendateien nicht korrekt installiert sind. Systeme können problemlos mehrere Java-Laufzeiten haben. Stellen Sie sicher, dass der richtige Speicherort verwendet wird.