All Products
Search
Document Center

ApsaraDB RDS:Use the Always confidential database feature from a client

Last Updated:Mar 28, 2026

Connect your Java application to an ApsaraDB RDS for PostgreSQL instance with Always confidential database enabled. This document covers EncJDBC (recommended, zero business code changes), EncDB SDK (explicit encrypt/decrypt calls), psql, and the Data Management (DMS) console.

Prerequisites

Before you begin, ensure that you have:

Security note

Store your master encryption key (MEK) in a secure location and never expose it in plaintext. The Always confidential database does not generate, store, or back up your MEK. If you lose your MEK, the data it encrypted becomes permanently inaccessible.

Choose a client method

MethodDescriptionBusiness code changes
EncJDBCAutomatically identifies encrypted columns and handles encryption/decryption transparentlyNot required (recommended)
EncDB SDKRequires explicit encrypt/decrypt calls in your application codeRequired
psqlCommand-line tool; returns ciphertext for encrypted columnsNot required
DMS consoleVisual query interface; returns ciphertext for encrypted columnsNot required

EncJDBC

EncJDBC works exactly like standard Java Database Connectivity (JDBC). Only the driver class and connection URL differ — no changes to your insert, update, or query logic are needed. This is the recommended approach for Java applications.

What happens under different conditions:

ConditionResult
EncJDBC connected, MEK correctValues are transparently encrypted on write and decrypted on read
EncJDBC connected, wrong MEKError on connect (error code 0xf7070000)
psql or DMS connectedEncrypted columns appear as ciphertext

Step 1: Download and install the driver

Download encjdbc-1.0.6.jar from the EncJDBC driver package.

This driver requires minor engine version 20230830 or later, with EncDB version 1.1.13 or later on the RDS instance.

Install the JAR to your local Maven repository:

mvn install:install-file \
  -DgroupId=com.alibaba.encdb \
  -DartifactId=encjdbc \
  -Dversion=1.0.6 \
  -Dpackaging=jar \
  -Dfile=<path-to-encjdbc-1.0.6.jar>

Step 2: Add Maven dependencies

Add the following to your pom.xml:

<dependencies>
  <dependency>
    <groupId>com.alibaba.encdb</groupId>
    <artifactId>encjdbc</artifactId>
    <version>1.0.6</version>
  </dependency>
  <!-- BouncyCastle crypto libraries -->
  <dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcprov-jdk15on</artifactId>
    <version>1.62</version>
  </dependency>
  <dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcpkix-jdk15on</artifactId>
    <version>1.62</version>
  </dependency>
  <dependency>
    <groupId>com.alibaba.fastjson2</groupId>
    <artifactId>fastjson2</artifactId>
    <version>2.0.2</version>
  </dependency>
  <dependency>
    <groupId>org.postgresql</groupId>
    <artifactId>postgresql</artifactId>
    <version>42.2.23</version>
  </dependency>
  <dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>24.1.1-jre</version>
  </dependency>
  <dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.2.4</version>
  </dependency>
  <dependency>
    <groupId>org.jgrapht</groupId>
    <artifactId>jgrapht-core</artifactId>
    <!-- jgrapht does not support Java 1.8 since 1.5.0 -->
    <version>1.4.0</version>
  </dependency>
</dependencies>

Step 3: Connect and query

The connection URL uses the encjdbc:postgresql:// scheme. All other JDBC operations — createStatement, PreparedStatement, ResultSet — work as usual.

Warning

Do not hardcode password or mek in production code. Load them from environment variables or an external configuration file.

Connection URL format:

String dbUrl = String.format(
    "encjdbc:postgresql://%s:%s/%s?mek=%s&enc_algo=%s",
    hostname, port, dbname, mek, encAlgo
);
Class.forName("com.alibaba.encdb.encjdbc.EncDriver");
Connection dbConnection = DriverManager.getConnection(dbUrl, username, password);

Connection URL parameters:

Data security-related parameters

