加密 SDK(Encryption SDK)是一个客户端密码库,提供了数据、文件流加解密等功能,旨在帮助客户专注于应用程序的核心功能,而不用关心数据加密和解密的实现过程。
SDK 支持 KMS 密钥环、本地密钥环加解密等多种加解密方式,并能够支持 KMS 跨地域级的容灾。用户只需调用加解密接口即可轻松实现数据、文件流加解密。
数据加解密实现过程由 Encryption SDK 进行封装,用户仅需提供主密钥信息相关必要信息和调用加解密接口可实现本地海量数据加解密。
默认情况下(未使用数据密钥缓存),Encryption SDK为它加密的每个数据对象生成唯一的数据密钥,遵循在每个加密操作中使用唯一数据密钥的加密最佳实践。
Encryption SDK 集成了华为云 KMS 服务,可以指定由华为云 KMS 生成的数据加密密钥,并由主密钥加密保护。华为云 KMS 通过使用硬件安全模块 HSM(Hardware Security Module, HSM)保护密钥的安全,所有的用户主密钥(MasterKey)都由 HSM 中的根密钥保护,避免主密钥泄露,满足安全与合规要求。
Encryption SDK 支持用户本地提供主密钥进行数据加解密。
Encryption SDK 同时支持对称加密和非对称加密算法,不同填充类型,具体算法支持 AES、RSA、国密 SM2 和 SM4 等加密方式。
Encryption SDK 具备 DEK 缓存管理功能,将 DEK 缓存在本地,用户选择使用缓存机制能够有效降低加密过程中导致的性能损耗。同时,缓存提供了最大使用次数,最大使用字节数,过期时间三个参数限定每一个数据密钥的使用,使数据密钥的不定期轮换,提高加解密的安全性。
Encryption SDK 支持同时使用多个主密钥进行数据加解密,数据加解密可指定多个 KMS 主密钥(建议指定不同region的 KMS),任意 KMS 均可解密 DEK 从而对数据进行解密,从而保证数据跨地域可用和灾备能力。
1.下载sdk代码,编译打包
git clone https://github.com/HuaweiCloudDeveloper/huaweicloud-encryption-sdk-java.git
cd EncryptionSDK
mvn clean install -DskipTests2.项目中添加打包依赖
<dependency>
<groupId>com.huaweicloud.sdk</groupId>
<artifactId>huaweicloud-encryption-sdk-java</artifactId>
<!-- 具体版本号依代码为准 -->
<version>1.0.16</version>
</dependency>
3.参照 examples 目录下的示例代码使用加密 SDK
package com.huaweicloud.encryptionsdk.example;
import com.huaweicloud.encryptionsdk.HuaweiConfig;
import com.huaweicloud.encryptionsdk.HuaweiCrypto;
import com.huaweicloud.encryptionsdk.keyrings.KmsKeyringFactory;
import com.huaweicloud.encryptionsdk.keyrings.kmskeyring.KMSKeyring;
import com.huaweicloud.encryptionsdk.model.CryptoResult;
import com.huaweicloud.encryptionsdk.model.KMSConfig;
import com.huaweicloud.encryptionsdk.model.enums.CryptoAlgorithm;
import com.huaweicloud.encryptionsdk.model.enums.KeyringTypeEnum;
import com.huaweicloud.encryptionsdk.model.request.EncryptRequest;
import com.huaweicloud.encryptionsdk.util.CommonUtils;
import org.apache.commons.lang3.Validate;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.List;
import java.util.Map;
/**
* @description: 本示例演示使用 KMSDiscoveryKeyring 密钥环进行加密文件,然后解密文件。
* </p>
* 使用 KMSDiscoveryKeyring 密钥环进行解密无需再传递 keyId,regionId,projectId 等信息,仅需ak,sk即可。
* </p>
* 你需要提供访问华为云 KMS 的 ak、sk 作为环境变量,以及可使用的 KMS 对称主密钥所属的 projectId、region、keyId 和纯文本字符串作为参数。
*/
public class KmsDiscoveryEncryptionExample {
private static final Logger LOGGER = LoggerFactory.getLogger(KmsEncryptionExample.class);
public static void main(String[] args) {
// 1. 获取环境变量中的 ak、sk
// 用于鉴权的AK、SK硬编码或明文存储,存在极大安全隐患。AK/SK在配置文件或环境变量中建议密文存储,在使用过程中进行解密,以保证安全。
// 本例中,AK和SK保存在环境变量中,用于鉴权认证。在执行本示例前,需要在本地环境中设置环境变量:CLOUD_SDK_AK和CLOUD_SDK_SK。
String ak = System.getenv("CLOUD_SDK_AK");
String sk = System.getenv("CLOUD_SDK_SK");
// 2. 获取参数传入的 KMS 对称主密钥所属的 projectId、region、keyId 和纯文本字符串
String projectId = args[0];
String region = args[1];
String keyId = args[2];
String endpoint = args[3];
// 待加密文件路径,精确到文件
String originFilePath = args[4];
// 加密后的文件路径,精确到文件
String targetEncryptFilePath = args[5];
// 解密后的文件路径,精确到文件
String targetDecryptFilePath = args[6];
// 3. KMS 配置基本信息:封装 region,keyId,projectId 信息(可支持多个 region,此处仅设置一个 region 信息)
List<KMSConfig> kmsConfigList = Collections.singletonList(new KMSConfig(region, keyId, projectId, endpoint));
// 4. 初始化 KMS 相关信息及设置加密算法
HuaweiConfig huaweiConfig = HuaweiConfig.builder()
.sk(sk)
.ak(ak)
.kmsConfigList(kmsConfigList)
.cryptoAlgorithm(CryptoAlgorithm.AES_256_GCM_NOPADDING)
// 开启discover密钥环
.isDiscovery(true)
.build();
// 5. 选择 KMS 密钥环类型
KMSKeyring keyring = new KmsKeyringFactory().getKeyring(KeyringTypeEnum.KMS_MULTI_REGION.getType());
// 6. 使用上述配置及密钥环信息初始化加密 SDK
HuaweiCrypto huaweiCrypto = new HuaweiCrypto(huaweiConfig).withKeyring(keyring);
// 7. 创建加密上下文(大多数加密数据都应该有一个关联的加密上下文来保护完整性)
Map<String, String> map = CommonUtils.getEncryptoMap();
// 8. 加密数据
huaweiCrypto.encrypt(originFilePath, targetEncryptFilePath, map);
LOGGER.info("The file encryption is complete. Origin file: {}; Encrypted file: {}.", originFilePath, targetEncryptFilePath);
// 9. 构建 KMS discovery 解密 SDK(无需再传递 keyId,regionId,projectId 等信息)
HuaweiConfig huaweiConfigDiscovery = HuaweiConfig.builder().sk(sk).ak(ak).build();
KMSKeyring keyringDiscovery = new KmsKeyringFactory().getKeyring(KeyringTypeEnum.KMS_DISCOVERY.getType());
HuaweiCrypto huaweiCryptoDecrypt = new HuaweiCrypto(huaweiConfigDiscovery).withKeyring(keyringDiscovery);
// 10. 解密数据
huaweiCryptoDecrypt.decrypt(targetEncryptFilePath, targetDecryptFilePath);
LOGGER.info("The file decryption is complete. Encrypted file: {}; Decrypted file: {}.", targetEncryptFilePath, targetDecryptFilePath);
// 11. 验证解密后的数据是否和原始纯文本字符串一致
Validate.isTrue(compareFile(originFilePath, targetDecryptFilePath));
}
/**
* 对比2个路径文件内容是否一致
* @param sourceFilePath 源文件路劲
* @param targetFilePath 目标文件路径
* @return 一致返回 true,否则返回 false
*/
public static boolean compareFile(String sourceFilePath, String targetFilePath) {
File sourceFile = new File(sourceFilePath);
File targetFile = new File(targetFilePath);
if (sourceFile.length() != targetFile.length()) {
return false;
}
try (FileInputStream sourceStream = new FileInputStream(sourceFile);
FileInputStream targetStream = new FileInputStream(sourceFile)) {
byte[] sourceBytes = new byte[1024];
byte[] targetBytes = new byte[1024];
int sourceBytesRead;
int targetBytesRead;
while ((sourceBytesRead = sourceStream.read(sourceBytes)) != -1) {
targetBytesRead = targetStream.read(targetBytes);
if (sourceBytesRead != targetBytesRead || !isEqual(sourceBytes, targetBytes, sourceBytesRead)) {
return false;
}
}
} catch (Exception e) {
LOGGER.error(e.getMessage());
}
return true;
}
/**
* 对比 2 个字节数组的前 n 个字节是否一致
* @param sourceBytes 源字节数组
* @param targetBytes 目标字节数组
* @param bytesRead 需要对比字节个数
* @return 一致返回 true,否则返回 false
*/
public static boolean isEqual(byte[] sourceBytes, byte[] targetBytes, int bytesRead) {
for (int i = 0; i < bytesRead; i++) {
if (sourceBytes[i] != targetBytes[i]) {
return false;
}
}
return true;
}
}你可以在 examples 目录查看更多示例代码。
密钥胶囊是一种基于接入点策略的加密方式,支持 ECS、CCE 和自定义接入点类型,通过策略控制数据密钥的生成与解密权限。
import com.huaweicloud.encryptionsdk.HuaweiConfig;
import com.huaweicloud.encryptionsdk.HuaweiCrypto;
import com.huaweicloud.encryptionsdk.keyrings.KmsKeyringFactory;
import com.huaweicloud.encryptionsdk.keyrings.kmskeyring.KMSKeyring;
import com.huaweicloud.encryptionsdk.model.*;
import com.huaweicloud.encryptionsdk.model.enums.CryptoAlgorithm;
import com.huaweicloud.encryptionsdk.model.enums.KeyringTypeEnum;
import com.huaweicloud.encryptionsdk.model.request.EncryptRequest;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
public class KeyCapsuleExample {
public static void main(String[] args) {
// 1. 获取环境变量中的 ak、sk
String ak = System.getenv("CLOUD_SDK_AK");
String sk = System.getenv("CLOUD_SDK_SK");
// 2. KMS 配置
List<KMSConfig> kmsConfigList = Collections.singletonList(
new KMSConfig("cn-north-7", "your_key_id", "your_project_id", "https://kms.cn-north-7.myhuaweicloud.com")
);
// 3. 接入点配置
AccessPointConfig accessPointConfig = AccessPointConfig.builder()
.type(2) // 1:ECS, 2:Custom, 3:CCE
.encryptedPrivateKey("your_encrypted_private_key")
.privateKeyDecryptCallback(encryptedKey -> {
// 用户实现回调解密私钥,返回 Base64 格式的明文私钥
return "your_plain_private_key";
})
.build();
// 4. 密钥胶囊配置
KeyCapsuleConfig keyCapsuleConfig = KeyCapsuleConfig.builder()
.region("cn-north-7")
.defaultPolicyId("your_policy_id")
.defaultKeyPolicy(null) // 可选,优先使用 defaultPolicyId
.accessPointConfig(accessPointConfig)
.build();
// 5. 构建加密配置
HuaweiConfig config = HuaweiConfig.builder()
.ak(ak)
.sk(sk)
.cryptoAlgorithm(CryptoAlgorithm.AES_256_GCM_NOPADDING)
.kmsConfigList(kmsConfigList)
.keyCapsuleConfig(keyCapsuleConfig)
.build();
// 6. 创建密钥胶囊密钥环并初始化 SDK
KMSKeyring keyring = new KmsKeyringFactory().getKeyring(KeyringTypeEnum.KMS_KEY_CAPSULE.getType());
HuaweiCrypto encryptCrypto = new HuaweiCrypto(config).withKeyring(keyring);
// 7. 加密
EncryptRequest encryptRequest = new EncryptRequest();
encryptRequest.setPlainText("Hello, Key Capsule!".getBytes(StandardCharsets.UTF_8));
CryptoResult<byte[]> result = encryptCrypto.encrypt(encryptRequest);
// 8. 构建解密配置(解密无需 kmsConfigList)
HuaweiConfig decryptConfig = HuaweiConfig.builder()
.ak(ak)
.sk(sk)
.keyCapsuleConfig(keyCapsuleConfig)
.build();
KMSKeyring decryptKeyring = new KmsKeyringFactory().getKeyring(KeyringTypeEnum.KMS_KEY_CAPSULE.getType());
HuaweiCrypto decryptCrypto = new HuaweiCrypto(decryptConfig).withKeyring(decryptKeyring);
// 9. 解密
CryptoResult<byte[]> decryptResult = decryptCrypto.decrypt(result.getResult());
System.out.println(new String(decryptResult.getResult(), StandardCharsets.UTF_8));
// 10. 关闭HuaweiCrypto
encryptCrypto.close();
decryptCrypto.close();
}
}| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| region | String | 是 | KMS 区域,如 cn-north-7 |
| keyId | String | 是 | KMS 对称主密钥 ID |
| projectId | String | 是 | 项目 ID |
| endpoint | String | 是 | KMS 端点,如 https://kms.cn-north-7.myhuaweicloud.com |
支持多个 region,加密时按顺序选择:
List<KMSConfig> kmsConfigList = Arrays.asList(
new KMSConfig("cn-north-7", "key_id_1", "project_id_1", "https://kms.cn-north-7.myhuaweicloud.com"),
new KMSConfig("cn-south-1", "key_id_2", "project_id_2", "https://kms.cn-south-1.myhuaweicloud.com")
);重要:
KeyCapsuleConfig.region必须是kmsConfigList中已配置的 region。KMSConfig支持配置多个 region,但KeyCapsuleConfig只能配置一个 region,且该 region 必须在kmsConfigList中存在。
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| type | int | 是 | 接入点类型:1=ECS,2=Custom(通用),3=CCE |
| encryptedPrivateKey | String | 是 | 加密的私钥(Base64 编码) |
| privateKeyDecryptCallback | PrivateKeyDecryptCallback | 是 | 私钥解密回调,用户实现解密逻辑 |
| serviceAccount | String | 否 | CCE 场景的 ServiceAccount 名称(已废弃,SDK 自动从 /var/run/secrets/kubernetes.io/serviceaccount/token 读取 service token) |
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| region | String | 是 | 创建/解密密钥胶囊的 region |
| defaultPolicyId | String | 否 | 默认策略 ID(EncryptRequest 未指定策略时使用) |
| defaultKeyPolicy | String | 否 | 默认内联策略 JSON(优先级低于 defaultPolicyId) |
| accessPointConfig | AccessPointConfig | 是 | 接入点配置 |
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| ak | String | 是 | 华为云 Access Key |
| sk | String | 是 | 华为云 Secret Key |
| cryptoAlgorithm | CryptoAlgorithm | 是 | 加密算法(加密时必填,解密时自动从密文头解析) |
| kmsConfigList | List<KMSConfig> | 加密必填 | KMS 配置列表(解密时无需传入) |
| keyCapsuleConfig | KeyCapsuleConfig | 是 | 密钥胶囊配置 |
| logConfig | LogConfig | 否 | LTS 日志上报配置 |
| localLogOnly | boolean | 否 | 是否仅本地打印日志(不上报 LTS),默认 false |
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| plainText | byte[] | 是 | 待加密的明文 |
| policyId | String | 否 | 本次加密使用的策略 ID(覆盖 defaultPolicyId) |
| keyPolicy | String | 否 | 本次加密使用的内联策略 JSON(覆盖 defaultKeyPolicy) |
| 枚举值 | 说明 |
|---|---|
CryptoAlgorithm.AES_128_GCM_NOPADDING |
AES-128-GCM |
CryptoAlgorithm.AES_256_GCM_NOPADDING |
AES-256-GCM |
CryptoAlgorithm.SM4_128_GCM_NOPADDING |
SM4-128-GCM |
CryptoAlgorithm.SM4_128_CBC_PADDING |
SM4-128-CBC-PKCS5 |
LogConfig logConfig = LogConfig.builder()
.logGroupName("DSC")
.logStreamName("crypto_operation_log")
.region("cn-north-7")
.projectId("your_project_id")
.batchCountThreshold(1000)
.lingerMs(30000)
.batchSizeThresholdInBytes(524288)
.ioThreadCount(4)
.totalSizeInBytes(104857600)
.maxBlockMs(0)
.retries(5)
.baseRetryBackoffMs(100)
.maxRetryBackoffMs(500)
.backupDir("/home/logbackup")
.enableRecoveryOnStartup(true)
.recoveryBatchSize(1000)
.recoveryBatchInterval(1000)
.build();
HuaweiConfig config = HuaweiConfig.builder()
.ak(ak).sk(sk)
.cryptoAlgorithm(CryptoAlgorithm.AES_256_GCM_NOPADDING)
.kmsConfigList(kmsConfigList)
.keyCapsuleConfig(keyCapsuleConfig)
.logConfig(logConfig)
.build();HuaweiConfig config = HuaweiConfig.builder()
.ak(ak).sk(sk)
.cryptoAlgorithm(CryptoAlgorithm.AES_256_GCM_NOPADDING)
.kmsConfigList(kmsConfigList)
.keyCapsuleConfig(keyCapsuleConfig)
.localLogOnly(true)
.build();| 字段 | 默认值 | 说明 |
|---|---|---|
| logGroupName | DSC |
日志组名称 |
| logStreamName | crypto_operation_log |
日志流名称 |
| region | - | LTS 服务区域(必填) |
| projectId | - | 项目 ID(必填) |
| batchCountThreshold | 1000 | 缓冲区记录条数阈值 |
| lingerMs | 30000 | 异步上报间隔(毫秒) |
| batchSizeThresholdInBytes | 524288 | 批量大小阈值(字节) |
| ioThreadCount | CPU 核数 | IO 线程数 |
| totalSizeInBytes | 104857600 | 缓冲区大小上限(100MB) |
| maxBlockMs | 0 | 发送阻塞时间(毫秒),0=不阻塞 |
| retries | 5 | 重试次数 |
| baseRetryBackoffMs | 100 | 首次重试退避时间(毫秒) |
| maxRetryBackoffMs | 500 | 最大重试退避时间(毫秒) |
| backupDir | ~/lts_log_backup |
失败日志备份目录 |
| enableRecoveryOnStartup | true | 启动时恢复失败日志 |
| recoveryBatchSize | 1000 | 恢复批量大小 |
| recoveryBatchInterval | 1000 | 恢复批次间隔(毫秒) |
LocalDataKeyCache localDataKeyCache = new LocalDataKeyCache();
localDataKeyCache.setCapacity(10);
CacheCryptoMeterialManager cacheManager = new CacheCryptoMeterialManager(localDataKeyCache, config);
cacheManager.setMaxByteLimit(3000);
cacheManager.setMaxMessageLimit(1000);
cacheManager.setSurvivalTime(5000);
crypto.withCryptoMeterialManager(cacheManager);| 配置项 | 默认值 | 说明 |
|---|---|---|
| capacity | - | 最大缓存容量,超出按 LRU 淘汰 |
| maxByteLimit | Long.MAX_VALUE | 单个数据密钥加密 byte 最大数量 |
| maxMessageLimit | Integer.MAX_VALUE | 单个数据密钥加密数据条数最大限制 |
| survivalTime | 1000000 | 缓存存活时间(毫秒) |
- AK/SK 不应硬编码在代码中,建议从环境变量或密钥管理服务获取
privateKeyDecryptCallback中应实现安全的私钥解密逻辑,避免明文存储私钥