Der Advanced Encryption Standard (AES, Rijndael) ist ein Blockchiffrier-Verschlüsselungs- und -Entschlüsselungsalgorithmus, der weltweit am häufigsten verwendete Verschlüsselungsalgorithmus. Der AES verarbeitet Blöcke von 128 Bits unter Verwendung eines geheimen Schlüssels von 128, 192 oder 256 Bits.
Dieser Artikel zeigt Ihnen einige Beispiele für die Ver- und Entschlüsselung mit Java AES:
- AES String-Verschlüsselung – (Ver- und Entschlüsselung eines Strings).
- AES Passwort-basierte Verschlüsselung – (Der geheime Schlüssel wird aus einem gegebenen Passwort abgeleitet).
- AES Dateiverschlüsselung. (Passwort-basiert).
In diesem Artikel konzentrieren wir uns auf die 256-Bit-AES-Verschlüsselung mit Galois Counter Mode (GCM).
GCM = CTR + Authentication.
Weitere Lektüre
Lesen Sie dies – NIST – Recommendation for Galois/Counter Mode (GCM)
Nicht den AES Electronic codebook (ECB) Mode verwenden
Der AES ECB Mode, oder AES/ECB/PKCS5Padding
(in Java) ist semantisch nicht sicher – der ECB-verschlüsselte Chiffretext kann Informationen über den Klartext preisgeben. Hier ist eine Diskussion über Warum sollte ich keine ECB-Verschlüsselung verwenden?
Java und AES-Verschlüsselungseingänge.
Bei der AES-Verschlüsselung und -Entschlüsselung benötigen wir die folgenden Eingaben:
Best Practice bei der AES-Verschlüsselung
Den IV nicht mit demselben Schlüssel wiederverwenden.
1.1 Der IV (Initialwert oder Initialvektor), es sind zufällige Bytes, typischerweise 12 Bytes oder 16 Bytes. In Java können wir SecureRandom
verwenden, um den zufälligen IV zu erzeugen.
// 16 bytes IV public static byte getRandomNonce() { byte nonce = new byte; new SecureRandom().nextBytes(nonce); return nonce; } // 12 bytes IV public static byte getRandomNonce() { byte nonce = new byte; new SecureRandom().nextBytes(nonce); return nonce; }
1.2 Der geheime AES-Schlüssel, entweder AES-128
oder AES-256
. In Java können wir KeyGenerator
verwenden, um den geheimen AES-Schlüssel zu erzeugen.
// 256 bits AES secret key public static SecretKey getAESKey() throws NoSuchAlgorithmException { KeyGenerator keyGen = KeyGenerator.getInstance("AES"); keyGen.init(256, SecureRandom.getInstanceStrong()); return keyGen.generateKey(); }
1.3 Der geheime AES-Schlüssel, der aus einem gegebenen Passwort abgeleitet wurde. In Java können wir das SecretKeyFactory
und PBKDF2WithHmacSHA256
verwenden, um einen AES-Schlüssel aus einem gegebenen Passwort zu erzeugen.
// AES key derived from a password public static SecretKey getAESKeyFromPassword(char password, byte salt) throws NoSuchAlgorithmException, InvalidKeySpecException { SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256"); // iterationCount = 65536 // keyLength = 256 KeySpec spec = new PBEKeySpec(password, salt, 65536, 256); SecretKey secret = new SecretKeySpec(factory.generateSecret(spec).getEncoded(), "AES"); return secret; }
Wir verwenden salt
zum Schutz vor Regenbogenangriffen, und da es sich ebenfalls um ein zufälliges Byte handelt, können wir dasselbe 1.1 getRandomNonce
zur Erzeugung verwenden.
1.4 Wir gruppieren die oben genannten Methoden in einer einzigen util
-Klasse, damit wir nicht immer wieder den gleichen Code wiederholen.
package com.mkyong.crypto.utils;import javax.crypto.KeyGenerator;import javax.crypto.SecretKey;import javax.crypto.SecretKeyFactory;import javax.crypto.spec.PBEKeySpec;import javax.crypto.spec.SecretKeySpec;import java.security.NoSuchAlgorithmException;import java.security.SecureRandom;import java.security.spec.InvalidKeySpecException;import java.security.spec.KeySpec;import java.util.ArrayList;import java.util.List;public class CryptoUtils { public static byte getRandomNonce(int numBytes) { byte nonce = new byte; new SecureRandom().nextBytes(nonce); return nonce; } // AES secret key public static SecretKey getAESKey(int keysize) throws NoSuchAlgorithmException { KeyGenerator keyGen = KeyGenerator.getInstance("AES"); keyGen.init(keysize, SecureRandom.getInstanceStrong()); return keyGen.generateKey(); } // Password derived AES 256 bits secret key public static SecretKey getAESKeyFromPassword(char password, byte salt) throws NoSuchAlgorithmException, InvalidKeySpecException { SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256"); // iterationCount = 65536 // keyLength = 256 KeySpec spec = new PBEKeySpec(password, salt, 65536, 256); SecretKey secret = new SecretKeySpec(factory.generateSecret(spec).getEncoded(), "AES"); return secret; } // hex representation public static String hex(byte bytes) { StringBuilder result = new StringBuilder(); for (byte b : bytes) { result.append(String.format("%02x", b)); } return result.toString(); } // print hex with block size split public static String hexWithBlockSize(byte bytes, int blockSize) { String hex = hex(bytes); // one hex = 2 chars blockSize = blockSize * 2; // better idea how to print this? List<String> result = new ArrayList<>(); int index = 0; while (index < hex.length()) { result.add(hex.substring(index, Math.min(index + blockSize, hex.length()))); index += blockSize; } return result.toString(); }}
AES-Verschlüsselung und -Entschlüsselung.
Der AES-GSM ist die am weitesten verbreitete authentifizierte Chiffre. In diesem Beispiel wird eine Zeichenkette mit 256-Bit-AES im Galois-Counter-Modus (GCM) ver- und entschlüsselt.
Die AES-GCM-Eingaben:
- AES-Geheimschlüssel (256 Bits)
- IV – 96 Bits (12 Bytes)
- Länge (in Bits) der Authentifizierungsmarke – 128 Bits (16 Bytes)
2.1 In Java verwenden wir AES/GCM/NoPadding
, um den AES-GCM
-Algorithmus darzustellen. Für die verschlüsselte Ausgabe stellen wir dem verschlüsselten Text (Chiffretext) die 16 Bytes IV voran, da wir die gleiche IV für die Entschlüsselung benötigen.
Ist das ok, wenn die IV öffentlich bekannt ist?
Es ist in Ordnung, wenn der IV öffentlich bekannt ist, das einzige Geheimnis ist der Schlüssel, halten Sie ihn privat und vertraulich.
In diesem Beispiel wird AES verwendet, um einen Klartext Hello World AES-GCM
zu verschlüsseln und ihn später wieder in den ursprünglichen Klartext zu entschlüsseln.
package com.mkyong.crypto.encryptor;import com.mkyong.crypto.utils.CryptoUtils;import javax.crypto.Cipher;import javax.crypto.SecretKey;import javax.crypto.spec.GCMParameterSpec;import java.nio.ByteBuffer;import java.nio.charset.Charset;import java.nio.charset.StandardCharsets;/** * AES-GCM inputs - 12 bytes IV, need the same IV and secret keys for encryption and decryption. * <p> * The output consist of iv, encrypted content, and auth tag in the following format: * output = byte {i i i c c c c c c ...} * <p> * i = IV bytes * c = content bytes (encrypted content, auth tag) */public class EncryptorAesGcm { private static final String ENCRYPT_ALGO = "AES/GCM/NoPadding"; private static final int TAG_LENGTH_BIT = 128; private static final int IV_LENGTH_BYTE = 12; private static final int AES_KEY_BIT = 256; private static final Charset UTF_8 = StandardCharsets.UTF_8; // AES-GCM needs GCMParameterSpec public static byte encrypt(byte pText, SecretKey secret, byte iv) throws Exception { Cipher cipher = Cipher.getInstance(ENCRYPT_ALGO); cipher.init(Cipher.ENCRYPT_MODE, secret, new GCMParameterSpec(TAG_LENGTH_BIT, iv)); byte encryptedText = cipher.doFinal(pText); return encryptedText; } // prefix IV length + IV bytes to cipher text public static byte encryptWithPrefixIV(byte pText, SecretKey secret, byte iv) throws Exception { byte cipherText = encrypt(pText, secret, iv); byte cipherTextWithIv = ByteBuffer.allocate(iv.length + cipherText.length) .put(iv) .put(cipherText) .array(); return cipherTextWithIv; } public static String decrypt(byte cText, SecretKey secret, byte iv) throws Exception { Cipher cipher = Cipher.getInstance(ENCRYPT_ALGO); cipher.init(Cipher.DECRYPT_MODE, secret, new GCMParameterSpec(TAG_LENGTH_BIT, iv)); byte plainText = cipher.doFinal(cText); return new String(plainText, UTF_8); } public static String decryptWithPrefixIV(byte cText, SecretKey secret) throws Exception { ByteBuffer bb = ByteBuffer.wrap(cText); byte iv = new byte; bb.get(iv); //bb.get(iv, 0, iv.length); byte cipherText = new byte; bb.get(cipherText); String plainText = decrypt(cipherText, secret, iv); return plainText; } public static void main(String args) throws Exception { String OUTPUT_FORMAT = "%-30s:%s"; String pText = "Hello World AES-GCM, Welcome to Cryptography!"; // encrypt and decrypt need the same key. // get AES 256 bits (32 bytes) key SecretKey secretKey = CryptoUtils.getAESKey(AES_KEY_BIT); // encrypt and decrypt need the same IV. // AES-GCM needs IV 96-bit (12 bytes) byte iv = CryptoUtils.getRandomNonce(IV_LENGTH_BYTE); byte encryptedText = EncryptorAesGcm.encryptWithPrefixIV(pText.getBytes(UTF_8), secretKey, iv); System.out.println("\n------ AES GCM Encryption ------"); System.out.println(String.format(OUTPUT_FORMAT, "Input (plain text)", pText)); System.out.println(String.format(OUTPUT_FORMAT, "Key (hex)", CryptoUtils.hex(secretKey.getEncoded()))); System.out.println(String.format(OUTPUT_FORMAT, "IV (hex)", CryptoUtils.hex(iv))); System.out.println(String.format(OUTPUT_FORMAT, "Encrypted (hex) ", CryptoUtils.hex(encryptedText))); System.out.println(String.format(OUTPUT_FORMAT, "Encrypted (hex) (block = 16)", CryptoUtils.hexWithBlockSize(encryptedText, 16))); System.out.println("\n------ AES GCM Decryption ------"); System.out.println(String.format(OUTPUT_FORMAT, "Input (hex)", CryptoUtils.hex(encryptedText))); System.out.println(String.format(OUTPUT_FORMAT, "Input (hex) (block = 16)", CryptoUtils.hexWithBlockSize(encryptedText, 16))); System.out.println(String.format(OUTPUT_FORMAT, "Key (hex)", CryptoUtils.hex(secretKey.getEncoded()))); String decryptedText = EncryptorAesGcm.decryptWithPrefixIV(encryptedText, secretKey); System.out.println(String.format(OUTPUT_FORMAT, "Decrypted (plain text)", decryptedText)); }}
Ausgabe
Klartext : Hello World AES-GCM
------ AES GCM Encryption ------Input (plain text) :Hello World AES-GCMKey (hex) :603d87185bf855532f14a77a91ec7b025c004bf664e9f5c6e95613ee9577f436IV (hex) :bdb271ce5235996a0709e09cEncrypted (hex) :bdb271ce5235996a0709e09c2d03eefe319e9329768724755c56291aecaef88cd1e6bdf72b8c7b54d75a94e66b0cd3Encrypted (hex) (block = 16) :------ AES GCM Decryption ------Input (hex) :bdb271ce5235996a0709e09c2d03eefe319e9329768724755c56291aecaef88cd1e6bdf72b8c7b54d75a94e66b0cd3Input (hex) (block = 16) :Key (hex) :603d87185bf855532f14a77a91ec7b025c004bf664e9f5c6e95613ee9577f436Decrypted (plain text) :Hello World AES-GCM
Klartext : Hello World AES-GCM, Welcome to Cryptography!
------ AES GCM Encryption ------Input (plain text) :Hello World AES-GCM, Welcome to Cryptography!Key (hex) :ddc24663d104e1c2f81f11aef98156503dafdc435f81e3ac3d705015ebab095cIV (hex) :b05d6aedf023f73b9e1e2d11Encrypted (hex) :b05d6aedf023f73b9e1e2d11f6f5137d971aea8c5cdd5b045e0960eb4408e0ee4635cccc2dfeec2c13a89bd400f659be82dc2329e9c36e3b032f38bd42296a8495ac840b0625c097d9Encrypted (hex) (block = 16) :------ AES GCM Decryption ------Input (hex) :b05d6aedf023f73b9e1e2d11f6f5137d971aea8c5cdd5b045e0960eb4408e0ee4635cccc2dfeec2c13a89bd400f659be82dc2329e9c36e3b032f38bd42296a8495ac840b0625c097d9Input (hex) (block = 16) :Key (hex) :ddc24663d104e1c2f81f11aef98156503dafdc435f81e3ac3d705015ebab095cDecrypted (plain text) :Hello World AES-GCM, Welcome to Cryptography!
AES Passwort-basierte Ver- und Entschlüsselung.
Für die passwortbasierte Verschlüsselung können wir die Password-Based Cryptography Specification (PKCS), definiert in RFC 8018, verwenden, um einen Schlüssel aus einem gegebenen Passwort zu generieren.
Für PKCS-Eingaben:
- Passwort, das Sie bereitstellen.
- Salt – Mindestens 64 Bits (8 Bytes) Zufallsbytes.
- Iterationsanzahl – Empfohlen wird eine minimale Iterationsanzahl von 1.000.
Was ist Salt und Iterationsanzahl?
- Das
salt
erzeugt einen breiten Satz von Schlüsseln für ein gegebenes Passwort. Wenn das Salz z. B. 128 Bit beträgt, gibt es für jedes Kennwort sogar 2^128 Schlüssel. Daher erhöht es die Schwierigkeit von Rainbow-Angriffen. Außerdem wird die Rainbow-Tabelle, die Angreifer für das Passwort eines Benutzers erstellt haben, für einen anderen Benutzer unbrauchbar. - Die
iteration count
erhöht die Kosten für die Erzeugung von Schlüsseln aus einem Passwort, wodurch die Schwierigkeit erhöht und die Geschwindigkeit der Angriffe verlangsamt wird.
3.1 Für die verschlüsselte Ausgabe stellen wir dem Chiffretext das 12 bytes IV
und das password salt
voran, da wir für die Entschlüsselung die gleiche IV und das Passwortsalz (für den geheimen Schlüssel) benötigen. Außerdem verwenden wir den Base64
-Encoder, um den verschlüsselten Text in eine String-Repräsentation zu kodieren, so dass wir den verschlüsselten Text oder den Chiffretext im String-Format senden können (war Byte-Array).
Ist es in Ordnung, wenn das Passwort-Salz öffentlich bekannt ist?
Es ist dasselbe mit dem IV, und es ist in Ordnung, wenn das Passwort-Salz öffentlich bekannt ist, das einzige Geheimnis ist der Schlüssel, der privat und vertraulich bleibt.
package com.mkyong.crypto.encryptor;import com.mkyong.crypto.utils.CryptoUtils;import javax.crypto.Cipher;import javax.crypto.SecretKey;import javax.crypto.spec.GCMParameterSpec;import java.nio.ByteBuffer;import java.nio.charset.Charset;import java.nio.charset.StandardCharsets;import java.util.Base64;/** * AES-GCM inputs - 12 bytes IV, need the same IV and secret keys for encryption and decryption. * <p> * The output consist of iv, password's salt, encrypted content and auth tag in the following format: * output = byte {i i i s s s c c c c c c ...} * <p> * i = IV bytes * s = Salt bytes * c = content bytes (encrypted content) */public class EncryptorAesGcmPassword { private static final String ENCRYPT_ALGO = "AES/GCM/NoPadding"; private static final int TAG_LENGTH_BIT = 128; // must be one of {128, 120, 112, 104, 96} private static final int IV_LENGTH_BYTE = 12; private static final int SALT_LENGTH_BYTE = 16; private static final Charset UTF_8 = StandardCharsets.UTF_8; // return a base64 encoded AES encrypted text public static String encrypt(byte pText, String password) throws Exception { // 16 bytes salt byte salt = CryptoUtils.getRandomNonce(SALT_LENGTH_BYTE); // GCM recommended 12 bytes iv? byte iv = CryptoUtils.getRandomNonce(IV_LENGTH_BYTE); // secret key from password SecretKey aesKeyFromPassword = CryptoUtils.getAESKeyFromPassword(password.toCharArray(), salt); Cipher cipher = Cipher.getInstance(ENCRYPT_ALGO); // ASE-GCM needs GCMParameterSpec cipher.init(Cipher.ENCRYPT_MODE, aesKeyFromPassword, new GCMParameterSpec(TAG_LENGTH_BIT, iv)); byte cipherText = cipher.doFinal(pText); // prefix IV and Salt to cipher text byte cipherTextWithIvSalt = ByteBuffer.allocate(iv.length + salt.length + cipherText.length) .put(iv) .put(salt) .put(cipherText) .array(); // string representation, base64, send this string to other for decryption. return Base64.getEncoder().encodeToString(cipherTextWithIvSalt); } // we need the same password, salt and iv to decrypt it private static String decrypt(String cText, String password) throws Exception { byte decode = Base64.getDecoder().decode(cText.getBytes(UTF_8)); // get back the iv and salt from the cipher text ByteBuffer bb = ByteBuffer.wrap(decode); byte iv = new byte; bb.get(iv); byte salt = new byte; bb.get(salt); byte cipherText = new byte; bb.get(cipherText); // get back the aes key from the same password and salt SecretKey aesKeyFromPassword = CryptoUtils.getAESKeyFromPassword(password.toCharArray(), salt); Cipher cipher = Cipher.getInstance(ENCRYPT_ALGO); cipher.init(Cipher.DECRYPT_MODE, aesKeyFromPassword, new GCMParameterSpec(TAG_LENGTH_BIT, iv)); byte plainText = cipher.doFinal(cipherText); return new String(plainText, UTF_8); } public static void main(String args) throws Exception { String OUTPUT_FORMAT = "%-30s:%s"; String PASSWORD = "this is a password"; String pText = "AES-GSM Password-Bases encryption!"; String encryptedTextBase64 = EncryptorAesGcmPassword.encrypt(pText.getBytes(UTF_8), PASSWORD); System.out.println("\n------ AES GCM Password-based Encryption ------"); System.out.println(String.format(OUTPUT_FORMAT, "Input (plain text)", pText)); System.out.println(String.format(OUTPUT_FORMAT, "Encrypted (base64) ", encryptedTextBase64)); System.out.println("\n------ AES GCM Password-based Decryption ------"); System.out.println(String.format(OUTPUT_FORMAT, "Input (base64)", encryptedTextBase64)); String decryptedText = EncryptorAesGcmPassword.decrypt(encryptedTextBase64, PASSWORD); System.out.println(String.format(OUTPUT_FORMAT, "Decrypted (plain text)", decryptedText)); }}
Ausgabe
------ AES GCM Password-based Encryption ------Input (plain text) :AES-GSM Password-Bases encryption!Encrypted (base64) :KmrvjnMusJTQo/hB7T5BvlQpvi3bVbdjpZP51NT7I/enrIfSQuDfSK6iXgdPzvUP2IE54mwrKiyHqMkG8224lRZ9tXHcclmdh98I8b3B------ AES GCM Password-based Decryption ------Input (base64) :KmrvjnMusJTQo/hB7T5BvlQpvi3bVbdjpZP51NT7I/enrIfSQuDfSK6iXgdPzvUP2IE54mwrKiyHqMkG8224lRZ9tXHcclmdh98I8b3BDecrypted (plain text) :AES-GSM Password-Bases encryption!
3.2. Wenn das Passwort nicht übereinstimmt, wirft Java AEADBadTagException: Tag mismatch!
// change the password to something else String decryptedText = EncryptorAesGcmPassword.decrypt(encryptedTextBase64, "other password"); System.out.println(String.format(OUTPUT_FORMAT, "Decrypted (plain text)", decryptedText));
Ausgabe
Exception in thread "main" javax.crypto.AEADBadTagException: Tag mismatch! at java.base/com.sun.crypto.provider.GaloisCounterMode.decryptFinal(GaloisCounterMode.java:623) at java.base/com.sun.crypto.provider.CipherCore.finalNoPadding(CipherCore.java:1118) at java.base/com.sun.crypto.provider.CipherCore.fillOutputBuffer(CipherCore.java:1055) at java.base/com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:855) at java.base/com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:446) at java.base/javax.crypto.Cipher.doFinal(Cipher.java:2207) at com.mkyong.crypto.encryptor.EncryptorAesGcmPassword.decrypt(EncryptorAesGcmPassword.java:88) at com.mkyong.crypto.encryptor.EncryptorAesGcmPassword.main(EncryptorAesGcmPassword.java:109)
AES-Datei verschlüsseln und entschlüsseln.
Dieses Beispiel ist eine AES-Passwort-basierte Dateiverschlüsselung. Die Ideen sind die gleichen, aber wir brauchen einige IO-Klassen, um mit den Ressourcen oder Dateien zu arbeiten.
Hier ist eine Textdatei, im Ordner resources
.
This is line 1.This is line 2.This is line 3.This is line 4.This is line 5.This is line 9.This is line 10.
4.1 Dieses Beispiel ist ähnlich wie 3.1 EncryptorAesGcmPassword.java
, mit einigen kleinen Änderungen wie der Rückgabe eines byte
anstelle eines base64-kodierten Strings.
public static byte encrypt(byte pText, String password) throws Exception { //... // prefix IV and Salt to cipher text byte cipherTextWithIvSalt = ByteBuffer.allocate(iv.length + salt.length + cipherText.length) .put(iv) .put(salt) .put(cipherText) .array(); // it works, even if we save the based64 encoded string into a file. // return Base64.getEncoder().encodeToString(cipherTextWithIvSalt); // we save the byte into a file. return cipherTextWithIvSalt; }
Add encryptFile
und decryptFile
, um mit der Datei zu arbeiten.
public static void encryptFile(String fromFile, String toFile, String password) throws Exception { // read a normal txt file byte fileContent = Files.readAllBytes(Paths.get(ClassLoader.getSystemResource(fromFile).toURI())); // encrypt with a password byte encryptedText = EncryptorAesGcmPasswordFile.encrypt(fileContent, password); // save a file Path path = Paths.get(toFile); Files.write(path, encryptedText); } public static byte decryptFile(String fromEncryptedFile, String password) throws Exception { // read a file byte fileContent = Files.readAllBytes(Paths.get(fromEncryptedFile)); return EncryptorAesGcmPasswordFile.decrypt(fileContent, password); }
4.2. Lesen Sie die obige readme.txt
Datei aus dem Klassenpfad, verschlüsseln Sie sie und die verschlüsselten Daten in eine neue Datei c:\test\readme.encrypted.txt
.
String password = "password123"; String fromFile = "readme.txt"; // from resources folder String toFile = "c:\\test\\readme.encrypted.txt"; // encrypt file EncryptorAesGcmPasswordFile.encryptFile(fromFile, toFile, password);
Ausgabe
4.3 Lesen Sie die verschlüsselte Datei, entschlüsseln Sie sie und geben Sie die Ausgabe aus.
String password = "password123"; String toFile = "c:\\test\\readme.encrypted.txt"; // decrypt file byte decryptedText = EncryptorAesGcmPasswordFile.decryptFile(toFile, password); String pText = new String(decryptedText, UTF_8); System.out.println(pText);
Ausgabe
This is line 1.This is line 2.This is line 3.This is line 4.This is line 5.This is line 9.This is line 10.
P.S Die AES-Bildverschlüsselung ist das gleiche Konzept.
Quellcode herunterladen
$ git clone https://github.com/mkyong/core-java
$ cd java-crypto
Lassen Sie mich wissen, wenn der Artikel verbessert werden muss. Danke.
- Wikipedia – Cipher JavaDoc
- Wikipedia – Cipher Block Chaining (CBC)
- Wikipedia – Galois/Counter Mode (GCM)
- Oracle – KeyGenerator Algorithms JavaDoc
- Java – How to generate a random 12 bytes?
- Warum sollte ich keine ECB-Verschlüsselung verwenden?
- Spring Security Crypto Module
- Wikipedia – PBKDF2
- RFC 8018 – PKCS
- Java – Wie man ein Byte-Array verbindet und aufteilt
- Java Security Standard Algorithmus-Namen
- NIST – Empfehlung für Galois/Counter Mode (GCM)
mkyong
Gründer von Mkyong.com, liebt Java und Open-Source-Kram. Folgen Sie ihm auf Twitter. Wenn Ihnen meine Tutorials gefallen, überlegen Sie sich eine Spende für diese Wohltätigkeitsorganisationen.