EncJDBC is a JDBC driver that lets Java applications connect to an always-confidential database and transparently decrypt encrypted column data—without changing your query logic.
With the master encryption key (MEK) configured, EncJDBC automatically decrypts ciphertext and returns plaintext to your application. The encryption and decryption process is invisible to your application code.
How it works
EncJDBC uses a two-step process:
At connection time, EncJDBC distributes your MEK to the server using envelope encryption, ensuring the key is never transmitted in plaintext.
For each query, EncJDBC automatically encrypts parameters targeting encrypted columns and decrypts results before returning them to your application.
Your application code continues to work with plaintext values—no changes to query logic are needed.
Prerequisites
Before you begin, ensure that you have:
The always-confidential database feature enabled on your ApsaraDB RDS for MySQL instance. See Enable the always-confidential database feature
Connection details for the instance: hostname, port, database name, username, and password
A data protection rule configured. See Configure data protection rules
JDK 1.8 or later
The examples in this topic use Maven 3.9.2 and IntelliJ IDEA Community Edition 2022.3.2.
Store your MEK securely and never expose it. If lost, the encrypted data becomes permanently inaccessible. Your RDS instance never generates, stores, or backs up your MEK.
Add the Maven dependency
Add the following dependency to the pom.xml file of your project:
<dependencies>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-encdb-mysql-jdbc</artifactId>
<version>1.0.9-1</version>
</dependency>
</dependencies>Configure and connect
EncJDBC uses the JDBC URL format jdbc:mysql:encdb://{hostname}:{port}/{dbname} and the driver class com.aliyun.encdb.mysql.jdbc.EncDriver.
Before connecting, configure two required parameters:
| Parameter | Example value | Description |
|---|---|---|
MEK | 00112233445566778899aabbccddeeff | The master encryption key (MEK) that you generate and manage. Valid value: a 32-character hexadecimal string (16 bytes). Generate one using openssl rand -hex 16, a language's random function, or Key Management Service (KMS). |
ENC_ALGO | SM4_128_CBC | The encryption algorithm. Default: SM4_128_GCM. |
Supported encryption algorithms:
| Category | Algorithms |
|---|---|
| AES (internationally accepted) | AES_128_GCM, AES_128_CTR, AES_128_CBC, AES_128_ECB (not recommended) |
| SM4 (Chinese national standard) | SM4_128_GCM (default), SM4_128_CTR, SM4_128_CBC, SM4_128_ECB (not recommended) |
AvoidAES_128_ECBandSM4_128_ECB—these modes do not provide strong security guarantees.
Pass configuration to EncJDBC
Three methods are available. If you want to use more than two methods to configure the parameters in JDBC, the methods are prioritized in the following order: JDBC properties > configuration file > URL parameter.
You can concatenate multiple parameters using &.
Option 1: JDBC properties
Set MEK and ENC_ALGO directly in the Properties object before opening a connection:
// Replace the placeholders with your instance connection details.
String hostname = "<hostname>";
String port = "<port>";
String dbname = "<dbname>";
String username = "<username>";
String password = "<password>";
String mek = "<your-mek>"; // 32-character hex string
String encAlgo = "<enc-algo>"; // e.g., SM4_128_GCM
Properties props = new Properties();
props.setProperty("user", username);
props.setProperty("password", password);
props.setProperty("MEK", mek);
props.setProperty("ENC_ALGO", encAlgo);
String dbUrl = String.format("jdbc:mysql:encdb://%s:%s/%s", hostname, port, dbname);
Class.forName("com.aliyun.encdb.mysql.jdbc.EncDriver");
Connection connection = DriverManager.getConnection(dbUrl, props);Option 2: Configuration file
Create a configuration file with the following content:
MEK=<your-mek>
ENC_ALGO=<enc-algo>Place the file in one of these locations:
The
resourcesdirectory of your projectThe root directory of your project (the working directory at runtime)
The default filename is encjdbc.conf. To use a custom path, set the encJdbcConfigFile system property to the directory of the configuration file.
After placing the file, connect without specifying MEK or ENC_ALGO in code:
String dbUrl = String.format("jdbc:mysql:encdb://%s:%s/%s", hostname, port, dbname);
Class.forName("com.aliyun.encdb.mysql.jdbc.EncDriver");
Connection connection = DriverManager.getConnection(dbUrl, username, password);Option 3: URL parameter
Append MEK and ENC_ALGO directly to the JDBC URL:
String dbUrl = String.format(
"jdbc:mysql:encdb://%s:%s/%s?MEK=%s&ENC_ALGO=%s",
hostname, port, dbname, mek, encAlgo
);
Class.forName("com.aliyun.encdb.mysql.jdbc.EncDriver");
Connection connection = DriverManager.getConnection(dbUrl, username, password);Complete example
The following example uses JDBC properties to connect, insert rows into a table, and query the plaintext results.
// Replace the placeholders with your instance connection details.
String hostname = "hostname";
String port = "port";
String dbname = "db";
String username = "user";
String password = "password";
// Use a strong, randomly generated MEK in production.
String mek = "00112233445566778899aabbccddeeff";
String encAlgo = "SM4_128_CBC";
Properties props = new Properties();
props.setProperty("user", username);
props.setProperty("password", password);
props.setProperty("MEK", mek);
props.setProperty("ENC_ALGO", encAlgo);
String dbUrl = String.format("jdbc:mysql:encdb://%s:%s/%s", hostname, port, dbname);
Class.forName("com.aliyun.encdb.mysql.jdbc.EncDriver");
Connection connection = DriverManager.getConnection(dbUrl, props);
int[] intData = {1, 2, 3, 4, 5, 6};
String[] strData = {"abc", "bcd", "1", "def", "efg", "fgi"};
// Create the table.
connection.createStatement().executeUpdate("drop table if exists test");
connection.createStatement().executeUpdate("create table test (a int, b text)");
// Insert rows using PreparedStatement.
// EncJDBC automatically encrypts values targeting encrypted columns.
for (int i = 0; i < 6; i++) {
PreparedStatement pstmt = connection.prepareStatement("insert into test values (?,?)");
pstmt.setInt(1, intData[i]);
pstmt.setString(2, strData[i]);
pstmt.executeUpdate();
}
// Query rows. EncJDBC automatically decrypts results before returning them.
ResultSet rs = connection.createStatement().executeQuery("select * from test");
while (rs.next()) {
for (int i = 0; i < rs.getMetaData().getColumnCount(); i++) {
System.out.print(rs.getString(i + 1));
System.out.print("\t");
}
System.out.print("\n");
}Expected output:
1 abc
2 bcd
3 cde
4 def
5 efg
6 fgiNote the following:
All reads and writes to encrypted columns go through
PreparedStatement. The driver automatically encrypts parameters and decrypts results—no changes to your query logic are required.Values passed to non-encrypted columns are not affected.
Troubleshooting
IllegalAccessError: cannot access class com.sun.crypto.provider.SunJCE
This error occurs because newer JDK versions restrict cross-module access by default. Add the following VM option when running your program:
--add-exports=java.base/com.sun.crypto.provider=ALL-UNNAMEDfailed in mek provision: gcmEncrypt error
This is a known issue with Oracle JDK. Use one of the following fixes:
Switch to Amazon Corretto — a drop-in OpenJDK distribution that does not have this issue.
Add the BouncyCastle security provider to Oracle JDK:
Locate your JDK installation directory.
Open
<jdk-path>/conf/security/java.security.In the
List of providers and their preference orderssection, add: ``security.provider.14=org.bouncycastle.jce.provider.BouncyCastleProvider``