Of course! Here is a comprehensive guide on how to perform AES encryption and decryption in Java, including Base64 encoding of the resulting byte arrays.

This is a very common requirement for securely storing or transmitting data.
Core Concepts
- AES (Advanced Encryption Standard): A symmetric encryption algorithm, meaning the same key is used for both encryption and decryption. We'll use AES in GCM mode (Galois/Counter Mode), which is a modern, authenticated mode that provides both confidentiality and integrity. This is highly recommended over older modes like CBC.
- Base64: An encoding scheme that converts binary data into a text string. It's not encryption; it's just a way to represent binary data (like the encrypted output) in a format that is safe for transport in text-based systems like JSON, XML, or URLs.
- Java Cryptography Architecture (JCA): The framework in Java for all cryptographic operations. We'll use its built-in classes.
Step-by-Step Implementation with GCM Mode (Recommended)
This approach is secure, modern, and includes integrity checks to ensure the data hasn't been tampered with.
The AesGcmUtil Class
This utility class will contain all the logic for encryption and decryption. It's designed to be reusable.
import javax.crypto.*;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Base64;
public class AesGcmUtil {
// AES-GCM parameters
private static final String ALGORITHM = "AES";
private static final String TRANSFORMATION = "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; // GCM recommended IV length is 12 bytes
private static final int KEY_LENGTH_BIT = 256; // AES-256
/**
* Generates a new random AES key.
* @return A Base64 encoded string of the key.
*/
public static String generateKey() {
KeyGenerator keyGenerator = null;
try {
keyGenerator = KeyGenerator.getInstance(ALGORITHM);
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("Failed to generate key", e);
}
keyGenerator.init(KEY_LENGTH_BIT);
SecretKey secretKey = keyGenerator.generateKey();
return Base64.getEncoder().encodeToString(secretKey.getEncoded());
}
/**
* Encrypts a plaintext string.
* @param plaintext The string to encrypt.
* @param key The Base64 encoded AES key.
* @return A Base64 encoded string containing the IV, ciphertext, and authentication tag.
*/
public static String encrypt(String plaintext, String key) throws Exception {
try {
// 1. Decode the key from Base64
byte[] decodedKey = Base64.getDecoder().decode(key);
SecretKey secretKey = new SecretKeySpec(decodedKey, ALGORITHM);
// 2. Generate a random IV (Initialization Vector)
byte[] iv = new byte[IV_LENGTH_BYTE];
new SecureRandom().nextBytes(iv);
// 3. Get Cipher instance
Cipher cipher = Cipher.getInstance(TRANSFORMATION);
// 4. Create GCMParameterSpec
GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(TAG_LENGTH_BIT, iv);
// 5. Initialize Cipher for ENCRYPT_MODE
cipher.init(Cipher.ENCRYPT_MODE, secretKey, gcmParameterSpec);
// 6. Encrypt the plaintext
byte[] cipherText = cipher.doFinal(plaintext.getBytes(StandardCharsets.UTF_8));
// 7. Combine IV and cipherText (IV is needed for decryption)
byte[] encryptedData = new byte[iv.length + cipherText.length];
System.arraycopy(iv, 0, encryptedData, 0, iv.length);
System.arraycopy(cipherText, 0, encryptedData, iv.length, cipherText.length);
// 8. Return Base64 encoded combined data
return Base64.getEncoder().encodeToString(encryptedData);
} catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
throw new Exception("Cipher algorithm or padding not available", e);
} catch (InvalidKeyException | InvalidAlgorithmParameterException e) {
throw new Exception("Invalid key or parameters for encryption", e);
} catch (IllegalBlockSizeException | BadPaddingException e) {
throw new Exception("Error during encryption process", e);
}
}
/**
* Decrypts a Base64 encoded encrypted string.
* @param encryptedText The Base64 encoded string to decrypt (contains IV, ciphertext, and tag).
* @param key The Base64 encoded AES key.
* @return The original plaintext string.
*/
public static String decrypt(String encryptedText, String key) throws Exception {
try {
// 1. Decode the key from Base64
byte[] decodedKey = Base64.getDecoder().decode(key);
SecretKey secretKey = new SecretKeySpec(decodedKey, ALGORITHM);
// 2. Decode the encrypted data from Base64
byte[] encryptedData = Base64.getDecoder().decode(encryptedText);
// 3. Extract the IV (first 12 bytes)
byte[] iv = new byte[IV_LENGTH_BYTE];
System.arraycopy(encryptedData, 0, iv, 0, iv.length);
// 4. Extract the actual cipherText (everything after the IV)
int cipherTextLength = encryptedData.length - IV_LENGTH_BYTE;
byte[] cipherText = new byte[cipherTextLength];
System.arraycopy(encryptedData, IV_LENGTH_BYTE, cipherText, 0, cipherTextLength);
// 5. Get Cipher instance
Cipher cipher = Cipher.getInstance(TRANSFORMATION);
// 6. Create GCMParameterSpec
GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(TAG_LENGTH_BIT, iv);
// 7. Initialize Cipher for DECRYPT_MODE
cipher.init(Cipher.DECRYPT_MODE, secretKey, gcmParameterSpec);
// 8. Decrypt the cipherText
byte[] decryptedText = cipher.doFinal(cipherText);
// 9. Return the original plaintext
return new String(decryptedText, StandardCharsets.UTF_8);
} catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
throw new Exception("Cipher algorithm or padding not available", e);
} catch (InvalidKeyException | InvalidAlgorithmParameterException e) {
throw new Exception("Invalid key or parameters for decryption", e);
} catch (IllegalBlockSizeException | BadPaddingException e) {
throw new Exception("Error during decryption process. The key may be wrong or the data is corrupted.", e);
}
}
}
Example Usage
Here's how you would use the AesGcmUtil class.

public class Main {
public static void main(String[] args) {
try {
// 1. Generate a new key (do this once and store it securely!)
// In a real application, you would load this key from a secure location,
// not generate it every time.
String secretKey = AesGcmUtil.generateKey();
System.out.println("Generated Key (Base64): " + secretKey);
// 2. The data we want to encrypt
String originalData = "This is a secret message that needs to be protected.";
// 3. Encrypt the data
String encryptedData = AesGcmUtil.encrypt(originalData, secretKey);
System.out.println("Encrypted Data (Base64): " + encryptedData);
// 4. Decrypt the data
String decryptedData = AesGcmUtil.decrypt(encryptedData, secretKey);
System.out.println("Decrypted Data: " + decryptedData);
// --- Verification ---
if (originalData.equals(decryptedData)) {
System.out.println("\nSuccess! Data decrypted correctly.");
} else {
System.out.println("\nError! Decrypted data does not match original.");
}
// --- Example of using a wrong key (will throw an exception) ---
System.out.println("\n--- Testing with a wrong key ---");
String wrongKey = AesGcmUtil.generateKey(); // Generate a different key
try {
AesGcmUtil.decrypt(encryptedData, wrongKey);
} catch (Exception e) {
System.out.println("Caught expected exception with wrong key: " + e.getMessage());
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
Expected Output
Generated Key (Base64): 8L2n5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1g==
Encrypted Data (Base64): vJvF7lE7tZ8q4jR8eWJ1bA==8L2n5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5pZ7fU1gJ9vE8kL2mN5p 