Working...
📌 Use Case
In real-world Oracle Integration Cloud (OIC) projects, sensitive data like passwords, API keys, or personal information must be transmitted securely. A common approach is to encrypt data before sending it to a target system and decrypt it upon retrieval.
By leveraging AES encryption/decryption inside an OCI Function and invoking it from OIC, we can:
- Securely encrypt payloads before sending to external applications.
- Decrypt incoming encrypted data from third-party systems.
- Ensure compliance with data security requirements (AES/CBC/PKCS5Padding or AES/ECB/PKCS5Padding).
✅ Solution Steps
1. Create an OCI Function for AES Encryption/Decryption
Develop a Java OCI Function (see full code below).
Function accepts input parameters:
- message → Text to encrypt or decrypt.
- secretKeyBase64 → AES key (Base64 encoded).
- ivBase64 → Initialization Vector (required for CBC mode).
- aesMode → Cipher mode (e.g., AES/CBC/PKCS5Padding or AES/ECB/PKCS5Padding).
- actionType → Either ENCRYPT or DECRYPT.
2. Deploy the Function in OCI
Use Fn Project CLI to deploy.
Make sure the function has appropriate IAM permissions to be invoked from OIC.
3. Invoke OCI Function from OIC
- In OIC, create a REST Adapter to call the OCI Function.
- Pass input parameters (message, aesMode, etc.) in the request body.
- Receive encrypted/decrypted message in the response payload.
4. Use in Integration Flows
Encrypt sensitive data (like API credentials) before storing or transmitting.
Decrypt incoming messages before business logic processing.
📝 Function Code
Here’s the Java OCI Function code you can deploy:
package com.clp.fn;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;
import java.util.logging.*;
import java.security.SecureRandom;
public class AESEncryptDecrypt {
private static final Logger logger = Logger.getLogger(AESEncryptDecrypt.class.getName());
public static class Input {
public String message;
public String secretKeyBase64;
public String ivBase64;
public String aesMode; // AES/CBC/PKCS5Padding or AES/ECB/PKCS5Padding
public String actionType; // ENCRYPT or DECRYPT
}
public static class Result {
public String message;
public String salt;
public String wechataeskey;
public String executionInfo;
}
public Result handleRequest(Input input) {
logger.log(Level.INFO, "OIC - message:", input.message);
logger.log(Level.INFO, "OIC - secretKeyBase64:", input.secretKeyBase64);
logger.log(Level.INFO, "OIC - ivBase64", input.ivBase64);
logger.log(Level.INFO, "OIC - aesMode:", input.aesMode);
logger.log(Level.INFO, "OIC - actionType:", input.actionType);
Result result = null;
if ("DECRYPT".equals(input.actionType)) {
result = decryptMyMessage(input);
} else if ("ENCRYPT".equals(input.actionType)) {
result = encryptMyMessage(input);
} else {
result = new Result();
result.executionInfo = "ERROR: No proper action found , " +
"possible value is ENCRYPT or DECRYPT , recieved value:" + input.actionType;
}
return result;
}
// Generate random 16-byte IV for AES/CBC
public static IvParameterSpec generateIV() {
byte[] iv = new byte[16]; // 128-bit IV
new SecureRandom().nextBytes(iv);
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
return ivParameterSpec;
}
public Result encryptMyMessage(Input input) {
Result result = new Result();
try {
byte[] decodedKey = null;
if (input.secretKeyBase64 == null) {
// Generate 16-digit random numeric string
String keyString = generateRandomDigits(16);
//System.out.println("Generated 16-digit AES key: " + keyString);
// Convert to byte array (each digit becomes 1 byte, 16 bytes total = 128 bits)
result.wechataeskey = keyString;
decodedKey = keyString.getBytes("UTF-8");
} else {
// Decode the base64 encoded string
decodedKey = Base64.getDecoder().decode(input.secretKeyBase64);
}
byte[] messageBytes = input.message.getBytes("UTF-8");
// Create a SecretKeySpec for the AES key
SecretKeySpec secretKeySpec = new SecretKeySpec(decodedKey, "AES");
// Create a Cipher instance for AES
Cipher cipher = Cipher.getInstance(input.aesMode);
if (input.aesMode.contains("CBC")) {
// AES/CBC/PKCS5Padding required IV
IvParameterSpec ivParameterSpec = generateIV();
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
result.salt = Base64.getEncoder().encodeToString(ivParameterSpec.getIV());
} else {
// AES/ECB/PKCS5Padding do not require IV
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
}
// Decrypt the message
byte[] originalBytes = cipher.doFinal(messageBytes);
String encodedString = Base64.getEncoder().encodeToString(originalBytes);
result.message = encodedString;
// String originalMessage = new String(originalBytes);
result.executionInfo = "SUCCESS";
} catch (Exception e) {
result.executionInfo = e.getMessage();
logger.log(Level.INFO, "Error Details:", e.getMessage());
}
return result;
}
public Result decryptMyMessage(Input input) {
Result result = new Result();
generateIV();
try {
// Decode the base64 encoded string
byte[] decodedKey = Base64.getDecoder().decode(input.secretKeyBase64);
byte[] encryptedBytes = Base64.getDecoder().decode(input.message);
// Create a SecretKeySpec for the AES key
SecretKeySpec secretKeySpec = new SecretKeySpec(decodedKey, "AES");
// Create a Cipher instance for AES
Cipher cipher = Cipher.getInstance(input.aesMode);
if (input.aesMode.contains("CBC")) {
// AES/CBC/PKCS5Padding required IV
byte[] decodedIV = Base64.getDecoder().decode(input.ivBase64);
IvParameterSpec ivParameterSpec = new IvParameterSpec(decodedIV);
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec);
} else {
// AES/ECB/PKCS5Padding do not require IV
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
}
// Decrypt the message
byte[] originalBytes = cipher.doFinal(encryptedBytes);
String encodedString = Base64.getEncoder().encodeToString(originalBytes);
result.message = encodedString;
// String originalMessage = new String(originalBytes);
result.executionInfo = "SUCCESS";
} catch (Exception e) {
result.executionInfo = e.getMessage();
logger.log(Level.INFO, "Error Details:", e.getMessage());
}
return result;
}
byte[] decodedIV = Base64.getDecoder().decode(input.ivBase64);
IvParameterSpec ivParameterSpec = new IvParameterSpec(decodedIV);
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec);
} else {
//AES/ECB/PKCS5Padding do not require IV
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
}
// Decrypt the message
byte[] originalBytes = cipher.doFinal(encryptedBytes);
String encodedString = Base64.getEncoder().encodeToString(originalBytes);
result.message = encodedString;
//String originalMessage = new String(originalBytes);
result.executionInfo = "SUCCESS";
} catch (Exception e) {
result.executionInfo = e.getMessage();
logger.log(Level.INFO, "Error Details:", e.getMessage());
}
return result;
}
// WeChat, generate a random string of digits for AES Key
public static String generateRandomDigits(int length) {
SecureRandom random = new SecureRandom();
StringBuilder sb = new StringBuilder(length);
for (int i = 0; i < length; i++) {
sb.append(random.nextInt(10)); //0-9
}
return sb.toString();
}
}
Code link:
https://drive.google.com/file/d/1OQnaC9XaEqvIMrTkbi1o5wvJsa5i1LPL/view?usp=drivesdk
Key Benefits
- Ensures data confidentiality across systems.
- Supports multiple AES modes (CBC, ECB) with PKCS5Padding.
- Can be reused across multiple OIC integrations via a single OCI Function.
- No direct exposure of keys inside OIC flows
No comments:
Post a Comment