ParameterExampleDescription
mek0x00112233445566778899aabbccddeeffThe MEK specified by the data owner. Generate with openssl rand -hex 16, a language random function, or Key Management Service (KMS). Must be a 32-character hexadecimal string. The MEK is transmitted to the server using envelope encryption.
enc_algoSM4_128_CBCEncryption algorithm. Options: AES_128_GCM, AES_128_CBC, AES_128_ECB (internationally accepted); SM4_128_GCM, SM4_128_CBC (default), SM4_128_ECB (ShangMi). The CTR algorithm is not supported. Avoid AES_128_ECB and SM4_128_ECB in production — they provide weaker security guarantees.
enc_schemeRNDEncryption method. RND (probabilistic, default) or DET (deterministic). Invalid when enc_algo is AES_128_ECB or SM4_128_ECB.
dek_gen_modeENCLAVEData encryption key (DEK) generation mode. ENCLAVE (server generates the DEK in the trusted enclave, default) or LOCAL (client generates the DEK).
statelesstrueWhether the MEK stays valid after the client disconnects. true (default) or false.

Use & to concatenate multiple parameters in the URL.

Complete example:

// Replace with your instance connection details
String hostname = "hostname";
String port     = "port";
String dbname   = "db";
String username = "user";
String password = "password"; // Load from environment variable in production

// Use a strong MEK generated by openssl rand -hex 16 or KMS
String mek     = "00112233445566778899aabbccddeeff";
String encAlgo = "SM4_128_CBC";

String dbUrl = String.format(
    "encjdbc:postgresql://%s:%d/%s?mek=%s&enc_algo=%s",
    hostname, port, dbname, mek, encAlgo
);
Class.forName("com.alibaba.encdb.encjdbc.EncDriver");
Connection dbConnection = DriverManager.getConnection(dbUrl, username, password);

// Create table
dbConnection.createStatement().executeUpdate("DROP TABLE IF EXISTS example");
dbConnection.createStatement().executeUpdate(
    "CREATE TABLE example (id INTEGER, name VARCHAR, price enc_int4, miles enc_float4, secret enc_text, PRIMARY KEY (id))"
);

// Insert data
PreparedStatement stmt = dbConnection.prepareStatement(
    "INSERT INTO example (id, name, price, miles, secret) VALUES(?,?,?,?,?)"
);
int price   = 1234;
float miles = 12.34f;
String secret = "aliyun";
stmt.setInt(1, 1);
stmt.setString(2, "name");
stmt.setInt(3, price);
stmt.setFloat(4, miles);
stmt.setString(5, secret);
stmt.execute();

// Query — EncJDBC transparently decrypts encrypted columns
String sqlCmd = "SELECT * FROM example WHERE price > ?";
PreparedStatement queryStmt = dbConnection.prepareStatement(sqlCmd);
queryStmt.setInt(1, 100);
ResultSet rs = queryStmt.executeQuery();
while (rs.next()) {
    int id       = rs.getInt(1);
    String name  = rs.getString(2);
    int p        = rs.getInt(3);
    float m      = rs.getFloat(4);
    String s     = rs.getString(5);
    System.out.println(id + ", " + name + ", " + p + ", " + m + ", " + s);
}

Expected output:

1, name, 1234, 12.34, aliyun

EncJDBC handles all encryption and decryption automatically. Apart from the driver class name and the encjdbc:postgresql:// URL scheme, no other code changes are needed.

EncDB SDK

Use EncDB SDK when your application needs explicit control over encryption and decryption. Unlike EncJDBC, EncDB SDK requires you to call cryptor.encrypt(...) before writing data and cryptor.decryptXxx(...) after reading it.

Step 1: Download and install the SDK

Download libencdb-1.2.12.jar from the EncDB SDK package.

This SDK requires minor engine version 20230830 or later, with EncDB version 1.1.13 or later on the RDS instance.

Install the JAR to your local Maven repository:

mvn install:install-file \
  -DgroupId=com.alibaba.encdb \
  -DartifactId=libencdb \
  -Dversion=1.2.12 \
  -Dpackaging=jar \
  -Dfile=<path-to-libencdb-1.2.12.jar>

Step 2: Add Maven dependencies

<dependencies>
  <dependency>
    <groupId>com.alibaba.encdb</groupId>
    <artifactId>libencdb</artifactId>
    <version>1.2.12</version>
  </dependency>
  <dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcprov-jdk15on</artifactId>
    <version>1.70</version>
  </dependency>
  <dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcpkix-jdk15on</artifactId>
    <version>1.70</version>
  </dependency>
  <dependency>
    <groupId>com.google.code.gson</groupId>
    <artifactId>gson</artifactId>
    <version>2.10.1</version>
  </dependency>
  <dependency>
    <groupId>org.postgresql</groupId>
    <artifactId>postgresql</artifactId>
    <version>42.2.23</version>
  </dependency>
  <dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>31.1-jre</version>
  </dependency>
  <dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>1.7.30</version>
  </dependency>
  <dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-collections4</artifactId>
    <version>4.4</version>
  </dependency>
