Advanced Encryption Standard (AES) algorithm in Galois Counter Mode (GCM), known as AES-GCM. Advanced Encryption Standard with Galois Counter Mode (AES-GCM) is introduced by the National Institute for Standard and Technology (NIST). In this article, we will learn about Java AES 256 GCM Encryption and Decryption
AES-GCM is a block cipher mode of operation that provides high speed of authenticated encryption and data integrity. In GCM mode, the block encryption is transformed into stream encryption, and therefore no padding is needed. The Additional Authenticated Data (AAD) will not be encrypted but used in the computation of Authentication Tag. The authenticated encryption operation takes Initialization Vector (IV), Additional Authenticated Data (AAD), Secret Key and 128-bit plaintext and gives a 128-bit ciphertext and authentication tag
Before getting into the implementation of AES GCM encryption algorithm, let’s first understand the basic difference between AES CBC and AES GCM.
Difference between AES-CBC and AES-GCM?
Both GCM and CBC Modes involves a block cipher and an exclusive-or (XOR) but internally they both work in a different manner. Let’s understand the difference between them.
In CBC mode, you encrypt a block of data by taking the current plaintext block and XOR’ing with the previous ciphertext block and which cannot be written in parallel, this significantly affects the performance of AES-CBC encryption and AES-CBC also is vulnerable to padding oracle attacks.
GCM mode maintains a counter for each block of data and sends the current value of the counter to the block cipher and the output of the block cipher is XOR’ed with the plain text to get the ciphertext. The counter mode of operation is designed to turn block ciphers into stream ciphers. AES GCM is written in parallel and each block with AES GCM can be encrypted independently, hence the performance is significantly higher than AES CBC.
Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy
Without JCE policy files and when we try to generate a 256-bit key for AES 256 GCM encryption, we will be getting the error like “java.security.InvalidKeyException: Illegal key size” or “org.apache.xml.security.encryption.XMLEncryptionException: Illegal key size or default parameters”
Installing Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files
We need to manually download the JCE Policy files for Java 6, Java 7 and Java 8.
Java 6, Java 7 & Java 8
- JCE for different versions of Java can be downloaded from the Oracle download page.
- Download the Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy File for the JVM which you have installed.
- jce_policy-6.zip for Java 6
- UnlimitedJCEPolicyJDK7.zip for Java 7
- jce_policy-8.zip for Java 8
- Unzip the downloaded policy zip file.
- Copy local_policy.jar and US_export_policy.jar to the $JAVA_HOME/jre/lib/security, these jars will be already present and we need to overwrite them.
From Java 9 onwards default JCE policy files bundled in this Java Runtime Environment allow for “unlimited” cryptographic strengths.
Java AES 256 GCM Encryption and Decryption Example
package com.javainterviewpoint; import java.security.SecureRandom; import java.util.Base64; import javax.crypto.Cipher; import javax.crypto.KeyGenerator; import javax.crypto.SecretKey; import javax.crypto.spec.GCMParameterSpec; import javax.crypto.spec.SecretKeySpec; public class AES_GCM_Example { static String plainText = "This is a plain text which need to be encrypted by Java AES 256 GCM Encryption Algorithm"; public static final int AES_KEY_SIZE = 256; public static final int GCM_IV_LENGTH = 12; public static final int GCM_TAG_LENGTH = 16; public static void main(String[] args) throws Exception { KeyGenerator keyGenerator = KeyGenerator.getInstance("AES"); keyGenerator.init(AES_KEY_SIZE); // Generate Key SecretKey key = keyGenerator.generateKey(); byte[] IV = new byte[GCM_IV_LENGTH]; SecureRandom random = new SecureRandom(); random.nextBytes(IV); System.out.println("Original Text : " + plainText); byte[] cipherText = encrypt(plainText.getBytes(), key, IV); System.out.println("Encrypted Text : " + Base64.getEncoder().encodeToString(cipherText)); String decryptedText = decrypt(cipherText, key, IV); System.out.println("DeCrypted Text : " + decryptedText); } public static byte[] encrypt(byte[] plaintext, SecretKey key, byte[] IV) throws Exception { // Get Cipher Instance Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding"); // Create SecretKeySpec SecretKeySpec keySpec = new SecretKeySpec(key.getEncoded(), "AES"); // Create GCMParameterSpec GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(GCM_TAG_LENGTH * 8, IV); // Initialize Cipher for ENCRYPT_MODE cipher.init(Cipher.ENCRYPT_MODE, keySpec, gcmParameterSpec); // Perform Encryption byte[] cipherText = cipher.doFinal(plaintext); return cipherText; } public static String decrypt(byte[] cipherText, SecretKey key, byte[] IV) throws Exception { // Get Cipher Instance Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding"); // Create SecretKeySpec SecretKeySpec keySpec = new SecretKeySpec(key.getEncoded(), "AES"); // Create GCMParameterSpec GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(GCM_TAG_LENGTH * 8, IV); // Initialize Cipher for DECRYPT_MODE cipher.init(Cipher.DECRYPT_MODE, keySpec, gcmParameterSpec); // Perform Decryption byte[] decryptedText = cipher.doFinal(cipherText); return new String(decryptedText); } }
- The KeyGenerator Class is used to generate symmetric encryption keys, the getInstance() method returns the KeyGenerator instance for the algorithm which is passed as a parameter, in our case it is AES
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
- Now we need to generate a 256-bit key for AES 256 GCM (Note: Installing Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy is a must). Call the init() method on top of the KeyGenerator instance which we have created in the previous step, we need to pass the bit size of the keys to generate.
keyGenerator.init(AES_KEY_SIZE);
- Once the KeyGenerator is initialized, we can generate the symmetric SecretKey by calling the generateKey() method on top of the KeyGenerator instance.
SecretKey key = keyGenerator.generateKey();
- The IV stands for Initialization Vector, it is an arbitrary number which will be used along with SecretKey during encryption. The IV adds randomness to the start of the encryption process, it is also called as nonce as it will be used only once. SecureRandom class provides a cryptographically strong random number generator
byte[] IV = new byte[GCM_IV_LENGTH]; SecureRandom random = new SecureRandom(); random.nextBytes(IV);
- The encryption and decryption are handled by the Cipher class. Cipher class instance is created by calling the getInstance() method passing the Cipher name as the parameter, in our case, it is AES/GCM/NoPadding
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
- Cipher name is made up of 3 parts
- The first part is the name of the algorithm – AES
- The second part is the mode in which the algorithm should be used – GCM
- The third part is the padding scheme which is going to be used – NoPadding. Since GCM Mode transforms block encryption into stream encryption
- SecretKeySpec is a subclass of SecretKey, SecretKeySpec is a concrete class that allows for easy construction of SecretKey from an existing key. The SecretKeySpec provides the mechanism of converting byte data into a secret key suitable to be passed to init() method of the Cipher class.
SecretKeySpec keySpec = new SecretKeySpec(key.getEncoded(), "AES");
- When using other block cipher modes such as CBC mode, we require only the Initialization Vector (IV), whereas in the case of GCM mode we required Initialization Vector (IV) and Authentication Tag and hence we need to use GCMParameterSpec instead of IvParameterSpec
GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(GCM_TAG_LENGTH * 8, IV);
- Once the Cipher instance is created we need to initialize the cipher instance for encryption or decryption by calling the init() method
- Cipher Mode – Cipher.ENCRYPT_MODE (or) Cipher.DECRYPT_MODE
- SecretKeySpec
- GCMParameterSpec
cipher.init(Cipher.ENCRYPT_MODE, keySpec, gcmParameterSpec);
(or)
cipher.init(Cipher.DECRYPT_MODE, keySpec, gcmParameterSpec);
- In order to encrypt we will be calling the doFinal() method on top of the Cipher instance passing the plainText as the parameter
byte[] cipherText = cipher.doFinal(plaintext);
- We will be encoding the ciperText with Base64 to ensure it to be intact without modification when it is transferred.
Base64.getEncoder().encodeToString(cipherText)
- To decrypt we need to pass the cipherText to the doFinal() method of the Cipher instance
byte[] decryptedText = cipher.doFinal(cipherText);
Output:
Thaara says
Great article!
Quick question though:
Just dropping the JARS under $JAVA_HOME/jre/lib/security didn’t work for me. I also noticed that those two JARS aren’t present directly under $JAVA_HOME/jre/lib/security. They are present in $JAVA_HOME/jre/lib/security/policy/unlimited and $JAVA_HOME/jre/lib/security/policy/limited directories.
I copied those JARS into both the directories. It still doesn’t work. Am I missing something?
javainterviewpoint says
What is the version of Java which you are using?
javainterviewpoint says
Gotcha, This behavior is introduced in JDK 8 ver 151./lib/security/java.security and search for the line #crypto.policy=unlimited. Now just remove # to uncomment and enable JCE Unlimited Strength
You got two ways to enable unlimited strength
1. Locate the file java.security under
2. Alternatively, you can add the below line in the main method [Add it as a first line in main() method]
Security.setProperty(“crypto.policy”, “unlimited”);
Chigozie says
If I wanted to use AES 128 GCM with this implementation is it as simple as changing the key length variable to 128? The IVs should always be the same since its GCM. Is there anything else I would need to change
javainterviewpoint says
All you need to do is change key length from 256 to 128, remaining things can remain the same.