The example given will accomplish below Tasks.
- Generate symmetric key using AES-128.
- Generate initialization vector used for CBC (Cipher Block Chaining).
- Encrypt message using symmetric key and initialization vector.
- Decrypt the encrypted message using symmetric key and initialization vector.
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
public class AESManager {
public static String ALGORITHM = "AES";
// public static String AES_CBC_NoPADDING = "AES/CBC/NoPadding";
public static String AES_CBC_PADDING = "AES/CBC/PKCS5Padding";
public static byte[] encrypt(final byte[] key, final byte[] IV, final byte[] message) throws Exception {
return AESManager.encryptDecrypt(Cipher.ENCRYPT_MODE, key, IV, message);
}
public static byte[] decrypt(final byte[] key, final byte[] IV, final byte[] message) throws Exception {
return AESManager.encryptDecrypt(Cipher.DECRYPT_MODE, key, IV, message);
}
private static byte[] encryptDecrypt(final int mode, final byte[] key, final byte[] IV, final byte[] message) throws Exception {
final Cipher cipher = Cipher.getInstance(AES_CBC_PADDING);
final SecretKeySpec keySpec = new SecretKeySpec(key, ALGORITHM);
final IvParameterSpec ivSpec = new IvParameterSpec(IV);
cipher.init(mode, keySpec, ivSpec);
return cipher.doFinal(message);
}
public static String getHex(byte[] data, int length) {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < length; i++) {
String hexStr = Integer.toHexString(((int) data[i]) & 0xFF);
if (hexStr.length() < 2) {
sb.append("0").append(hexStr.toUpperCase());
} else {
sb.append(hexStr.toUpperCase());
}
}
return sb.toString();
}
}
AESClient.java: AESClient class will generate random input message and will invoke AESManager.java to encrypt & decrypt input message.
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.util.Base64;
import java.util.UUID;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
public class AESClient {
private static int AES_128 = 128;
private static int AES_192 = 192;
private static int AES_256 = 256;
public static void main(String[] args) throws Exception {
byte keyBytes[] = generateKey();
String AES_KEY_HEX = AESManager.getHex(keyBytes, keyBytes.length);
System.out.println("AES-KEY : " +AES_KEY_HEX);
// Initialization vector
byte IVBytes[] = generateKey();
String randomString = UUID.randomUUID().toString().substring(0, 16);
System.out.println("1. Original Message: " + randomString);
byte[] cipherText = AESManager.encrypt(keyBytes, IVBytes, randomString.getBytes());
System.out.println("2. Encrypted Text: " + Base64.getEncoder().encodeToString(cipherText));
byte[] decryptedString = AESManager.decrypt(keyBytes, IVBytes, cipherText);
System.out.println("3. Decrypted Message : " + new String(decryptedString));
}
public static byte[] generateKey() throws NoSuchAlgorithmException, InvalidKeySpecException {
KeyGenerator keyGenerator = KeyGenerator.getInstance(AESManager.ALGORITHM);
keyGenerator.init(AES_128);
SecretKey key = keyGenerator.generateKey();
return key.getEncoded();
}
}
Sample outPut:
AES-KEY : 6239A5DBBA65D0D42E6520922621A8B8
1. Original Message: 5dbf850f-3938-48
2. Encrypted Text: smV12iTwLIHNTgFRSDzG2xmzYl5yRJQ6Jo2qnqK0iqc=
3. Decrypted Message : 5dbf850f-3938-48Generate symmetric key using AES-128.
Important Note:
AES uses block size of 16 bytes (128 bits), so if you are using "AES/CBC/NoPadding", then Smaller input must be padded with zeros to 16 bytes otherwise you will get below exception:
javax.crypto.IllegalBlockSizeException: Input length not
multiple of 16 bytes
In order to avoid padding at your end, then you have to use "AES/CBC/PKCS5Padding" as shown in above example.