AES In Java using Crypto API
Sample class library implementing AES using Java Crypto API
Introduction
The Advanced Encryption Standard (AES), also known by its original name Rijndael is a specification for the encryption of electronic data. AES is a subset of the Rijndael block cipher developed by two Belgian cryptographers, Vincent Rijmen and Joan Daemen.
AES is a symmetric key algorithm, meaning the same key is used for both encryption and decryption of data.
Java Cryptography Architecture
Java Cryptography Architecture is a framework for working with cryptography using Java. It contains a set of APIs for various purposes such as encryption, key generation and management etc. In this article we will look at AES encryption capabilities.
Implementation
Lets start using AES in our code. We would need to import following crypto packages.
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
We would also need following security packages.
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.SecureRandom;
import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.KeySpec;
And finally following utitlity package imports.
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.Base64;
import java.util.List;
Encryption
encrypt method accepts a string and key, encrypts string with key and random IV and returns a base64 encoded string packing IV and encrypted string. Our wrapper is using following 2 variations of the transforms.
- AES/GCM/NoPadding (default)
- AES/CBC/PKCS5Padding - compatible with Micosoft’s System.Security.AES and BouncyCastle.Net’s AES/CBC/PKCS7
We will start by creating a SecretKeySpec
object using key bytes passed to the method.
SecretKey secretKey = new SecretKeySpec(key, ALGORITHM);
Next we will create an instane of SecureRandom and generate random IV.
SecureRandom random = new SecureRandom();
byte[] iv = random.generateSeed(AesIvSize);
We will then create an instance of cipher using Cipher.getInstance
helper method by passing the transformation to use. We call getTransformation
helper method to get current transformation to use as set in the constructor. Transformation would be either AES/GCM/NoPadding
or AES/CBC/PKCS5Padding
. We then initialise cipher
object with ENCRYPT_MODE
, secretKey
and transformation specific parameters, created using createParameterSpec
helper method.
Cipher cipher = Cipher.getInstance(getTransformation());
cipher.init(Cipher.ENCRYPT_MODE, secretKey, createParameterSpec(iv, GcmTagSize * 8));
We then have to convert plain text to bytes and call doFinal
method on cipher
object to encrypt data.
byte[] plainTextBytes = plainText.getBytes("UTF8");
byte[] encryptedBytes = cipher.doFinal(plainTextBytes);
We finally pack the data in a byte array along with IV, GCM tag size (depending on CipherMode) and convert to base64 string. IV/gcm tag size would be required to decrypt data along with key if not packed with encrypted data.
Complete code for the method is below
public String encrypt(String plainText, byte[] key)
throws InvalidKeyException, InvalidAlgorithmParameterException, Exception {
SecretKey secretKey = new SecretKeySpec(key, ALGORITHM);
SecureRandom random = new SecureRandom();
byte[] iv = random.generateSeed(AesIvSize);
Cipher cipher = Cipher.getInstance(getTransformation());
cipher.init(Cipher.ENCRYPT_MODE, secretKey, createParameterSpec(iv, GcmTagSize * 8));
byte[] plainTextBytes = plainText.getBytes("UTF8");
byte[] encryptedBytes = cipher.doFinal(plainTextBytes);
return packCipherData(encryptedBytes, iv);
}
Decryption
decrypt method works in conjunction with encrypt method above, it accepts base64 encoded cipher text string and key. It unpacks base64 encoded string to get iv, gcm tag size if CipherMode is GCM and encrypted data bytes and performs decryption and returns plain text.
We will start by creating a SecretKeySpec
object using key bytes passed to the method.
SecretKey secretKey = new SecretKeySpec(key, ALGORITHM);
We will then unpack cipher text to get IV used to encrypt data, gcm tag size and encrypted data bytes.
List<Object> cipherData = unpackCipherData(cipherText);
byte[] encryptedBytes = (byte[])cipherData.get(0);
byte[] iv = (byte[])cipherData.get(1);
byte gcmTagSize = (byte)cipherData.get(2);
We will then create an instance of cipher using Cipher.getInstance
helper method by passing the transformation to use. We call getTransformation
helper method to get current transformation to use as set in the constructor. Transformation would be either AES/GCM/NoPadding
or AES/CBC/PKCS5Padding
. We then initialise cipher
object with DECRYPT_MODE
, secretKey
and transformation specific parameters, created using createParameterSpec
helper method.
Cipher cipher = Cipher.getInstance(getTransformation());
cipher.init(Cipher.DECRYPT_MODE, secretKey, createParameterSpec(iv, gcmTagSize * 8));
We will follow that by a call doFinal
method on cipher
object to decrypt data.
byte[] decryptedBytes = cipher.doFinal(encryptedBytes);
And finally we convert decrypted bytes to UTF8 string and return to caller.
return new String(decryptedBytes, "UTF8");
Complete code for the method is below
public String decrypt(String cipherText, byte[] key)
throws InvalidKeyException, InvalidAlgorithmParameterException, Exception {
SecretKey secretKey = new SecretKeySpec(key, ALGORITHM);
List<Object> cipherData = unpackCipherData(cipherText);
byte[] encryptedBytes = (byte[])cipherData.get(0);
byte[] iv = (byte[])cipherData.get(1);
byte gcmTagSize = (byte)cipherData.get(2);
Cipher cipher = Cipher.getInstance(getTransformation());
cipher.init(Cipher.DECRYPT_MODE, secretKey, createParameterSpec(iv, gcmTagSize * 8));
byte[] decryptedBytes = cipher.doFinal(encryptedBytes);
return new String(decryptedBytes, "UTF8");
}
Complete code for the wrapper class that implements encryption and decryption using Java Cryptography APIs’ Aes can be found at AesCrypto.java. Unit tests for the wrapper class can be found at AesCryptoTests.java. Complete repository with other samples and languages can be found at CryptoSandbox.
References
https://en.wikipedia.org/wiki/Advanced_Encryption_Standard https://en.wikipedia.org/wiki/Java_Cryptography_Architecture https://github.com/junit-team/junit4/wiki/Getting-started And many more
Leave a Comment
Your email address will not be published. Required fields are marked *