Friday, September 26, 2025

OIC - How to Encrypt and Decrypt Using AES Key and OCI Function in Oracle Integration Cloud (OIC)

 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:

  1. Securely encrypt payloads before sending to external applications.
  2. Decrypt incoming encrypted data from third-party systems.
  3. Ensure compliance with data security requirements (AES/CBC/PKCS5Padding or AES/ECB/PKCS5Padding).
This approach allows OIC to delegate cryptographic operations to OCI Functions, ensuring flexibility and security without exposing raw secrets in integration flows.

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

Featured Post

OIC - How to Encrypt and Decrypt Using AES Key and OCI Function in Oracle Integration Cloud (OIC)

 Working... 📌 Use Case In real-world Oracle Integration Cloud (OIC) projects, sensitive data like passwords, API keys, or personal informat...