文档

EncDB SDK

更新时间:
重要

本文中含有需要您注意的重要提示信息,忽略该信息可能对您的业务造成影响,请务必仔细阅读。

如果您希望使用全密态功能对数据库表中的被保护数据列进行加密,并且使用Java应用程序访问数据库,可以使用全密态客户端Java SDK模块EncDB SDK接入全密态数据库,接入操作便捷,能够降低使用全密态功能的成本。本文介绍如何通过EncDB SDK访问全密态数据库。

EncDB SDK支持可信密钥管理、端到端安全通信、数据加解密等功能,并提供了灵活的调用接口,应用可以根据业务逻辑需要灵活控制密态数据的处理过程。

前提条件

  • 已开通全密态功能,详情请参见开通全密态功能

  • 获取加密数据库连接信息。您首先需要获取加密数据库的连接信息,如域名(host)、端口(port)、数据库实例名(dbname)、用户名(username)、密码(password)等。

  • 配置数据保护规则。具体操作请参见配置数据保护规则

注意事项

  • 请保存好您设置的主密钥MEK

  • Java使用JDK 1.8或以上版本。

    说明

    本文中使用的Maven版本为3.9.2,使用的开发工具为IntelliJ IDEA Community Edition 2022.3.2

操作步骤

下载EncDB SDK库包及依赖配置

EncDB SDK库包

EncDB SDK支持任何兼容MySQL协议的客户端(例如社区版MySQL JDBC)。EncDB SDK下载地址:libencdb-1.2.13-SNAPSHOT.jar

Maven依赖配置

  1. 如果您的Java项目使用Maven构建,可以通过如下命令将上面的EncJDBC依赖包安装至您的本地仓库:

    mvn install:install-file -DgroupId=com.alibaba.encdb -DartifactId=<安装的Jar包名> -Dversion=<安装的Jar版本> -Dpackaging=jar -Dfile=<安装的Jar包文件名>

    例如:

    mvn install:install-file -DgroupId=com.alibaba.encdb -DartifactId=libencdb -Dversion=1.2.13-SNAPSHOT -Dpackaging=jar -Dfile=libencdb-1.2.13-SNAPSHOT.jar
  2. 在安装EncDB SDK依赖包的基础上,您需要在自己的Maven项目配置文件中加入以下依赖项:

    <dependencies>
       ...
       <dependency>
          <groupId>mysql</groupId>
          <artifactId>mysql-connector-java</artifactId>
          <version>您需要MySQL驱动版本(8.0.11~8.0.32)</version>
       </dependency>
       <dependency>
          <groupId>com.alibaba.encdb</groupId>
          <artifactId>libencdb</artifactId>
          <version>1.2.13-SNAPSHOT</version>
       </dependency>
       <!-- https://mvnrepository.com/artifact/org.bouncycastle/bcprov-jdk15on -->
       <dependency>
         <groupId>org.bouncycastle</groupId>
         <artifactId>bcprov-jdk15on</artifactId>
         <version>1.62</version>
       </dependency>
       <!-- https://mvnrepository.com/artifact/org.bouncycastle/bcpkix-jdk15on -->
       <dependency>
         <groupId>org.bouncycastle</groupId>
         <artifactId>bcpkix-jdk15on</artifactId>
         <version>1.62</version>
       </dependency>
       <dependency>
         <groupId>com.google.code.gson</groupId>
         <artifactId>gson</artifactId>
         <version>2.10.1</version>
       </dependency>
       <dependency>
         <groupId>com.google.guava</groupId>
         <artifactId>guava</artifactId>
         <version>24.1.1-jre</version>
       </dependency>
      <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-api</artifactId>
      <version>1.7.30</version>
    </dependency>
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-log4j12</artifactId>
      <version>1.7.30</version>
    </dependency>
       ...
    </dependencies>

通过全密态客户端查询(代码示例)

您需要在处理收发密文数据前,使用我们的EncDB SDK对数据进行加解密。在使用EncDB SDK时,您需要配置和您数据安全息息相关的参数,包括MEK(主密钥)、EncAlgo(加密算法)、KeyMgmtType(密钥管理类型)。

具体参数解释及取值示例如下:

参数

取值示例(字符串类型)

说明

MEK

