AES Encryption and Decryption Logic
This document explains the logic behind using AES (Advanced Encryption Standard) for secure data transmission, particularly in encrypting and decrypting data, with a symmetric key. We’ll cover how AES encryption in CBC mode with PKCS5 padding is implemented and used for secure data transmission.
Below are the main components involved in the process, along with a sample Java code implementation.
1. Symmetric key Encryption
AES is a symmetric encryption algorithm, meaning the same key is used for both encryption and decryption.
2. Initialization Vector(IV)
AES in CBC (Cipher Block Chaining) mode requires an Initialization Vector (IV) to ensure that encrypting the same data with the same key multiple times results in different ciphertexts.
3. Base64 Encoding
Since encryption produces binary output, Base64 encoding is commonly used to convert the encrypted data into a string format suitable for transmission over text-based protocols, such as HTTP. Both the encryption key and encrypted data are Base64 encoded.
4. Padding Scheme (PKCS5)
AES encryption requires that the data length be a multiple of the block size (16 bytes for AES). To achieve this, a padding scheme PKCS5 is applied during encryption and automatically removed during decryption.
5. Process Flow
Encryption:
- Decode the Base64-encoded symmetric key.
- Generate a random IV.
- Encrypt the data using the decoded key and IV.
- Combine the IV and the encrypted data into one payload.
- Encode the final output with Base64 for transmission.
Decryption:
- Decode the Base64-encoded input (both IV and ciphertext).
- Extract the IV from the first part of the input.
- Decrypt the remaining ciphertext using the same key and extracted IV.
- Remove any extraneous noise (if applicable) after decryption, ensuring the output is in the expected format.
6. Handling Noise in Decrypted Data
In cases where noise or extra characters may be present after decryption (e.g., due to system-specific formatting issues), it's crucial to clean the decrypted data. This can be done by identifying and preserving the structure of the original payload, such as JSON objects or arrays.
Sample Java Code Implementation:
Below is a sample implementation of the AES encryption and decryption logic in Java:
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; import java.security.SecureRandom; import java.util.Base64; import java.util.Arrays; import java.nio.charset.StandardCharsets; public class AESUtils { // —------- Encryption Method —----------- public static String EncryptRequest(Object incomingJsonReq, String key) throws Exception { byte[] decodedKey = Base64.getDecoder().decode(key); if (decodedKey.length != 32) { throw new IllegalArgumentException("Invalid key"); } // Generate a random IV byte[] iv = new byte[16]; SecureRandom random = new SecureRandom(); random.nextBytes(iv); System.out.println("IV generated: " + Arrays.toString(iv)); // Convert payload to byte array byte[] payloadBytes = incomingJsonReq.toString().getBytes(); // Initialize AES cipher SecretKeySpec secretKeySpec = new SecretKeySpec(decodedKey,"AES"); Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); IvParameterSpec ivSpec = new IvParameterSpec(iv); cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivSpec); // Encrypt the data byte[] encryptedBytes = cipher.doFinal(payloadBytes); // Combine IV and encrypted data byte[] result = new byte[iv.length + encryptedBytes.length]; System.arraycopy(iv, 0, result, 0, iv.length); System.arraycopy(encryptedBytes, 0, result, iv.length,encryptedBytes.length); // Return Base64 encoded result return Base64.getEncoder().encodeToString(result); } // —-------- Decryption Method ----------- public String decryptRequest(String encryptedString, String key) throws Exception { // Decode Base64 encoded input and key byte[] byteCipherText = Base64.getDecoder().decode(encryptedString); byte[] byteKey = Base64.getDecoder().decode(key); // Extract IV and cipher text from the encrypted input byte[] iv = Arrays.copyOfRange(byteCipherText, 0, 16); byte[] cipherText = Arrays.copyOfRange(byteCipherText, 16, byteCipherText.length); // Initialize AES cipher for decryption SecretKeySpec secretKey = new SecretKeySpec(byteKey, "AES"); IvParameterSpec ivParams = new IvParameterSpec(iv); Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); cipher.init(Cipher.DECRYPT_MODE, secretKey, ivParams); // Decrypt the cipher text byte[] bytePlainText = cipher.doFinal(cipherText); // Clean the decrypted data and return return removeNoise(new String(bytePlainText, StandardCharsets.UTF_8).trim()); } // Removing noise and returning clean string up to } or ] private String removeNoise(String data) { int lastCurlyBrace = data.lastIndexOf('}'); int lastSquareBracket = data.lastIndexOf(']'); int lastIndex = Math.max(lastCurlyBrace, lastSquareBracket); if (lastIndex != -1) { return data.substring(0, lastIndex + 1); } return data; } } |
Conclusion:
The logic explained in this document enables secure encryption and decryption of data using AES in CBC mode. By combining proper key management, secure IV generation, and Base64 encoding for transmission, the method ensures the confidentiality of sensitive information.
Notes:
|