</dependencies>

Step 3: Initialize the SDK and query

The EncDB SDK uses a standard JDBC connection string (jdbc:postgresql://) and a separate EncdbSDK object for key management. In most cases, configure setMek and setEncAlgo; all other parameters use sensible defaults.

Warning

Do not hardcode password or mek in production code. Load them from environment variables or an external configuration file.

SDK initialization pattern:

// Standard PostgreSQL JDBC connection
String dbUrl = String.format(
    "jdbc:postgresql://%s:%s/%s?binaryTransfer=true",
    hostname, port, dbname
);
Class.forName("org.postgresql.Driver");
Connection dbConnection = DriverManager.getConnection(dbUrl, username, password);

// Initialize the EncDB SDK with your MEK and encryption algorithm
String mek = ...;
Constants.EncAlgo encAlgo = ...;
EncdbSDK sdk = EncdbSDKBuilder.newInstance()
        .setDbConnection(dbConnection)
        .setMek(mek)
        .setEncAlgo(encAlgo)
        .build();
Cryptor cryptor = sdk.getCryptor();

// Use cryptor to encrypt before writing and decrypt after reading:
// byte[] cipherBytes = cryptor.encrypt("tableName", "columnName", value);
// int plainInt = cryptor.decryptInt(rs.getBytes(columnIndex));

SDK initialization parameters:

Initialize SDK-related parameters

ParameterExampleDescription
Mek0x00112233445566778899aabbccddeeffThe MEK specified by the data owner. Must be a 16-byte byte[] or a 32-character hexadecimal string. Generate with openssl rand -hex 16, a language random function, or KMS. The MEK is transmitted using envelope encryption.
EncAlgoSM4_128_CBCEncryption algorithm. Same options as EncJDBC. Default: SM4_128_CBC.
EncSchemeRNDEncryption method. RND (probabilistic, default) or DET (deterministic). Invalid when EncAlgo is AES_128_ECB or SM4_128_ECB.
DekGenModeENCLAVEDEK generation mode. ENCLAVE (default) or LOCAL.
SdkModeDefaultSDK mode. Default supports all ciphertext types in Basic Edition and Hardware-enhanced Edition.
StatelesstrueWhether the MEK stays valid after disconnect. true (default) or false.

Complete example:

// Replace with your instance connection details
String hostname = "hostname";
String port     = "port";
String dbname   = "db";
String username = "user";
String password = "password"; // Load from environment variable in production

// Establish a standard PostgreSQL JDBC connection
String dbUrl = String.format(
    "jdbc:postgresql://%s:%s/%s?binaryTransfer=true",
    hostname, port, dbname
);
Class.forName("org.postgresql.Driver");
Connection dbConnection = DriverManager.getConnection(dbUrl, username, password);

// Initialize the SDK — use a strong MEK in production
String mek = "00112233445566778899aabbccddeeff";
Constants.EncAlgo encAlgo = Constants.EncAlgo.SM4_128_CBC;
EncdbSDK sdk = EncdbSDKBuilder.newInstance()
        .setDbConnection(dbConnection)
        .setMek(mek)
        .setEncAlgo(encAlgo)
        .build();
Cryptor cryptor = sdk.getCryptor();

// Create table
dbConnection.createStatement().executeUpdate("DROP TABLE IF EXISTS example");
dbConnection.createStatement().executeUpdate(
    "CREATE TABLE example (id INTEGER, name VARCHAR, price enc_int4, miles enc_float4, secret enc_text, PRIMARY KEY (id))"
);

// Insert data — encrypt each sensitive column value before binding
PreparedStatement stmt = dbConnection.prepareStatement(
    "INSERT INTO example (id, name, price, miles, secret) VALUES(?,?,?,?,?)"
);
int price   = 1234;
float miles = 12.34f;
String secret = "aliyun";
stmt.setInt(1, 1);
stmt.setString(2, "name");
stmt.setBytes(3, cryptor.encrypt("example", "price", price));
stmt.setBytes(4, cryptor.encrypt("example", "miles", miles));
stmt.setBytes(5, cryptor.encrypt("example", "secret", secret));
stmt.execute();

// Query — decrypt each encrypted column after reading
String sqlCmd = "SELECT * FROM example WHERE price > ?";
stmt = dbConnection.prepareStatement(sqlCmd);
stmt.setBytes(1, cryptor.encrypt("example", "price", 100));
ResultSet rs = stmt.executeQuery();
while (rs.next()) {
    int id      = rs.getInt(1);
    String name = rs.getString(2);
    price       = cryptor.decryptInt(rs.getBytes(3));
    miles       = cryptor.decryptFloat(rs.getBytes(4));
    String text = cryptor.decryptString(rs.getBytes(5));
    System.out.println(id + ", " + name + ", " + price + ", " + miles + ", " + text);
}

Expected output:

1, name, 1234, 12.34, aliyun

SDK API reference

com.alibaba.encdb.crypto.EncdbSDKBuilder

`com.alibaba.encdb.crypto.EncdbSDKBuilder` — builds an EncdbSDK instance.

// Obtain a builder instance (required entry point)
EncdbSDKBuilder newInstance();

// Set the database connection used for key management (required)
// Use a dedicated connection separate from your application's query connection
EncdbSDKBuilder setDbConnection(java.sql.Connection dbConnection);

// Specify the client type (required; use MYSQL_PROXY for Always confidential MySQL databases)
EncdbSDKBuilder setKeyMgmtType(KeyMgmtType kmType);

// Set the MEK — 16-byte byte[] or 32-character hex string (required)
EncdbSDKBuilder setMek(byte[] mek);
EncdbSDKBuilder setMek(String mekStr);

// Set the encryption algorithm (optional; defaults to SM4_128_CBC)
EncdbSDKBuilder setEncAlgo(EncAlgo encAlgo);

// Build the EncdbSDK object
EncdbSDK build();

com.alibaba.encdb.EncdbSDK

`com.alibaba.encdb.EncdbSDK` — provides key management and secure communication.

// Get a Cryptor object for encrypt/decrypt operations
Cryptor getCryptor();

com.alibaba.encdb.Cryptor

`com.alibaba.encdb.Cryptor` — encrypts and decrypts column values.

Encrypt overloads (for byte[], int, long, float, double, String, BigDecimal, Timestamp):

byte[] encrypt(String tblName, String colName, <value>);
byte[] encrypt(String schemaName, String tblName, String colName, <value>);
// To use the default DEK, set tblName = "default" and colName = "default"

Decrypt overloads:

byte[]     decrypt(byte[] val);
int        decryptInt(byte[] val);
long       decryptLong(byte[] val);
float      decryptFloat(byte[] val);
double     decryptDouble(byte[] val);
String     decryptString(byte[] val);
BigDecimal decryptDecimal(byte[] val);
Timestamp  decryptTimestamp(byte[] val);

psql

Run queries against Always confidential databases using psql. Encrypted columns appear as ciphertext — psql does not decrypt them.

For example, executing SELECT * FROM example; returns:

image.png

In the output, id and name are plaintext columns. price, miles, and secret are ciphertext columns. The encrypted data cannot be viewed on the RDS instance, which prevents unauthorized access from both inside and outside the database server.

DMS console

Use the Data Management (DMS) console to query Always confidential databases visually. Like psql, DMS returns ciphertext for encrypted columns.

image.png

In the output, id and name are plaintext columns, and price, miles, and secret are ciphertext columns.

FAQ

What causes `org.postgresql.util.PSQLException: ERROR: db_process_msg_api: process message failure - returned 0xf7070000`?

Error code 0xf7070000 means the MEK could not be imported. Data encrypted with one MEK cannot be accessed with a different MEK. This error most often occurs when the same account connects to the same Always confidential database with different MEK values across sessions. Always use the same MEK for a given database.

What causes `java.lang.IllegalAccessError: class com.alibaba.encdb.common.SymCrypto ... cannot access class com.sun.crypto.provider.SunJCE`?

This error occurs when the JDK version is newer than expected and inter-module access is restricted. Add the following VM option when running your program:

--add-exports=java.base/com.sun.crypto.provider=ALL-UNNAMED