00112233445566778899aabbccddeeff

用户主密钥,由用户自定义指定。

常见的生成方法有:密码生成工具(如openssl, openssl rand -hex 16)、编程语言中的random函数、或者从第三方密钥管理服务(KMS)获取。

取值范围:长度为16字节的16进制字符串,且长度为32个字符。

警告

用户主密钥是您访问加密数据的根凭据,出于安全考虑,全密态数据库不持有并管理您的主密钥,也不提供用户主密钥的生成和备份服务,您需要自行生成用户主密钥。一旦您丢失密钥,将无法再访问已有的数据。因此我们建议您妥善备份用户主密钥。

EncAlgo

SM4_128_GCM

指明被保护数据将要使用的加密算法。

取值范围:

  • 国际算法:

    • AES_128_GCM

    • AES_128_CTR

    • AES_128_CBC

    • AES_128_ECB(不推荐)

  • 国密算法:

    • SM4_128_GCM(默认)

    • SM4_128_CTR

    • SM4_128_CBC

    • SM4_128_ECB(不推荐)

说明
  • AES_128_ECB和SM4_128_ECB加密算法安全性较弱,请谨慎使用,推荐适用其他安全性更高的加密算法。

  • 可选,默认为SM4_128_GCM。

KeyMgmtType

RDS_MYSQL

设置全密态密钥管理类型,对于指定数据库类型值是固定的。

取值范围:

  • RDS_MYSQL:适用于RDS MySQL

  • POLARDB_MYSQL:适用于PolarDB MySQL(连接Proxy的情况下)

  • PG:适用于RDS PG和PolarDB PG模式下

  • KEYSTORE_SERVER:适用于服务化的密文元数据管理系统(即KeyStore)

SDK配置

EncDB SDK提供了对应的接口用户初始化SDK对象时配置对应的参数。通常您只需要配置主密钥(setMek)以及期望的加密算法(setEncAlgo),其他参数建议您使用默认缺省配置或者固定值。如下面所示:

// 准备好域名(hostname)、端口(port)、数据库实例名(dbname)、用户名(username)、密码(password)等连接信息
// ...

// 使用MySQL JDBC连接数据库
Class.forName("com.mysql.cj.jdbc.Driver");
String dbUrl = String.format("jdbc:mysql://%s:%s/%s", hostname, port, dbname);
Connection connection = DriverManager.getConnection(dbUrl, username, password);

// 初始化用户密钥,并获取加解密算子
String mek = "00112233445566778899aabbccddeeff";
Constants.EncAlgo encAlgo=Constants.EncAlgo.SM4_128_CBC;
Constants.KeyMgmtType keyMgmtType=Constants.KeyMgmtType.RDS_MYSQL;
EncdbSDK sdk = EncdbSDKBuilder.newInstance()
    .setKeyMgmtType(keyMgmtType)
    .setDbConnection(connection)
    .setMek(mek)
    .setEncAlgo(encAlgo)
    .build();
Cryptor cryptor = sdk.getCryptor();

// 调用加解密接口
// byte[] cipherBytes = cryptor.encrypt(...);
// XXX value = cryptor.decryptXXX(...):

// ... 发起查询 ...
说明

MEK及其他参数均在客户端本地进行处理、并以安全方式进行分发(信封加密)到服务端,始终保证MEK不泄露。

完整代码示例

以下示例是基于社区版MySQL JDBC和EncDB SDK构建的(需要在Maven依赖里额外引入MySQL JDBC),其中enc_int列配置为被保护字段。

// 以下域名(hostname)、端口(port)、数据库实例名(dbname)、用户名(username)、密码(password)等连接信息需要更新为您的实例信息
String hostname = "hostname";
String port = "port";
String dbname = "db";
String username = "user";
String password = "password";

// 使用MySQL JDBC连接数据库
Class.forName("com.mysql.cj.jdbc.Driver");
String dbUrl = String.format("jdbc:mysql://%s:%s/%s", hostname, port, dbname);
Connection connection = DriverManager.getConnection(dbUrl, username, password);

