
# 使用密钥胶囊进行加解密
#### 应用场景
对大型文件、图片等数据通过HTTPS请求到KMS服务进行保护时会消耗大量网络资源，降低加密效率。
#### 解决方案
加密SDK通过文件流分段信封加密的原理进行加密。
数据加密通过KMS生成的数据密钥在SDK内部进行，内存中分段加解密文件无需将数据通过网络传输后再进行加解密，保证了文件加密的安全性和正确性。
对于大型文件，SDK执行加密过程中，将文件分段读取到内存中，通过加解密写到目标文件后再进行下一段文件读取和加解密，直至完成整个文件的加解密。
#### **配置说明**
- KMSConfig（KMS 配置）
  
  | 字段        | 类型     | 必填 | 说明                                                 |
  |:---|:---|:---|:---|
  | region    | String | 是  | KMS区域，如cn-north-4                                  |
  | keyId     | String | 是  | KMS对称主密钥 ID                                        |
  | projectId | String | 是  | 项目ID                                               |
  | endpoint  | String | 是  | KMS终端节点，如 https://kms.cn-north-4.myhuaweicloud.com |
     
  支持多个 region，加密时按顺序选择：
  ```
  List<KMSConfig> kmsConfigList = Arrays.asList(
      new KMSConfig("cn-north-4", "key_id_1", "project_id_1", "https://kms.cn-north-4.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中存在。
  

- AccessPointConfig（接入点配置）
  
  | 字段                        | 类型                        | 必填            | 说明                                                                                                                                                                                                                                                                                                                                                                                                                                     |
  |:---|:---|:---|:---|
  | type                      | int                       | 是             | 接入点类型： - 1=ECS  - 2=Custom（通用）  - 3=CCE   |
  | encryptedPrivateKey       | String                    | 否（type=2时，必填） | 加密的私钥（Base64 编码）                                                                                                                                                                                                                                                                                                                                                                                                                       |
  | privateKeyDecryptCallback | PrivateKeyDecryptCallback | 否（type=2时，必填） | 私钥解密回调，用户实现解密逻辑，返回明文私钥的Base64 编码                                                                                                                                                                                                                                                                                                                                                                                                       |
     
  

- KeyCapsuleConfig（密钥胶囊配置）
  
  | 字段                | 类型                | 必填 | 说明                               |
  |:---|:---|:---|:---|
  | region            | String            | 是  | 创建/解密密钥胶囊的region                 |
  | defaultPolicyId   | String            | 是  | 默认策略ID（EncryptRequest 未指定策略时使用）  |
  | defaultKeyPolicy  | String            | 是  | 默认内联策略JSON（优先级高于defaultPolicyId） |
  | accessPointConfig | AccessPointConfig | 是  | 接入点配置                            |
     
  

- HuaweiConfig（全局配置）
  
  | 字段               | 类型                | 必填    | 说明                         |
  |:---|:---|:---|:---|
  | ak               | String            | 是     | 华为云Access Key              |
  | sk               | String            | 是     | 华为云Secret Key              |
  | cryptoAlgorithm  | CryptoAlgorithm   | 是     | 加密算法（加密时必填，解密时自动从密文头解析）    |
  | kmsConfigList    | List\<KMSConfig\> | 加密时必填 | KMS配置列表（解密时无需传入）           |
  | keyCapsuleConfig | KeyCapsuleConfig  | 是     | 密钥胶囊配置                     |
  | logConfig        | LogConfig         | 否     | LTS日志上报配置                  |
  | localLogOnly     | boolean           | 否     | 是否仅本地打印日志（不上报 LTS），默认false |
     
  

- EncryptRequest（加密请求）
  
  | 字段        | 类型       | 必填 | 说明                                  |
  |:---|:---|:---|:---|
  | plainText | byte\[\] | 是  | 待加密的明文                              |
  | policyId  | String   | 否  | 本次加密使用的策略ID（覆盖defaultPolicyId）      |
  | keyPolicy | String   | 否  | 本次加密使用的内联策略JSON（覆盖defaultKeyPolicy） |
     
  

- LTS 日志上报（可选）
  - 启用日志上报
    ```
    LogConfig logConfig = LogConfig.builder()
            .logGroupName("DSC")
            .logStreamName("crypto_operation_log")
            .region("cn-north-4")
            .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();
    ```
    
  
  - 仅本地打印日志（不上报 LTS）
    ```
    HuaweiConfig config = HuaweiConfig.builder()
            .ak(ak).sk(sk)
            .cryptoAlgorithm(CryptoAlgorithm.AES_256_GCM_NOPADDING)
            .kmsConfigList(kmsConfigList)
            .keyCapsuleConfig(keyCapsuleConfig)
            .localLogOnly(true)
            .build();
    ```
    
  
  - LogConfig 配置说明
    
    | 字段                        | 默认值                  | 说明               |
    |:---|:---|:---|
    | 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中应实现安全的私钥解密逻辑，避免明文存储私钥。
   
 
#### 操作步骤
1. 获取AK/SK： 
   - ACCESS_KEY：华为账号Access Key，获取方式请参见[获取AK/SK](https://support.huaweicloud.com/iam_faq/iam_01_0618.html)。
   
   - SECRET_ACCESS_KEY：华为账号Secret Access Key，获取方式请参见[获取AK/SK](https://support.huaweicloud.com/iam_faq/iam_01_0618.html)。
   
   - PROJECT_ID：局点项目ID，获取方式请参见[获取项目ID](https://support.huaweicloud.com/api-iam/iam_17_0002.html)。
   
   - KMS_ENDPOINT：华为云KMS服务访问终端地址，获取方式请参见[终端节点](https://support.huaweicloud.com/api-dew/dew_02_0052.html#section2)。
   
   - 认证用的ak和sk直接写到代码中有很大的安全风险，建议在配置文件或者环境变量中密文存放，使用时解密，确保安全。
   
   - 本示例以ak和sk保存在环境变量中来实现身份验证为例，运行本示例前请先在本地环境中设置环境变量HUAWEICLOUD_SDK_AK和HUAWEICLOUD_SDK_SK。
   
   
   
   
2. 获取region相关信息。 
   1. [登录DEW服务控制台](https://console.huaweicloud.com/dew/?locale=zh-cn#/dew/)。
   
   2. 鼠标移动至右上方的用户名，在下拉列表中选择"我的凭证"。
   
   3. 获取"项目ID"(PROJECT_ID)和"项目"(REGION)。
      图1获取项目ID和项目   
      ![](https://support.huaweicloud.com/bestpractice-dew/zh-cn_image_0000002660200179.png "点击放大") 
   
   4. 单击页面左侧![](https://support.huaweicloud.com/bestpractice-dew/zh-cn_image_0000002684593997.png "点击放大")，选择"安全与合规 \> 密码安全中心 DEW"，默认进入"密钥管理"界面。
   
   5. 获取当前Region需要使用的主密钥ID（KEYID）。
      图2获取主密钥ID
      ![](https://support.huaweicloud.com/bestpractice-dew/zh-cn_image_0000002660200181.png "点击放大")
      
      
   
   6. 获取当前Region需要使用的终端节点（ENDPOINT）。 终端节点（Endpoint）即调用API的**请求地址** ，不同服务不同区域的终端节点不同，您可以从[地区和终端节点](https://developer.huaweicloud.com/endpoint?DEW)中查询服务的终端节点。
      图3获取终端节点   
      ![](https://support.huaweicloud.com/bestpractice-dew/zh-cn_image_0000002630040910.png "点击放大") 
   
   
   
   
3. 加解密。 
   ```
   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. 鉴权信息（建议从环境变量获取）
           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 crypto = new HuaweiCrypto(config).withKeyring(keyring);
           // 7. 加密
           EncryptRequest encryptRequest = new EncryptRequest();
           encryptRequest.setPlainText("Hello, Key Capsule!".getBytes(StandardCharsets.UTF_8));
           CryptoResult<byte[]> result = crypto.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));
       }
   }
   ```
   
   
 