// 初始化用户密钥,并获取加解密算子
String mek = "00112233445566778899aabbccddeeff";
Constants.EncAlgo encAlgo=Constants.EncAlgo.SM4_128_CBC;
Constants.KeyMgmtType keyMgmtType=Constants.KeyMgmtType.RDS_MYSQL;
EncdbSDK sdk = EncdbSDKBuilder.newInstance()
    .setKeyMgmtType(keyMgmtType)
    .setDbConnection(connection)
    .setMek(mek)
    .setEncAlgo(encAlgo)
    .build();
Cryptor cryptor = sdk.getCryptor();

// 创建表并写入数据
connection.createStatement().executeUpdate("drop table if exists test");
connection.createStatement().executeUpdate("create table test (enc_int int)");
connection.createStatement().executeUpdate("insert into test values (1)");

// 发起查询
ResultSet rs = connection.createStatement().executeQuery("select * from test");
while (rs.next()) {
    for (int i = 0; i < rs.getMetaData().getColumnCount(); i++) {
        // 获取密文字节流
        byte[] cipher = rs.getBytes(i + 1);
        // 调用Cryptor.decrypt方法解密获取明文字节流
        byte[] plaintext = cryptor.decrypt(Base64.decode(new String(cipher, StandardCharsets.UTF_8)));
        
        // 输出,对比明密文
        System.out.println("明文:" + new String(plaintext) + ",密文:" + new String(cipher));
    }
    System.out.print("\n");
}

输出结果:

明文:1 密文:QmEA/4d0ROXfA3QeUZFiu7EdlvZy4Yaa+uDnyFHvFOnVK4dtgVIzjrYI54I=

相关API

EncDB SDK主要包含以下几个Java功能模块:

com.alibaba.encdb.crypto.EncdbSDKBuilder

为EncdbSDK类的构造类。

// 获取一个新的EncdbSDKBuilder实例。您总是应该用这个方法来构造EncdbSDKBuilder。
EncdbSDKBuilder newInstance();
// (必选)设置一个数据库连接,用于全密态相关的密钥管理动作。这个数据库连接可以独立于业务中实际用到的数据库连接。
EncdbSDKBuilder setDbConnection(java.sql.Connection dbConnection);
// (必选)设置全密态密钥管理类型
EncdbSDKBuilder setKeyMgmtType(KeyMgmtType kmType);
// (必选)设置用户主密钥
EncdbSDKBuilder setMek(byte[] mek);
EncdbSDKBuilder setMek(String mek);
// (可选)设置加密算法
EncdbSDKBuilder setEncAlgo(EncAlgo encAlgo);
// 在完成上述设置之后,构造一个EncdbSDK对象
EncdbSDK build();

com.alibaba.encdb.EncdbSDK

提供可信密钥管理、端到端安全通信功能。

// 获取一个Cryptor对象,用于操作密文/明文。
Cryptor getCryptor();

com.alibaba.encdb.Cryptor

提供密码计算功能。

// 输入密文,返回对应的明文。注意:您需要自行将解密结果转换成目标数据类型。
byte[] decrypt(byte[] val);

常见问题

  • Q:运行程序时报错Exception in thread "main" java.lang.IllegalAccessError: class com.alibaba.encdb.common.SymCrypto (in unnamed module @0x5c0369c4) cannot access class com.sun.crypto.provider.SunJCE (in module java.base) because module java.base does not export com.sun.crypto.provider to unnamed module @0x5c0369c4,如何处理?

    A: 该报错可能是因为您的JDK版本较高导致的模块间权限问题,请在运行时添加VM option参数--add-exports=java.base/com.sun.crypto.provider=ALL-UNNAMED将com.sun.crypto.provider导出给Unnamed模块,以解决访问权限问题。

  • Q:运行程序时报错failed in mek provision: you might have an incorrect mek setting. Detail:gcmEncrypt error,如何处理?

    A:该问题常见于Oracle系列的JDK,如需解决此问题,您可以任选如下两种方式之一:

    • 使用Amazon Correto系列的JDK。

    • 仍然使用Oracle系列的JDK,但需要手动配置Security provider。具体步骤如下:

      1. 找到JDK的安装路径。

      2. 安装路径/conf/security/路径下,找到java.security文件。

      3. 编辑java.security文件,在List of providers and their preference orders (see above):区域,补充如下内容:

        security.provider.14=org.bouncycastle.jce.provider.BouncyCastleProvider
  • 本页导读 (1)