

本文属于机器翻译版本。若本译文内容与英语原文存在差异，则一律以英文原文为准。

# 密钥环
<a name="keyrings"></a>


****  

|  | 
| --- |
| 我们的客户端加密库已重命名为 AWS 数据库加密 SDK。本开发人员指南仍提供有关 [DynamoDB 加密客户端](legacy-dynamodb-encryption-client.md)的信息。 | 

 AWS 数据库加密 SDK 使用*密钥环*来执行[信封加密](concepts.md#envelope-encryption)。密钥环生成、加密和解密数据密钥。密钥环确定保护每条加密记录的唯一数据密钥的来源，以及加密该数据密钥的[包装密钥](concepts.md#wrapping-key)。您在加密时指定一个密钥环，并在解密时指定相同或不同的密钥环。

您可以单独使用每个密钥环，也可以将多个密钥环合并为一个[多重密钥环](use-multi-keyring.md)。虽然大多数密钥环可以生成、加密和解密数据密钥，但您也可以创建只执行一项特定操作的密钥环，例如只生成数据密钥的密钥环，并将此密钥环与其他密钥环结合使用。

我们建议您使用可保护包装密钥并在安全边界内执行加密操作的密钥环，例如密 AWS KMS 钥环，它使用永不保密 [AWS Key Management Service](https://docs.aws.amazon.com/kms/latest/developerguide/)() AWS KMS keys AWS KMS的密钥环。您还可以编写一个使用封装密钥的密钥环，这些密钥存储在硬件安全模块 (HSMs) 中或受其他主密钥服务保护。

您的密钥环决定了哪些包装密钥保护您的数据密钥并最终保护您的数据。使用最安全且对您的任务实用的包装密钥。尽可能使用由硬件安全模块（HSM）或密钥管理基础设施保护的包装密钥，例如 [AWS Key Management Service](https://docs.aws.amazon.com/kms/latest/developerguide/)（AWS KMS）中的 KMS 密钥或 [AWS CloudHSM](https://docs.aws.amazon.com/cloudhsm/latest/userguide/) 中的加密密钥。

 AWS 数据库加密 SDK 提供了多种密钥环和密钥环配置，您可以创建自己的自定义密钥环。您也可以创建包含一个或多个相同或不同类型的密钥环的[多重密钥环](use-multi-keyring.md)。

**Topics**
+ [密钥环的工作方式](#using-keyrings)
+ [AWS KMS 钥匙圈](use-kms-keyring.md)
+ [AWS KMS 分层钥匙圈](use-hierarchical-keyring.md)
+ [AWS KMS ECDH 钥匙圈](use-kms-ecdh-keyring.md)
+ [原始 AES 密钥环](use-raw-aes-keyring.md)
+ [原始 RSA 密钥环](use-raw-rsa-keyring.md)
+ [未加工的 ECDH 钥匙圈](use-raw-ecdh-keyring.md)
+ [多重密钥环](use-multi-keyring.md)

## 密钥环的工作方式
<a name="using-keyrings"></a>


****  

|  | 
| --- |
| 我们的客户端加密库已重命名为 AWS 数据库加密 SDK。本开发人员指南仍提供有关 [DynamoDB 加密客户端](legacy-dynamodb-encryption-client.md)的信息。 | 

在对数据库中的字段进行加密和签名时， AWS 数据库加密 SDK 会要求密钥环提供加密材料。密钥环返回一个明文数据密钥、由密钥环中的每个包装密钥加密的数据密钥副本，以及与数据密钥关联的 MAC 密钥。 AWS 数据库加密 SDK 使用明文密钥对数据进行加密，然后尽快从内存中删除明文数据密钥。然后， AWS 数据库加密 SDK 会添加[材料描述](concepts.md#material-description)，其中包括加密的数据密钥和其他信息，例如加密和签名指令。 AWS 数据库加密 SDK 使用 MAC 密钥计算基于哈希的消息身份验证码 (HMACs)，而不是材料描述和所有标记为或的字段的规范化。`ENCRYPT_AND_SIGN` `SIGN_ONLY`

解密数据时，您可以使用加密数据所用的密钥环，也可以使用其他密钥环。要解密数据，解密密钥环必须有权访问加密密钥环中的至少一个包装密钥。

 AWS 数据库加密 SDK 将材料描述中的加密数据密钥传递到密钥环，并要求密钥环解密其中任何一个。密钥环使用其包装密钥以解密一个加密的数据密钥，并返回明文数据密钥。 AWS 数据库加密 SDK 使用明文数据密钥将对数据进行解密。如果密钥环中的所有包装密钥都无法解密任何加密的数据密钥，解密操作将失败。

您可以使用一个密钥环，也可以将相同类型或不同类型的密钥环组合到一个[多重密钥环](use-multi-keyring.md)中。当您加密数据时，多重密钥环返回数据密钥的副本，该数据密钥使用构成该多重密钥环的所有密钥环中的所有包装密钥和与数据密钥关联的 MAC 密钥加密。您可以使用包含多重密钥环中任一包装密钥的密钥环解密数据。

# AWS KMS 钥匙圈
<a name="use-kms-keyring"></a>


****  

|  | 
| --- |
| 我们的客户端加密库已重命名为 AWS 数据库加密 SDK。本开发人员指南仍提供有关 [DynamoDB 加密客户端](legacy-dynamodb-encryption-client.md)的信息。 | 

 AWS KMS 密钥环使用对称加密或非对称 RSA [AWS KMS keys](https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#master_keys)来生成、加密和解密数据密钥。 AWS Key Management Service (AWS KMS) 保护您的 KMS 密钥并在 FIPS 边界内执行加密操作。我们建议您尽可能使用 AWS KMS 密钥环或具有类似安全属性的密钥环。

您还可以在密钥环中使用对称多区域 KMS 密钥。 AWS KMS 有关使用多区域的更多详细信息和示例 AWS KMS keys，请参阅[使用多区域 AWS KMS keys](#config-mrks)。有关多区域密钥的信息，请参阅《AWS Key Management Service 开发人员指南**》中的[使用多区域密钥](https://docs.aws.amazon.com/kms/latest/developerguide/multi-region-keys-overview.html)。

AWS KMS 钥匙圈可以包括两种类型的包装钥匙：
+ **生成器密钥**：生成并加密明文数据密钥。加密数据的密钥环必须有一个生成器密钥。
+ **其他密钥**：加密生成器密钥生成的纯文本数据密钥。 AWS KMS 钥匙圈可以有零个或多个额外的钥匙。

您必须拥有生成器密钥才能加密记录。当 AWS KMS 密钥环只有一个 AWS KMS 密钥时，该密钥用于生成和加密数据密钥。

像所有钥匙圈一样， AWS KMS 钥匙圈可以单独使用，也可以与其他相同或不同[类型的钥匙圈一起在多](use-multi-keyring.md)钥匙圈中使用。

**Topics**
+ [AWS KMS 密钥环所需的权限](#kms-keyring-permissions)
+ [在 AWS KMS 钥匙圈 AWS KMS keys 中识别](#kms-keyring-id)
+ [创建密 AWS KMS 钥环](#kms-keyring-create)
+ [使用多区域 AWS KMS keys](#config-mrks)
+ [使用 AWS KMS 发现密钥环](#kms-keyring-discovery)
+ [使用 AWS KMS 区域发现密钥环](#kms-keyring-regional)

## AWS KMS 密钥环所需的权限
<a name="kms-keyring-permissions"></a>

 AWS 数据库加密 SDK 不需要 AWS 账户 ，也不依赖于任何一个 AWS 服务。但是，要使用 AWS KMS 密钥环，您需要对 AWS 账户 密钥环 AWS KMS keys 中的具有以下最低权限。
+ 要使用密 AWS KMS 钥环进行加密，您需要生成器[密钥的 kms: GenerateDataKey](https://docs.aws.amazon.com/kms/latest/APIReference/API_GenerateDataKey.html) 权限。您需要对密钥环中的所有其他密钥拥有 [kms: encrypt](https://docs.aws.amazon.com/kms/latest/APIReference/API_Encrypt.html) 权限。 AWS KMS 
+ 要使用密钥环进行解密，您需要对密 AWS KMS 钥环中的至少一个密钥具有 [kms: Decrypt](https://docs.aws.amazon.com/kms/latest/APIReference/API_Decrypt.html) 权限。 AWS KMS 
+ 要使用由密钥环组成的多密钥环进行加密，你需要获得生成器[密 AWS KMS 钥环中生成器密钥的 kms: GenerateDataKey](https://docs.aws.amazon.com/kms/latest/APIReference/API_GenerateDataKey.html) 权限。你需要对所有其他密钥环中的所有其他密钥具有 [kms: encrypt](https://docs.aws.amazon.com/kms/latest/APIReference/API_Encrypt.html) 权限。 AWS KMS 
+ 要使用非对称 RSA AWS KMS 密钥环进行加密，您不需要 kms[: GenerateDataKey](https://docs.aws.amazon.com/kms/latest/APIReference/API_GenerateDataKey.html) 或 [kms: E](https://docs.aws.amazon.com/kms/latest/APIReference/API_Encrypt.html) ncrypt，因为在创建密钥环时必须指定要用于加密的公钥材料。使用此密钥环加密时不会 AWS KMS 发出任何呼叫。[要使用非对称 RSA 密 AWS KMS 钥环进行解密，你需要 kms: Decrypt 权限。](https://docs.aws.amazon.com/kms/latest/APIReference/API_Decrypt.html)

有关权限的详细信息 AWS KMS keys，请参阅《*AWS Key Management Service 开发人员指南》*中的[身份验证和访问控制](https://docs.aws.amazon.com/kms/latest/developerguide/control-access.html)。

## 在 AWS KMS 钥匙圈 AWS KMS keys 中识别
<a name="kms-keyring-id"></a>

一个 AWS KMS 钥匙圈可以包括一个或多 AWS KMS keys个。要在 AWS KMS 密钥环 AWS KMS key 中指定，请使用支持的 AWS KMS 密钥标识符。可用于在密钥环 AWS KMS key 中识别的密钥标识符因操作和语言实现而异。有关 AWS KMS key密钥标识符的详细信息，请参阅《AWS Key Management Service 开发人员指南**》中的[密钥标识符](https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#key-id)。

作为最佳实践，请使用最适合您任务的密钥标识符。
+ 要使用密 AWS KMS 钥环进行加密，您可以使用[密钥 ID](https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#key-id-key-id)、密[钥 ARN](https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#key-id-key-ARN) [、别名或别名](https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#key-id-alias-name) [ARN](https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#key-id-alias-ARN) 来加密数据。
**注意**  
如果您在加密密钥环中为 KMS 密钥指定别名名称或别名 ARN，则加密操作会将当前与该别名关联的密钥 ARN 保存在加密数据密钥的元数据中。它不会保存别名。更改别名不会影响用于解密加密数据密钥的 KMS 密钥。
+ 要使用密 AWS KMS 钥环解密，必须使用密钥 ARN 进行识别。 AWS KMS keys有关更多信息，请参阅 [选择包装密钥](configure.md#config-keys)。
+ 在用于加密和解密的密钥环中，您必须使用密钥 ARN 以标识 AWS KMS keys。

解密时， AWS 数据库加密 SDK 会在密 AWS KMS 钥环中搜索 AWS KMS key 可以解密其中一个加密数据密钥的。具体而言， AWS 数据库加密 SDK 对材料描述中的每个加密数据密钥使用以下模式。
+  AWS 数据库加密 SDK 从材料描述的元数据 AWS KMS key 中获取加密数据密钥的密钥 ARN。
+  AWS 数据库加密 SDK 在解密密钥环中搜索密钥匹配的 AWS KMS key ARN。
+ 如果在密钥环中找到密钥 ARN 匹配的，则 AWS 数据库加密 SDK 会要求 AWS KMS 使用 KMS 密钥解密加密的数据密钥。 AWS KMS key 
+ 否则，它跳到下一个加密的数据密钥（如果有）。

## 创建密 AWS KMS 钥环
<a name="kms-keyring-create"></a>

您可以为每个 AWS KMS 密钥环配置一个 AWS KMS key 或多个 AWS KMS keys 相同或不同的密钥环 AWS 账户 。 AWS 区域 AWS KMS key 必须是对称加密密钥（`SYMMETRIC_DEFAULT`）或非对称 RSA KMS 密钥。您也可以使用对称加密[多区域 KMS 密钥](#config-mrks)。您可以在[多 AWS KMS](use-multi-keyring.md)密钥环中使用一个或多个钥匙圈。

您可以创建用于加密和解密数据的密 AWS KMS 钥环，也可以创建专门用于加密或解密的 AWS KMS 密钥环。创建用于加密数据的 AWS KMS 密钥环时，必须指定*生成器密钥*，该密钥用于生成纯文本数据密钥并对其进行加密。 AWS KMS key 数据密钥在数学上与 KMS 密钥无关。然后，如果您愿意，则可以指定用于加密相同纯文本数据密钥的其他 AWS KMS keys 内容。要解密受此密钥环保护的加密字段，您使用的解密密钥环必须至少包含密钥环中 AWS KMS keys 定义的密钥环中的一个，或者不是。 AWS KMS keys（没有的 AWS KMS 密钥环 AWS KMS keys 称为[AWS KMS 发现密钥环](#kms-keyring-discovery)。）

加密密钥环或多重密钥环中的所有包装密钥均必须能够加密数据密钥。如有任何包装密钥无法加密，此加密方法将失败。因此，调用方必须拥有密钥环中所有密钥的[所需权限](#kms-keyring-permissions)。如果您单独或在多重密钥环中使用 Discovery 密钥环加密数据，加密操作将失败。

以下示例使用该`CreateAwsKmsMrkMultiKeyring`方法创建具有对称加密 KMS AWS KMS 密钥的密钥环。该`CreateAwsKmsMrkMultiKeyring`方法会自动创建 AWS KMS 客户端，并确保密钥环能够正确处理单区域和多区域密钥。这些示例使用[密钥 ARNs](https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#key-id-key-ARN)来识别 KMS 密钥。有关详细信息，请参阅 [在 AWS KMS 钥匙圈 AWS KMS keys 中识别](#kms-keyring-id)

------
#### [ Java ]

```
final MaterialProviders matProv = MaterialProviders.builder()
        .MaterialProvidersConfig(MaterialProvidersConfig.builder().build())
        .build();
final CreateAwsKmsMrkMultiKeyringInput keyringInput = CreateAwsKmsMrkMultiKeyringInput.builder()
        .generator(kmsKeyArn)
        .build();
final IKeyring kmsKeyring = matProv.CreateAwsKmsMrkMultiKeyring(keyringInput);
```

------
#### [ C\$1 / .NET ]

```
var matProv = new MaterialProviders(new MaterialProvidersConfig());
var createAwsKmsMrkMultiKeyringInput = new CreateAwsKmsMrkMultiKeyringInput
{
    Generator = kmsKeyArn
};
var awsKmsMrkMultiKeyring = matProv.CreateAwsKmsMrkMultiKeyring(createAwsKmsMrkMultiKeyringInput);
```

------
#### [ Rust ]

```
let provider_config = MaterialProvidersConfig::builder().build()?;
let mat_prov = client::Client::from_conf(provider_config)?;
let kms_keyring = mat_prov
    .create_aws_kms_mrk_multi_keyring()
    .generator(kms_key_id)
    .send()
    .await?;
```

------

以下示例使用该`CreateAwsKmsRsaKeyring`方法创建带有非对称 RSA KMS AWS KMS 密钥的密钥环。要创建非对称 RSA AWS KMS 密钥环，请提供以下值。
+ `kmsClient`: 创建新 AWS KMS 客户端
+ `kmsKeyID`: 用于识别您的非对称 RSA KMS 密钥的密钥 ARN
+ `publicKey`: a 来 ByteBuffer 自 UTF-8 编码的 PEM 文件，该文件代表你传递给的密钥的公钥 `kmsKeyID`
+ `encryptionAlgorithm`: 加密算法必须是`RSAES_OAEP_SHA_256`或 `RSAES_OAEP_SHA_1`

------
#### [ Java ]

```
 final MaterialProviders matProv = MaterialProviders.builder()
    .MaterialProvidersConfig(MaterialProvidersConfig.builder().build())
    .build();
final CreateAwsKmsRsaKeyringInput createAwsKmsRsaKeyringInput =
    CreateAwsKmsRsaKeyringInput.builder()
        .kmsClient(KmsClient.create())
        .kmsKeyId(rsaKMSKeyArn)
        .publicKey(publicKey)
        .encryptionAlgorithm(EncryptionAlgorithmSpec.RSAES_OAEP_SHA_256)
        .build();
IKeyring awsKmsRsaKeyring = matProv.CreateAwsKmsRsaKeyring(createAwsKmsRsaKeyringInput);
```

------
#### [ C\$1 / .NET ]

```
var matProv = new MaterialProviders(new MaterialProvidersConfig());
var createAwsKmsRsaKeyringInput = new CreateAwsKmsRsaKeyringInput
{
    KmsClient = new AmazonKeyManagementServiceClient(),
    KmsKeyId = rsaKMSKeyArn,
    PublicKey = publicKey,
    EncryptionAlgorithm = EncryptionAlgorithmSpec.RSAES_OAEP_SHA_256
};
IKeyring awsKmsRsaKeyring = matProv.CreateAwsKmsRsaKeyring(createAwsKmsRsaKeyringInput);
```

------
#### [ Rust ]

```
let mpl_config = MaterialProvidersConfig::builder().build()?;
let mpl = mpl_client::Client::from_conf(mpl_config)?;
let sdk_config = aws_config::load_defaults(aws_config::BehaviorVersion::latest()).await;
let kms_rsa_keyring = mpl
    .create_aws_kms_rsa_keyring()
    .kms_key_id(rsa_kms_key_arn)
    .public_key(public_key)
    .encryption_algorithm(aws_sdk_kms::types::EncryptionAlgorithmSpec::RsaesOaepSha256)
    .kms_client(aws_sdk_kms::Client::new(&sdk_config))
    .send()
    .await?;
```

------

## 使用多区域 AWS KMS keys
<a name="config-mrks"></a>

您可以在 AWS 数据库加密 SDK 中使用多区域 AWS KMS keys 作为包装密钥。如果您使用多区域密钥合而为一进行加密 AWS 区域，则可以使用其他密钥中的相关多区域密钥进行解密。 AWS 区域

多区域 KMS 密钥是一组 AWS KMS keys AWS 区域 具有相同密钥材料和密钥 ID 的不同密钥。您可以像在不同区域使用相同的密钥一样使用这些*相关*密钥。多区域密钥支持常见的灾难恢复和备份场景，这些场景要求在一个区域进行加密，并在另一个区域进行解密，而无需进行跨区域调用。 AWS KMS有关多区域密钥的信息，请参阅《AWS Key Management Service 开发人员指南**》中的[使用多区域密钥](https://docs.aws.amazon.com/kms/latest/developerguide/multi-region-keys-overview.html)。

为了支持多区域密钥， AWS 数据库加密 SDK 包括密 AWS KMS multi-Region-aware 钥环。`CreateAwsKmsMrkMultiKeyring` 方法同时支持单区域密钥和多区域密钥。
+ 对于单区域密钥，该 multi-Region-aware符号的行为就像单 AWS KMS 区域密钥环一样。该密钥尝试仅使用加密数据的单区域密钥来解密加密文字。为了简化您的 AWS KMS 密钥环体验，我们建议您在使用对称加密 KMS 密钥时使用该`CreateAwsKmsMrkMultiKeyring`方法。
+ 对于多区域密钥，该 multi-Region-aware符号尝试使用加密数据的相同多区域密钥或您指定的区域中的相关多区域密钥来解密密文。

在使用多个 KMS 密 multi-Region-aware钥的密钥环中，您可以指定多个单区域和多区域密钥。但是，您只能在每组相关的多区域密钥中指定一个密钥。如果您使用相同的密钥 ID 指定多个密钥标识符，则构造函数调用将失败。

以下示例使用多区域 KMS AWS KMS 密钥创建密钥环。这些示例将多区域密钥指定为生成器密钥，将单区域密钥指定为子密钥。

------
#### [ Java ]

```
final MaterialProviders matProv = MaterialProviders.builder()
        .MaterialProvidersConfig(MaterialProvidersConfig.builder().build())
        .build();
final CreateAwsKmsMrkMultiKeyringInput createAwsKmsMrkMultiKeyringInput =
    CreateAwsKmsMrkMultiKeyringInput.builder()
            .generator(multiRegionKeyArn)
            .kmsKeyIds(Collections.singletonList(kmsKeyArn))
            .build();
IKeyring awsKmsMrkMultiKeyring = matProv.CreateAwsKmsMrkMultiKeyring(createAwsKmsMrkMultiKeyringInput);
```

------
#### [ C\$1 / .NET ]

```
var matProv = new MaterialProviders(new MaterialProvidersConfig());
var createAwsKmsMrkMultiKeyringInput = new CreateAwsKmsMrkMultiKeyringInput
{
    Generator = multiRegionKeyArn,
    KmsKeyIds = new List<String> { kmsKeyArn }
};
var awsKmsMrkMultiKeyring = matProv.CreateAwsKmsMrkMultiKeyring(createAwsKmsMrkMultiKeyringInput);
```

------
#### [ Rust ]

```
let mpl_config = MaterialProvidersConfig::builder().build()?;
let mpl = mpl_client::Client::from_conf(mpl_config)?;

let aws_kms_mrk_multi_keyring = mpl
    .create_aws_kms_mrk_multi_keyring()
    .generator(multiRegion_key_arn)
    .kms_key_ids(vec![key_arn.to_string()])
    .send()
    .await?;
```

------

使用多区域 AWS KMS 密钥环时，可以在严格模式或发现模式下解密密文。要在严格模式下解密密文，请在解密密文的区域中 multi-Region-aware使用相关多区域密钥的密钥 ARN 来实例化符号。如果您在其他区域（例如，加密记录的区域）中指定相关多区域密钥的密钥 ARN，则该 multi-Region-aware符号将为此进行跨区域调用。 AWS KMS key

在严格模式下解密时， multi-Region-aware符号需要密钥 ARN。仅接受每组相关的多区域密钥中的一个密钥 ARN。

您还可以在*发现模式*下使用 AWS KMS 多区域密钥进行解密。在发现模式下解密时，不需指定任何 AWS KMS keys。（有关单区域 AWS KMS 发现密钥环的信息，请参阅[使用 AWS KMS 发现密钥环](#kms-keyring-discovery)。）

如果您使用多区域密钥加密，则发现模式下的 multi-Region-aware符号将尝试使用本地区域中的相关多区域密钥进行解密。如果不存在，则调用失败。在发现模式下， AWS 数据库加密 SDK 不会尝试跨区域调用用于加密的多区域密钥。

## 使用 AWS KMS 发现密钥环
<a name="kms-keyring-discovery"></a>

解密时，最佳做法是指定 AWS 数据库加密 SDK 可以使用的包装密钥。要遵循此最佳实践，请使用 AWS KMS 解密密钥环，将 AWS KMS 封装密钥限制在您指定的密钥范围内。但是，您也可以创建*AWS KMS 发现密钥环*，即不指定任何包装 AWS KMS 密钥的密钥环。

 AWS 数据库加密 SDK 为 AWS KMS 多区域密钥提供了标准 AWS KMS 发现密钥环和发现密钥环。有关多区域密钥与 AWS 数据库加密 SDK 结合使用的信息，请参阅 [使用多区域 AWS KMS keys](#config-mrks)。

由于 Discovery 密钥环未指定任何包装密钥，因此 Discovery 密钥无法加密数据。如果您单独或在多重密钥环中使用 Discovery 密钥环加密数据，加密操作将失败。

解密时，发现密钥环允许 AWS 数据库加密 SDK 要求使用加密数据密钥 AWS KMS 来解密任何加密的数据密钥，无论谁拥有或有权访问该 AWS KMS key 密钥。 AWS KMS key只有在调用方拥有 AWS KMS key的 `kms:Decrypt` 权限时，调用才会成功。

**重要**  
如果您在解密多密钥环中包含 AWS KMS 发现密钥环，则发现密[钥环将覆盖多](use-multi-keyring.md)密钥环中其他密钥环中指定的所有 KMS 密钥限制。多重密钥环的行为类似于限制最少的密钥环。如果您单独或在多重密钥环中使用 Discovery 密钥环加密数据，加密操作将失败

为方便起见， AWS 数据库加密 SDK 提供了 AWS KMS 发现密钥环。不过，出于以下原因，建议尽可能使用更受限制的密钥环。
+ **真实性** — AWS KMS 发现密钥环可以使用任何 AWS KMS key 用于加密材料描述中的数据密钥的密钥，前提是调用者有权使用该密钥 AWS KMS key 进行解密。这可能不是呼叫 AWS KMS key 者打算使用的。例如，其中一个加密的数据密钥可能是在任何人都可以 AWS KMS key 使用的安全性较低的情况下加密的。
+ **延迟和性能** — AWS KMS 发现密钥环可能比其他密钥环慢得多，因为 AWS 数据库加密 SDK 会尝试解密所有加密的数据密钥，包括由 AWS KMS keys 其他 AWS 账户 和区域加密的数据密钥，而调用者无权使用这些密钥进行解密。 AWS KMS keys 

如果您使用发现密钥环，我们建议您使用[*发现过滤器*](configure.md#config-discovery)将可用的 KMS 密钥限制为指定 AWS 账户 和[分区](https://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html)中的密钥。如需帮助查找您的账户 ID 和分区，请参阅中的[您的 AWS 账户 标识符](https://docs.aws.amazon.com/general/latest/gr/acct-identifiers.html)和 [ARN 格式](https://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html#arns-syntax)。*AWS 一般参考*

以下代码示例使用发现过滤器实例化 AWS KMS 发现密钥环，该过滤器将 AWS 数据库加密 SDK 可以使用的 KMS 密钥限制为`aws`分区和`111122223333`示例账户中的密钥。

在使用此代码之前，请将示例 AWS 账户 和分区值替换为 AWS 账户 和分区的有效值。如果您的 KMS 密钥位于中国区域，请使用 `aws-cn` 分区值。如果您的 KMS 密钥位于 AWS GovCloud (US) Regions，请使用 `aws-us-gov` 分区值。对于所有其他 AWS 区域，请使用 `aws` 分区值。

------
#### [ Java ]

```
// Create discovery filter
DiscoveryFilter discoveryFilter = DiscoveryFilter.builder()
        .partition("aws")
        .accountIds(111122223333)
        .build();
// Create the discovery keyring
CreateAwsKmsMrkDiscoveryMultiKeyringInput createAwsKmsMrkDiscoveryMultiKeyringInput = CreateAwsKmsMrkDiscoveryMultiKeyringInput.builder()
        .discoveryFilter(discoveryFilter)
        .build();
IKeyring decryptKeyring = matProv.CreateAwsKmsMrkDiscoveryMultiKeyring(createAwsKmsMrkDiscoveryMultiKeyringInput);
```

------
#### [ C\$1 / .NET ]

```
// Create discovery filter
var discoveryFilter = new DiscoveryFilter
{
    Partition = "aws",
    AccountIds = 111122223333
};
// Create the discovery keyring
var createAwsKmsMrkDiscoveryMultiKeyringInput = new CreateAwsKmsMrkDiscoveryMultiKeyringInput
{
    DiscoveryFilter = discoveryFilter
};
var decryptKeyring = matProv.CreateAwsKmsMrkDiscoveryMultiKeyring(createAwsKmsMrkDiscoveryMultiKeyringInput);
```

------
#### [ Rust ]

```
// Create discovery filter
let discovery_filter = DiscoveryFilter::builder()
    .partition("aws")
    .account_ids(111122223333)
    .build()?;

// Create the discovery keyring
let decrypt_keyring = mpl
    .create_aws_kms_mrk_discovery_multi_keyring()
    .discovery_filter(discovery_filter)
    .send()
    .await?;
```

------

## 使用 AWS KMS 区域发现密钥环
<a name="kms-keyring-regional"></a>

*AWS KMS 区域发现密钥环*是一种不指定 KMS 密钥 ARNs 的密钥环。相反，它允许 AWS 数据库加密 SDK 仅使用 KMS 密钥进行解密。 AWS 区域

使用 AWS KMS 区域发现密钥环解密时， AWS 数据库加密 SDK 会解密在指定项下加密的所有加密数据密钥。 AWS KMS key AWS 区域要成功，调用者必须拥有对数据密钥 AWS KMS keys 中至少一个加密数据密钥 AWS 区域 的`kms:Decrypt`权限。

与其他 Discovery 密钥环相同，Regional Discovery 密钥环对加密无效。该密钥环仅在解密加密字段时适用。如果您在用于加密和解密的多重密钥环中使用 Regional Discovery 密钥环，则该密钥环仅在解密时有效。如果您单独或在多重密钥环中使用多区域 Discovery 密钥环加密数据，加密操作将失败。

**重要**  
如果您在解密多密钥环中包含 AWS KMS 区域发现密钥环，则区域发现密[钥环将覆盖多](use-multi-keyring.md)密钥环中其他密钥环中指定的所有 KMS 密钥限制。多重密钥环的行为类似于限制最少的密钥环。单独使用或在多重密钥环中使用时， AWS KMS Discovery 密钥环对加密无效。

 AWS 数据库加密 SDK 中的区域发现密钥环仅尝试使用指定区域中的 KMS 密钥进行解密。使用发现密钥环时，需要在 AWS KMS 客户端上配置区域。这些 AWS 数据库加密 SDK 实现不会按区域筛选 KMS 密钥，但对指定区域之外的 KMS 密钥的解密请求 AWS KMS 将失败。

如果您使用发现密钥环，我们建议您使用*发现过滤器*将解密中使用的 KMS 密钥限制为指定 AWS 账户 和分区中的密钥。

例如，以下代码使用发现过滤器创建 AWS KMS 区域发现密钥环。此密钥环将 AWS 数据库加密 SDK 限制为美国西部（俄勒冈）区域 (us-west-2) 账户 111122223333 中的 KMS 密钥。

------
#### [ Java ]

```
// Create the discovery filter
DiscoveryFilter discoveryFilter = DiscoveryFilter.builder()
        .partition("aws")
        .accountIds(111122223333)
        .build();
// Create the discovery keyring
CreateAwsKmsMrkDiscoveryMultiKeyringInput createAwsKmsMrkDiscoveryMultiKeyringInput = CreateAwsKmsMrkDiscoveryMultiKeyringInput.builder()
        .discoveryFilter(discoveryFilter)
        .regions("us-west-2")
        .build();
IKeyring decryptKeyring = matProv.CreateAwsKmsMrkDiscoveryMultiKeyring(createAwsKmsMrkDiscoveryMultiKeyringInput);
```

------
#### [ C\$1 / .NET ]

```
// Create discovery filter
var discoveryFilter = new DiscoveryFilter
{
    Partition = "aws",
    AccountIds = 111122223333
};
// Create the discovery keyring
var createAwsKmsMrkDiscoveryMultiKeyringInput = new CreateAwsKmsMrkDiscoveryMultiKeyringInput
{
    DiscoveryFilter = discoveryFilter,
    Regions = us-west-2
};
var decryptKeyring = matProv.CreateAwsKmsMrkDiscoveryMultiKeyring(createAwsKmsMrkDiscoveryMultiKeyringInput);
```

------
#### [ Rust ]

```
// Create discovery filter
let discovery_filter = DiscoveryFilter::builder()
    .partition("aws")
    .account_ids(111122223333)
    .build()?;

// Create the discovery keyring
let decrypt_keyring = mpl
    .create_aws_kms_mrk_discovery_multi_keyring()
    .discovery_filter(discovery_filter)
    .regions(us-west-2)
    .send()
    .await?;
```

------

# AWS KMS 分层钥匙圈
<a name="use-hierarchical-keyring"></a>


****  

|  | 
| --- |
| 我们的客户端加密库已重命名为 AWS 数据库加密 SDK。本开发人员指南仍提供有关 [DynamoDB 加密客户端](legacy-dynamodb-encryption-client.md)的信息。 | 

**注意**  
自 2023 年 7 月 24 日起，不支持在开发者预览期间创建的分支密钥。创建新的分支密钥以继续使用您在开发者预览版期间创建的密钥库。

使用 AWS KMS 分层密钥环，您可以在对称加密 KMS 密钥下保护您的加密材料，而无需在 AWS KMS 每次加密或解密记录时都调用。对于需要最大限度地减少调用的应用程序以及可以在不违反其安全要求的情况下重复使用某些加密材料的应用程序来说，这是一个不错的选择。 AWS KMS

分层密钥环是一种加密材料缓存解决方案，它使用 AWS KMS 保存在Amazon DynamoDB表中的受保护*分支密钥*，然后在本地缓存用于加密和解密操作的分支密钥材料，从而减少 AWS KMS 调用次数。DynamoDB 表用作管理和保护分支密钥的密钥存储。其存储活动分支密钥和分支密钥的所有先前版本。*活动*分支密钥为最新分支密钥版本。分层密钥环对每个加密请求使用唯一的数据加密密钥，并使用从活动分支密钥派生的唯一包装密钥对每个数据加密密钥进行加密。分层密钥环依赖在活动分支密钥及其派生包装密钥之间建立的层次结构。

分层密钥环通常使用各分支密钥版本满足多个请求。但是您可以控制活动分支密钥的重复使用程度，并确定活动分支密钥的轮换频率。在您[轮换](rotate-branch-key.md)之前，分支密钥的活动版本会一直处于活动状态。活动分支密钥的先前版本不会用于执行加密操作，但仍可查询并用于解密操作。

当您实例化分层密钥环时，分层密钥环会创建本地缓存。您可以指定[缓存限制](#cache-limit)，该限制定义了分支密钥材料在过期并从缓存中移出之前存储在本地缓存中的最长时间。首次在操作中指定 a `branch-key-id` 时，分层密钥环会 AWS KMS 调用解密分支密钥并组装分支密钥材料。然后，分支密钥材料存储在本地缓存中，并重复用于所有指定 `branch-key-id` 的加密和解密操作，直至缓存限制到期。将分支密钥材料存储在本地缓存中可以减少 AWS KMS 调用。例如，假设缓存限制为 15 分钟。如果您在该缓存限制内执行 10,000 次加密操作，则[传统 AWS KMS 密钥环](use-kms-keyring.md)需要进行 10,000 次 AWS KMS 调用才能满足 10,000 次加密操作。如果您有一个处于活动状态`branch-key-id`，则分层密钥环只需要进行一次 AWS KMS 调用即可满足 10,000 个加密操作。

本地缓存将加密材料与解密材料分开。加密材料由活动分支密钥组合而成，并在缓存限制到期之前重复用于所有加密操作。解密材料是根据在加密字段的元数据中标识的分支密钥 ID 和版本汇编而成的，在缓存限制到期之前，它们可以重复用于与分支密钥 ID 和版本相关的所有解密操作。本地缓存可以一次存储同一个分支密钥的多个版本。将本地缓存配置为使用时[branch key ID supplier](#branch-key-id-supplier)，它还可以同时存储来自多个活动分支密钥的分支密钥材料。

**注意**  
 AWS 数据库加密 SDK 中所有提及*分层密钥环*的内容均指 AWS KMS 分层密钥环。

**Topics**
+ [工作原理](#how-hierarchical-keyring-works)
+ [先决条件](#hierarchical-keyring-prereqs)
+ [所需的权限](#hierarchical-keyring-permissions)
+ [选择缓存](#hierarchical-keyring-caches)
+ [创建分层密钥环](#initialize-hierarchical-keyring)
+ [使用分层密钥环进行可搜索加密](#searchable-encryption-hierarchical-keyrings)

## 工作原理
<a name="how-hierarchical-keyring-works"></a>

以下演练描述了分层密钥环如何汇编加密和解密材料，以及密钥环对加密和解密操作的不同调用。有关包装密钥派生和明文数据密钥加密过程的技术详细信息，请参阅 [AWS KMS 分层密钥环技术详细信息](reference.md#hierarchical-keyring-details)。

**加密并签名**  
以下演练描述了分层密钥环如何汇编加密材料并派生出唯一的包装密钥。

1. 加密方法要求分层密钥环提供加密材料。密钥环生成纯文本数据密钥，然后检查本地缓存中是否有有效的分支密钥材料来生成包装密钥。如果存在有效的分支密钥材料，则密钥环将进入**步骤 4**。

1. 如果没有有效的分支密钥材料，则分层密钥环会在密钥库中查询活动分支密钥。

   1. 密钥库调用 AWS KMS 解密活动分支密钥并返回纯文本活动分支密钥。标识活动分支密钥的数据会进行序列化，以便在解密调用 AWS KMS时提供额外验证数据。

   1. 密钥库返回纯文本分支密钥和标识该密钥的数据，例如分支密钥版本。

1. 分层密钥环汇编分支密钥材料（明文分支密钥和分支密钥版本），并将其副本存储在本地缓存中。

1. 分层密钥环从明文分支密钥和一个 16 字节的随机加密盐中派生出唯一的包装密钥。其使用派生包装密钥加密明文数据密钥的副本。

此加密方法使用加密材料对记录进行加密和签名。有关如何在 AWS 数据库加密 SDK 中对记录进行加密和签名的更多信息，请参阅[加密和签名](how-it-works.md#encrypt-and-sign)。

**解密并验证**  
以下演练描述了分层密钥环如何汇编解密材料并解密加密数据密钥。

1. 该解密方法标识来自加密记录的材料描述字段中的加密数据密钥，并将其传递给分层密钥环。

1. 分层密钥环反序列化标识加密数据密钥的数据，包括分支密钥版本、16 字节的加密盐以及其他描述数据密钥加密方式的信息。

   有关更多信息，请参阅 [AWS KMS 分层钥匙圈技术细节](reference.md#hierarchical-keyring-details)。

1. 分层密钥环会检查本地缓存中是否存在与**步骤 2** 标识的分支密钥版本相匹配的有效分支密钥材料。如果存在有效分支密钥材料，则密钥环将进入**步骤 6**。

1. 如果没有有效的分支密钥材料，则分层密钥环会在密钥库中查询与**步骤 2** 中确定的分支密钥版本相匹配的分支密钥。

   1. 密钥库调用 AWS KMS 解密分支密钥并返回纯文本活动分支密钥。标识活动分支密钥的数据会进行序列化，以便在解密调用 AWS KMS时提供额外验证数据。

   1. 密钥库返回纯文本分支密钥和标识该密钥的数据，例如分支密钥版本。

1. 分层密钥环汇编分支密钥材料（明文分支密钥和分支密钥版本），并将其副本存储在本地缓存中。

1. 分层密钥环使用汇编的分支密钥材料和**步骤 2** 标识的 16 字节加密盐重现加密数据密钥的唯一包装密钥。

1. 分层密钥环使用重现的包装密钥解密数据密钥并返回明文数据密钥。

该解密方法使用解密材料和明文数据密钥解密和验证记录。有关如何在 AWS 数据库加密 SDK 中解密和验证记录的更多信息，请参阅[解密](how-it-works.md#decrypt-and-verify)和验证。

## 先决条件
<a name="hierarchical-keyring-prereqs"></a>

在创建和使用分层密钥环之前，请确保满足以下先决条件。
+ 您或您的密钥库管理员已[创建密钥库](create-keystore.md)并[创建了至少一个有效的分支密钥](create-branch-keys.md)。
+ 您已经[配置了密钥存储操作](keystore-actions.md#config-keystore-actions)。
**注意**  
如何配置密钥存储操作决定了您可以执行的操作以及分层密钥环可以使用哪些 KMS 密钥。有关更多信息，请参阅[密钥存储操作](keystore-actions.md)。
+ 您拥有访问和使用密钥库和分支密钥所需的 AWS KMS 权限。有关更多信息，请参阅 [所需的权限](#hierarchical-keyring-permissions)。
+ 您已经查看了支持的缓存类型并配置了最适合您需求的缓存类型。有关更多信息，请参阅 [选择缓存](#hierarchical-keyring-caches)。

## 所需的权限
<a name="hierarchical-keyring-permissions"></a>

 AWS 数据库加密 SDK 不需要 AWS 账户 ，也不依赖于任何一个 AWS 服务。但是，要使用分层密钥环，您需要对 AWS 账户 密钥库中的对称加密 AWS KMS key具有以下最低权限。
+ [要使用分层密钥环加密和解密数据，你需要 kms: Decrypt。](https://docs.aws.amazon.com/kms/latest/APIReference/API_Decrypt.html)
+ 要[创建](create-branch-keys.md)和[轮换](rotate-branch-key.md)分支密钥，你需要 k [ms: GenerateDataKeyWithoutPlaintext](https://docs.aws.amazon.com/kms/latest/APIReference/API_GenerateDataKeyWithoutPlaintext.html) 和 [kms: ReEncrypt](https://docs.aws.amazon.com/kms/latest/APIReference/API_ReEncrypt.html)。

有关控制对分支密钥和密钥库的访问权限的更多信息，请参阅[实施最低权限](keystore-least-privilege.md)。

## 选择缓存
<a name="hierarchical-keyring-caches"></a>

分层密钥环 AWS KMS 通过在本地缓存加密和解密操作中使用的分支密钥材料来减少调用的次数。在[创建分层密钥环](#initialize-hierarchical-keyring)之前，您需要决定要使用的缓存类型。您可以使用默认缓存或自定义缓存以最适合您的需求。

分层密钥环支持以下缓存类型：
+ [默认缓存](#cache-default)
+ [MultiThreaded 缓存](#cache-multithreaded)
+ [StormTracking 缓存](#cache-stormtracking)
+ [共享缓存](#cache-shared)

### 默认缓存
<a name="cache-default"></a>

对于大多数用户而言，默认缓存可满足其线程要求。默认缓存用于支持超多线程环境。当分支密钥材料条目过期时，默认缓存会 AWS KMS 提前 10 秒通知一个线程分支密钥材料条目将过期，从而防止多个线程调用。这样可以确保只有一个线程向发送刷新缓存的请求。 AWS KMS 

Default 和 StormTracking 缓存支持相同的线程模型，但您只需要指定入口容量即可使用 Default 缓存。要进行更精细的缓存自定义，请使用。[StormTracking 缓存](#cache-stormtracking)

除非要自定义可以存储在本地缓存中的分支密钥材料条目的数量，否则在创建分层密钥环时无需指定缓存类型。如果未指定缓存类型，则分层密钥环使用默认缓存类型并将条目容量设置为 1000。

要自定义默认缓存，请指定以下值：
+ **条目容量**：限制可以存储在本地缓存中的分支密钥材料条目的数量。

------
#### [ Java ]

```
.cache(CacheType.builder()
        .Default(DefaultCache.builder()
        .entryCapacity(100)
        .build())
```

------
#### [ C\$1 / .NET ]

```
CacheType defaultCache = new CacheType
{
    Default = new DefaultCache{EntryCapacity = 100}
};
```

------
#### [ Rust ]

```
let cache: CacheType = CacheType::Default(
    DefaultCache::builder()
        .entry_capacity(100)
        .build()?,
);
```

------

### MultiThreaded 缓存
<a name="cache-multithreaded"></a>

 MultiThreaded 缓存可在多线程环境中安全使用，但它不提供任何可最大限度减少 AWS KMS 或 Amazon DynamoDB 调用的功能。因此，当分支密钥材料条目到期时，所有线程均将同时收到通知。这可能会导致多次 AWS KMS 调用刷新缓存。

要使用 MultiThreaded 缓存，请指定以下值：
+ **条目容量**：限制可以存储在本地缓存中的分支密钥材料条目的数量。
+ **条目修剪尾部大小**：定义在达到条目容量时要修剪的条目数量。

------
#### [ Java ]

```
.cache(CacheType.builder()
        .MultiThreaded(MultiThreadedCache.builder()
        .entryCapacity(100)
        .entryPruningTailSize(1)                                        
        .build())
```

------
#### [ C\$1 / .NET ]

```
CacheType multithreadedCache = new CacheType
{
    MultiThreaded = new MultiThreadedCache
    {
        EntryCapacity = 100,
        EntryPruningTailSize = 1
    }
};
```

------
#### [ Rust ]

```
CacheType::MultiThreaded(
            MultiThreadedCache::builder()
                    .entry_capacity(100)
                    .entry_pruning_tail_size(1)
                    .build()?)
```

------

### StormTracking 缓存
<a name="cache-stormtracking"></a>

 StormTracking 缓存旨在支持大量多线程环境。当分支密钥材料条目过期时， StormTracking 缓存会提前通知一个线程分支密钥材料条目即将过期，从而防止多个线程调用 AWS KMS 。这样可以确保只有一个线程向发送刷新缓存的请求。 AWS KMS 



要使用 StormTracking 缓存，请指定以下值：
+ **条目容量**：限制可以存储在本地缓存中的分支密钥材料条目的数量。

  默认值：1000 个条目
+ **条目修剪尾部大小**：定义一次要修剪的分支密钥材料条目的数量。

  默认值：1 个条目
+ **宽限期**：定义在到期前尝试刷新分支密钥材料的秒数。

  默认值：10 秒
+ **宽限间隔**：定义两次尝试刷新分支密钥材料间隔的秒数。

  默认值：1 秒
+ **扇出**：定义可以同时尝试刷新分支密钥材料的次数。

  默认值：20 次尝试
+ **传输中生存时间（TTL）**：定义在分支密钥材料刷新尝试超时之前的秒数。每当缓存为响应 `GetCacheEntry` 而返回 `NoSuchEntry` 时，分支密钥均视为*传输中*，直至相同密钥与 `PutCache` 条目一起写入。

  默认值：10 秒
+ **睡眠**：定义超过 `fanOut` 时线程应睡眠的秒数。

  默认值：20 毫秒

------
#### [ Java ]

```
.cache(CacheType.builder()
        .StormTracking(StormTrackingCache.builder()
        .entryCapacity(100)
        .entryPruningTailSize(1)
        .gracePeriod(10)
        .graceInterval(1)
        .fanOut(20) 
        .inFlightTTL(10)
        .sleepMilli(20)                                        
        .build())
```

------
#### [ C\$1 / .NET ]

```
CacheType stormTrackingCache = new CacheType
{
    StormTracking = new StormTrackingCache
    {
        EntryCapacity = 100,
        EntryPruningTailSize = 1,
        FanOut = 20,
        GraceInterval = 1,
        GracePeriod = 10,
        InFlightTTL = 10,
        SleepMilli = 20
    }
};
```

------
#### [ Rust ]

```
CacheType::StormTracking(
                StormTrackingCache::builder()
                    .entry_capacity(100)
                    .entry_pruning_tail_size(1)
                    .grace_period(10)
                    .grace_interval(1)
                    .fan_out(20)
                    .in_flight_ttl(10)
                    .sleep_milli(20)
                    .build()?)
```

------

### 共享缓存
<a name="cache-shared"></a>

默认情况下，每次实例化密钥环时，分层密钥环都会创建一个新的本地缓存。但是，共享缓存允许您在多个分层密钥环之间共享缓存，从而有助于节省内存。共享缓存不是为您实例化的每个分层密钥环创建新的加密材料缓存，而是在内存中只存储一个缓存，供所有引用它的分层密钥环使用。共享缓存可避免在密钥环之间重复加密材料，从而帮助优化内存使用率。相反，分层密钥环可以访问相同的底层缓存，从而减少总体内存占用。

创建共享缓存时，仍需要定义缓存类型。您可以指定[默认缓存](#cache-default)[MultiThreaded 缓存](#cache-multithreaded)、或[StormTracking 缓存](#cache-stormtracking)作为缓存类型，也可以替换任何兼容的自定义缓存。



**分区**  
多个分层密钥环可以使用单个共享缓存。使用共享缓存创建分层密钥环时，可以定义可选的**分区 ID**。分区 ID 可区分哪个分层密钥环正在写入缓存。如果两个分层密钥环引用相同的分区 ID 和分支密钥 ID[logical key store name](create-keystore.md#logical-key-store-name)，则两个密钥环将在缓存中共享相同的缓存条目。如果您创建了两个具有相同共享缓存但分区不同的分层密钥环 IDs，则每个密钥环只能访问共享缓存中自己指定的分区中的缓存条目。分区充当共享缓存中的逻辑分区，允许每个分层密钥环在自己的指定分区上独立运行，而不会干扰存储在另一个分区中的数据。

如果您打算重复使用或共享分区中的缓存条目，则必须定义自己的分区 ID。当您将分区 ID 传递给分层密钥环时，密钥环可以重复使用共享缓存中已存在的缓存条目，而不必再次检索和重新授权分支密钥材料。如果您未指定分区 ID，则每次实例化分层密钥环时，都会自动为密钥环分配一个唯一的分区 ID。

以下过程演示如何创建[默认缓存类型的共享缓存](#cache-default)并将其传递给分层密钥环。

1. 使用[材料提供者库 `CryptographicMaterialsCache`](https://github.com/aws/aws-cryptographic-material-providers-library) (MPL) 创建 (CMC)。

------
#### [ Java ]

   ```
   // Instantiate the MPL
   final MaterialProviders matProv =
       MaterialProviders.builder()
           .MaterialProvidersConfig(MaterialProvidersConfig.builder().build())
           .build();
   
   // Create a CacheType object for the Default cache
   final CacheType cache =
       CacheType.builder() 
           .Default(DefaultCache.builder().entryCapacity(100).build())
           .build();
   
   // Create a CMC using the default cache
   final CreateCryptographicMaterialsCacheInput cryptographicMaterialsCacheInput =
       CreateCryptographicMaterialsCacheInput.builder()
           .cache(cache)
           .build();
   
   final ICryptographicMaterialsCache sharedCryptographicMaterialsCache =
       matProv.CreateCryptographicMaterialsCache(cryptographicMaterialsCacheInput);
   ```

------
#### [ C\$1 / .NET ]

   ```
   // Instantiate the MPL
   var materialProviders = new MaterialProviders(new MaterialProvidersConfig());
    
   // Create a CacheType object for the Default cache
   var cache = new CacheType { Default = new DefaultCache{EntryCapacity = 100} };
    
   // Create a CMC using the default cache
   var cryptographicMaterialsCacheInput = new CreateCryptographicMaterialsCacheInput {Cache = cache};
    
   var sharedCryptographicMaterialsCache = materialProviders.CreateCryptographicMaterialsCache(cryptographicMaterialsCacheInput);
   ```

------
#### [ Rust ]

   ```
   // Instantiate the MPL
   let mpl_config = MaterialProvidersConfig::builder().build()?;
   let mpl = mpl_client::Client::from_conf(mpl_config)?;
   
   // Create a CacheType object for the default cache
   let cache: CacheType = CacheType::Default(
       DefaultCache::builder()
           .entry_capacity(100)
           .build()?,
   );
   
   // Create a CMC using the default cache
   let shared_cryptographic_materials_cache: CryptographicMaterialsCacheRef = mpl.
       create_cryptographic_materials_cache()
       .cache(cache)
       .send()
       .await?;
   ```

------

1. 为共享缓存创建`CacheType`对象。

   将`sharedCryptographicMaterialsCache`您在**步骤 1** 中创建的传递给新`CacheType`对象。

------
#### [ Java ]

   ```
   // Create a CacheType object for the sharedCryptographicMaterialsCache
   final CacheType sharedCache =
       CacheType.builder()
           .Shared(sharedCryptographicMaterialsCache)
           .build();
   ```

------
#### [ C\$1 / .NET ]

   ```
   // Create a CacheType object for the sharedCryptographicMaterialsCache
   var sharedCache = new CacheType { Shared = sharedCryptographicMaterialsCache };
   ```

------
#### [ Rust ]

   ```
   // Create a CacheType object for the shared_cryptographic_materials_cache
   let shared_cache: CacheType = CacheType::Shared(shared_cryptographic_materials_cache);
   ```

------

1. 将**步骤 2** 中的`sharedCache`对象传递到分层密钥环。

   使用共享缓存创建分层密钥环时，可以选择定义一个`partitionID`以在多个分层密钥环之间共享缓存条目。如果您未指定分区 ID，则分层密钥环会自动为密钥环分配一个唯一的分区 ID。
**注意**  
如果您创建两个或更多引用相同分区 ID 和分支密钥 ID 的密钥环，则您的分层密钥环将在共享缓存中共享相同的缓存条目。[logical key store name](create-keystore.md#logical-key-store-name)如果您不希望多个密钥环共享相同的缓存条目，则必须为每个分层密钥环使用唯一的分区 ID。

   以下示例创建了一个分层密钥环[branch key ID supplier](#branch-key-id-supplier)，其[缓存限制为](#cache-limit) 600 秒。有关以下分层密钥环配置中定义的值的更多信息，请参阅[创建分层密钥环](#initialize-hierarchical-keyring)。

------
#### [ Java ]

   ```
   // Create the Hierarchical keyring
   final CreateAwsKmsHierarchicalKeyringInput keyringInput =
       CreateAwsKmsHierarchicalKeyringInput.builder()
           .keyStore(keystore)
           .branchKeyIdSupplier(branchKeyIdSupplier)
           .ttlSeconds(600)
           .cache(sharedCache)
           .partitionID(partitionID)
           .build();        
   final IKeyring hierarchicalKeyring = matProv.CreateAwsKmsHierarchicalKeyring(keyringInput);
   ```

------
#### [ C\$1 / .NET ]

   ```
   // Create the Hierarchical keyring        
   var createKeyringInput = new CreateAwsKmsHierarchicalKeyringInput
   {
      KeyStore = keystore,
      BranchKeyIdSupplier = branchKeyIdSupplier,
      Cache = sharedCache,
      TtlSeconds = 600,
      PartitionId = partitionID
   };
   var keyring = materialProviders.CreateAwsKmsHierarchicalKeyring(createKeyringInput);
   ```

------
#### [ Rust ]

   ```
   // Create the Hierarchical keyring
   let keyring1 = mpl
       .create_aws_kms_hierarchical_keyring()
       .key_store(key_store1)
       .branch_key_id(branch_key_id.clone())
       // CryptographicMaterialsCacheRef is an Rc (Reference Counted), so if you clone it to
       // pass it to different Hierarchical Keyrings, it will still point to the same
       // underlying cache, and increment the reference count accordingly.
       .cache(shared_cache.clone())
       .ttl_seconds(600)
       .partition_id(partition_id.clone())
       .send()
       .await?;
   ```

------

## 创建分层密钥环
<a name="initialize-hierarchical-keyring"></a>

要创建分层密钥环，必须提供以下值：
+ **密钥库名称**

  您或您的密钥库管理员创建的用作密钥存储的 DynamoDB 表的名称。
+ 

  **缓存限制生存时间（TTL）**

  本地缓存中的分支密钥材料条目在过期之前可使用的时长（以秒为单位）。缓存限制 TTL 决定了客户端调 AWS KMS 用授权使用分支密钥的频率。该值必须大于零。缓存限制 TTL 到期后，该条目将永远不会被提供，并将从本地缓存中逐出。
+ **分支密钥标识符**

  您可以静态配置用于标识密钥库中单个活动分支密钥的，也可以提供分支密钥 ID 供应商。`branch-key-id`

  

  *分支密钥 ID 提供*者使用存储在加密上下文中的字段来确定解密记录需要哪个分支密钥。默认情况下，加密上下文中仅包含分区和排序密钥。但是，您可以使用加密[操作在`SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`加密](concepts.md#crypt-actions)上下文中包含其他字段。

  对于每个租户都有自己的分支密钥的多租户数据库，我们强烈建议使用分支密钥 ID 供应商。您可以使用分支密钥 ID 供应商为分支密钥创建友好名称， IDs 以便轻松识别特定租户的正确分支密钥 ID。例如，易记名称使您可以将分支密钥引用为 `tenant1` 而非 `b3f61619-4d35-48ad-a275-050f87e15122`。

  对于解密操作，您可以静态配置单个分层密钥环以限制对单个租户进行解密，也可以使用分支密钥 ID 提供程序确定哪个租户负责解密记录。
+ **（可选）缓存**

  如果要自定义缓存类型或可存储在本地缓存中分支密钥材料条目的数量，请在初始化密钥环时指定缓存类型和条目容量。

  分层密钥环支持以下缓存类型：默认、 MultiThreaded StormTracking、和共享。有关演示如何定义每种缓存类型的更多信息和示例，请参阅[选择缓存](#hierarchical-keyring-caches)。

  如果未指定缓存，则分层密钥环会自动使用默认缓存类型并将条目容量设置为 1000。
+ **（可选）分区 ID**

  如果指定[共享缓存](#cache-shared)，则可以选择定义分区 ID。分区 ID 可区分哪个分层密钥环正在写入缓存。如果您打算重复使用或共享分区中的缓存条目，则必须定义自己的分区 ID。您可以为分区 ID 指定任何字符串。如果您未指定分区 ID，则会在创建密钥环时自动为密钥环分配一个唯一的分区 ID。

  有关更多信息，请参阅 [Partitions](#shared-cache-partitions)。
**注意**  
如果您创建两个或更多引用相同分区 ID 和分支密钥 ID 的密钥环，则您的分层密钥环将在共享缓存中共享相同的缓存条目。[logical key store name](create-keystore.md#logical-key-store-name)如果您不希望多个密钥环共享相同的缓存条目，则必须为每个分层密钥环使用唯一的分区 ID。
+ **（可选）授权令牌列表**

  如果您通过[授权](https://docs.aws.amazon.com/kms/latest/developerguide/grants.html)控制对分层密钥环中 KMS 密钥的访问权限，则必须在初始化密钥环时提供所有必要的授权令牌。

### 使用静态分支密钥 ID 创建分层密钥环
<a name="static-branch-key-id-config"></a>

以下示例演示如何创建具有静态分支密钥 ID、缓存限制 TTL 为 600 秒的分层密钥环。[默认缓存](#cache-default)

------
#### [ Java ]

```
final MaterialProviders matProv = MaterialProviders.builder()
        .MaterialProvidersConfig(MaterialProvidersConfig.builder().build())
        .build();
final CreateAwsKmsHierarchicalKeyringInput keyringInput = CreateAwsKmsHierarchicalKeyringInput.builder()
        .keyStore(branchKeyStoreName)
        .branchKeyId(branch-key-id)
        .ttlSeconds(600)
        .build();
final Keyring hierarchicalKeyring = matProv.CreateAwsKmsHierarchicalKeyring(keyringInput);
```

------
#### [ C\$1 / .NET ]

```
var matProv = new MaterialProviders(new MaterialProvidersConfig());
var keyringInput = new CreateAwsKmsHierarchicalKeyringInput
{
   KeyStore = keystore,
   BranchKeyIdSupplier = branchKeyIdSupplier,
   TtlSeconds = 600
};
var hierarchicalKeyring = matProv.CreateAwsKmsHierarchicalKeyring(keyringInput);
```

------
#### [ Rust ]

```
let mpl_config = MaterialProvidersConfig::builder().build()?;
let mpl = mpl_client::Client::from_conf(mpl_config)?;

let hierarchical_keyring = mpl
    .create_aws_kms_hierarchical_keyring()
    .branch_key_id(branch_key_id)
    .key_store(branch_key_store_name)
    .ttl_seconds(600)
    .send()
    .await?;
```

------

### 使用分支密钥 ID 供应商创建分层密钥环
<a name="branch-key-id-supplier-config"></a>

以下过程演示如何使用分支密钥 ID 提供者创建分层密钥环。

1. 创建分支密钥 ID 供应商

   以下示例为**步骤 1** 中创建的两个分支密钥创建友好名称，并使用适用于 DynamoDB 客户端的 AWS 数据库加密 SDK 调`CreateDynamoDbEncryptionBranchKeyIdSupplier`用创建分支密钥 ID 提供者。

------
#### [ Java ]

   ```
   // Create friendly names for each branch-key-id 
   class ExampleBranchKeyIdSupplier implements IDynamoDbKeyBranchKeyIdSupplier {
       private static String branchKeyIdForTenant1;
       private static String branchKeyIdForTenant2;
   
       public ExampleBranchKeyIdSupplier(String tenant1Id, String tenant2Id) {
           this.branchKeyIdForTenant1 = tenant1Id;
           this.branchKeyIdForTenant2 = tenant2Id;
       }
   // Create the branch key ID supplier    
   final DynamoDbEncryption ddbEnc = DynamoDbEncryption.builder()
           .DynamoDbEncryptionConfig(DynamoDbEncryptionConfig.builder().build())
           .build();
   final BranchKeyIdSupplier branchKeyIdSupplier = ddbEnc.CreateDynamoDbEncryptionBranchKeyIdSupplier(
       CreateDynamoDbEncryptionBranchKeyIdSupplierInput.builder()
               .ddbKeyBranchKeyIdSupplier(new ExampleBranchKeyIdSupplier(branch-key-ID-tenant1, branch-key-ID-tenant2))
               .build()).branchKeyIdSupplier();
   ```

------
#### [ C\$1 / .NET ]

   ```
   // Create friendly names for each branch-key-id
    class ExampleBranchKeyIdSupplier : DynamoDbKeyBranchKeyIdSupplierBase {
       private String _branchKeyIdForTenant1;
       private String _branchKeyIdForTenant2;
   
       public ExampleBranchKeyIdSupplier(String tenant1Id, String tenant2Id) {
           this._branchKeyIdForTenant1 = tenant1Id;
           this._branchKeyIdForTenant2 = tenant2Id;
       }    
   // Create the branch key ID supplier
   var ddbEnc = new DynamoDbEncryption(new DynamoDbEncryptionConfig());
   var branchKeyIdSupplier = ddbEnc.CreateDynamoDbEncryptionBranchKeyIdSupplier(
       new CreateDynamoDbEncryptionBranchKeyIdSupplierInput
       {
           DdbKeyBranchKeyIdSupplier = new ExampleBranchKeyIdSupplier(branch-key-ID-tenant1, branch-key-ID-tenant2)
       }).BranchKeyIdSupplier;
   ```

------
#### [ Rust ]

   ```
   // Create friendly names for each branch_key_id
   pub struct ExampleBranchKeyIdSupplier {
       branch_key_id_for_tenant1: String,
       branch_key_id_for_tenant2: String,
   }
   
   impl ExampleBranchKeyIdSupplier {
       pub fn new(tenant1_id: &str, tenant2_id: &str) -> Self {
           Self {
               branch_key_id_for_tenant1: tenant1_id.to_string(),
               branch_key_id_for_tenant2: tenant2_id.to_string(),
           }
       }
   }
   
   // Create the branch key ID supplier                                        
   let dbesdk_config = DynamoDbEncryptionConfig::builder().build()?;
   let dbesdk = dbesdk_client::Client::from_conf(dbesdk_config)?;
   let supplier = ExampleBranchKeyIdSupplier::new(tenant1_branch_key_id, tenant2_branch_key_id);
   
   let branch_key_id_supplier = dbesdk
       .create_dynamo_db_encryption_branch_key_id_supplier()
       .ddb_key_branch_key_id_supplier(supplier)
       .send()
       .await?
       .branch_key_id_supplier
       .unwrap();
   ```

------

1. 创建分层密钥环

   以下示例使用**步骤 1** 中创建的分支密钥 ID 供应商初始化分层密钥环，缓存限制 TLL 为 600 秒，最大缓存大小为 1000。

------
#### [ Java ]

   ```
   final MaterialProviders matProv = MaterialProviders.builder()
           .MaterialProvidersConfig(MaterialProvidersConfig.builder().build())
           .build();
   final CreateAwsKmsHierarchicalKeyringInput keyringInput = CreateAwsKmsHierarchicalKeyringInput.builder()
           .keyStore(keystore)
           .branchKeyIdSupplier(branchKeyIdSupplier)
           .ttlSeconds(600)
           .cache(CacheType.builder() //OPTIONAL
                   .Default(DefaultCache.builder()
                   .entryCapacity(100)
                   .build())
           .build())
           .build();
   final Keyring hierarchicalKeyring = matProv.CreateAwsKmsHierarchicalKeyring(keyringInput);
   ```

------
#### [ C\$1 / .NET ]

   ```
   var matProv = new MaterialProviders(new MaterialProvidersConfig());
   var keyringInput = new CreateAwsKmsHierarchicalKeyringInput
   {
      KeyStore = keystore,
      BranchKeyIdSupplier = branchKeyIdSupplier,
      TtlSeconds = 600, 
      Cache = new CacheType
      {
           Default = new DefaultCache { EntryCapacity = 100 }
      }
   };
   var hierarchicalKeyring = matProv.CreateAwsKmsHierarchicalKeyring(keyringInput);
   ```

------
#### [ Rust ]

   ```
   let mpl_config = MaterialProvidersConfig::builder().build()?;
   let mpl = mpl_client::Client::from_conf(mpl_config)?;
   
   let hierarchical_keyring = mpl
       .create_aws_kms_hierarchical_keyring()
       .branch_key_id_supplier(branch_key_id_supplier)
       .key_store(key_store)
       .ttl_seconds(600)
       .send()
       .await?;
   ```

------

## 使用分层密钥环进行可搜索加密
<a name="searchable-encryption-hierarchical-keyrings"></a>

[可搜索加密](searchable-encryption.md)使您无需解密整个数据库即可搜索加密的记录。该操作通过使用[信标](beacons.md)对加密字段的明文值进行索引来实现。要实现可搜索加密，必须使用分层密钥环。

密钥存储 `CreateKey` 操作将产生分支密钥和*信标密钥*。分支密钥用于记录加密和解密操作。信标密钥用于生成信标。

分支密钥和信标密钥受您在创建密钥存储服务时指定的相同 AWS KMS key 密钥和信标密钥的保护。在`CreateKey`操作调 AWS KMS 用生成分支密钥后，它使用以下请求第二次调用 k [ms: GenerateDataKeyWithoutPlaintext](https://docs.aws.amazon.com/kms/latest/APIReference/API_GenerateDataKeyWithoutPlaintext.html) 以生成信标密钥。

```
{
   "EncryptionContext": { 
      "branch-key-id" : "branch-key-id",
      "type" : type,
      "create-time" : "timestamp",
      "tablename" : "the logical table name for your key store",
      "kms-arn" : the KMS key ARN,
      "hierarchy-version" : 1
   },
   "KeyId": "the KMS key ARN",
   "NumberOfBytes": "32"
}
```

生成两个密钥后，该`CreateKey`操作会调用 [ddb: TransactWriteItems](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_TransactWriteItems.html) 来编写两个新项目，它们将在分支密钥存储中保留分支密钥和信标密钥。

[配置标准信标](configure-beacons.md#config-standard-beacons)时， AWS 数据库加密 SDK 会在密钥库中查询信标密钥。然后，它使用基于 HMAC 的 extract-and-expand密钥派生函数 (H [KDF](https://en.wikipedia.org/wiki/HKDF)) 将信标密钥与[标准信标的名称相结合，为给定信标](beacons.md#standard-beacon-overview)创建 HMAC 密钥。

与分支密钥不同，每个密钥库`branch-key-id`中只有一个信标密钥版本。信标密钥永远不会轮换。

### 定义您的信标密钥源
<a name="beacon-key-source"></a>

为标准信标和复合信标定义[信标版本](using-beacons.md#beacon-version)时，必须识别信标密钥并为信标密钥材料定义缓存限制生存时间（TTL）。信标密钥材料与分支密钥分开存储在单独的本地缓存中。以下片段演示了如何为单租户数据库定义 `keySource`。通过与之关联的 `branch-key-id` 来识别您的信标密钥。

------
#### [ Java ]

```
keySource(BeaconKeySource.builder()
        .single(SingleKeyStore.builder()
                .keyId(branch-key-id)
                .cacheTTL(6000)
                .build())
        .build())
```

------
#### [ C\$1 / .NET ]

```
KeySource = new BeaconKeySource
{
    Single = new SingleKeyStore
    {
       KeyId = branch-key-id,
       CacheTTL = 6000
    }
}
```

------
#### [ Rust ]

```
 .key_source(BeaconKeySource::Single(
    SingleKeyStore::builder()
        // `keyId` references a beacon key.
        // For every branch key we create in the keystore,
        // we also create a beacon key.
        // This beacon key is not the same as the branch key,
        // but is created with the same ID as the branch key.
        .key_id(branch_key_id)
        .cache_ttl(6000)
        .build()?,
))
```

------

**在多租户数据库中定义信标源**  
如果您有多租户数据库，则在配置 `keySource` 时必须指定以下值。  
+ 

  **keyFieldName**

  定义存储与信标密钥关联的 `branch-key-id` 的字段名称，该信标密钥用于为给定租户生成信标。`keyFieldName` 可以是任何字符串，但它对于数据库中所有其他字段必须是唯一的。当您将新记录写入数据库时，标识用于为该记录生成任何信标的信标密钥的 `branch-key-id` 将存储在此字段中。您必须在信标查询中包含此字段，并确定重新计算信标所需的相应信标密钥材料。有关更多信息，请参阅 [查询多租户数据库中的信标](searchable-encryption-multitenant.md#query-multitenant-beacons)。
+ **cacheTTL**

  本地信标缓存中的信标密钥材料条目在过期之前可使用的时长（以秒为单位）。该值必须大于零。当缓存限制 TTL 到期时，该条目将从本地缓存中移出。
+ **（可选）缓存**

  如果要自定义缓存类型或可存储在本地缓存中分支密钥材料条目的数量，请在初始化密钥环时指定缓存类型和条目容量。

  分层密钥环支持以下缓存类型：默认、 MultiThreaded StormTracking、和共享。有关演示如何定义每种缓存类型的更多信息和示例，请参阅[选择缓存](#hierarchical-keyring-caches)。

  如果未指定缓存，则分层密钥环会自动使用默认缓存类型并将条目容量设置为 1000。
以下示例创建了一个分层密钥环，其分支密钥 ID 提供者缓存限制 TLL 为 600 秒，条目容量为 1000。  

```
final MaterialProviders matProv = MaterialProviders.builder()
        .MaterialProvidersConfig(MaterialProvidersConfig.builder().build())
        .build();
final CreateAwsKmsHierarchicalKeyringInput keyringInput = CreateAwsKmsHierarchicalKeyringInput.builder()
        .keyStore(branchKeyStoreName)
        .branchKeyIdSupplier(branchKeyIdSupplier)
        .ttlSeconds(600)
        .cache(CacheType.builder() //OPTIONAL
                .Default(DefaultCache.builder()
                        .entryCapacity(1000)
                        .build())
                .build());
final IKeyring hierarchicalKeyring = matProv.CreateAwsKmsHierarchicalKeyring(keyringInput);
```

```
var matProv = new MaterialProviders(new MaterialProvidersConfig());
var keyringInput = new CreateAwsKmsHierarchicalKeyringInput
{
   KeyStore = keystore,
   BranchKeyIdSupplier = branchKeyIdSupplier,
   TtlSeconds = 600, 
   Cache = new CacheType
   {
        Default = new DefaultCache { EntryCapacity = 1000 }
   }
};
var hierarchicalKeyring = matProv.CreateAwsKmsHierarchicalKeyring(keyringInput);
```

```
let provider_config = MaterialProvidersConfig::builder().build()?;
    let mat_prov = client::Client::from_conf(provider_config)?;
    let kms_keyring = mat_prov
        .create_aws_kms_hierarchical_keyring()
        .branch_key_id(branch_key_id)
        .key_store(key_store)
        .ttl_seconds(600)
        .send()
        .await?;
```

# AWS KMS ECDH 钥匙圈
<a name="use-kms-ecdh-keyring"></a>


****  

|  | 
| --- |
| 我们的客户端加密库已重命名为 AWS 数据库加密 SDK。本开发人员指南仍提供有关 [DynamoDB 加密客户端](legacy-dynamodb-encryption-client.md)的信息。 | 

**重要**  
 AWS KMS ECDH 密钥环仅在 1.5.0 或更高版本的材料提供者库中可用。

 AWS KMS ECDH 密钥环使用非对称密钥协议[AWS KMS keys](https://docs.aws.amazon.com/kms/latest/developerguide/key-types.html)来派生双方共享的对称包装密钥。首先，密钥环使用 Elliptic Curve Diffie-Hellman (ECDH) 密钥协议算法，从发送者的 KMS 密钥对中的私钥和接收者的公钥中派生出共享密钥。然后，密钥环使用共享密钥来派生用于保护您的数据加密密钥的共享包装密钥。 AWS 数据库加密 SDK 使用 (`KDF_CTR_HMAC_SHA384`) 派生共享包装密钥的密钥派生函数符合 [NIST 关于密钥派生的建议](https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-108r1-upd1.pdf)。

密钥派生函数返回 64 字节的密钥材料。为确保双方使用正确的密钥材料， AWS 数据库加密 SDK 使用前 32 字节作为承诺密钥，使用最后 32 字节作为共享封装密钥。解密时，如果密钥环无法复制存储在加密记录材料描述字段中的相同承诺密钥和共享包装密钥，则操作将失败。例如，如果您使用配置有 **Alice 私钥和 **Bob** 公钥的**密钥环对记录进行加密，则使用 B **ob 的私钥和 Alice 的****公钥配置的**密钥环将复制相同的承诺密钥和共享包装密钥，并能够解密该记录。如果 Bob 的公钥不是来自 KMS 密钥对，那么 Bob 可以创建一个 Ra [w ECDH 密钥环](use-raw-ecdh-keyring.md)来解密记录。

 AWS KMS ECDH 密钥环使用 AES-GCM 使用对称密钥对记录进行加密。然后使用 AES-GCM 使用派生的共享包装密钥对数据密钥进行信封加密。[每个 AWS KMS ECDH 密钥环只能有一个共享的包装密钥，但您可以在多密钥环中单独或与其他密钥环一起包含多个 AWS KMS ECDH 密钥环。](use-multi-keyring.md)

**Topics**
+ [AWS KMS ECDH 密钥环所需的权限](#kms-ecdh-permissions)
+ [创建 AWS KMS ECDH 密钥环](#kms-ecdh-create)
+ [创建 AWS KMS ECDH 发现密钥环](#kms-ecdh-discovery)

## AWS KMS ECDH 密钥环所需的权限
<a name="kms-ecdh-permissions"></a>

 AWS 数据库加密 SDK 不需要 AWS 帐户，也不依赖任何 AWS 服务。但是，要使用 AWS KMS ECDH 密钥环，您需要一个 AWS 帐户以及对密钥环 AWS KMS keys 中的以下最低权限。权限因您使用的密钥协议架构而异。
+ 要使用密`KmsPrivateKeyToStaticPublicKey`钥协议架构加密和解密记录，您需要在*发送者的非对称 KMS 密钥对DeriveSharedSecret上使用 kms*[: GetPublicKey](https://docs.aws.amazon.com/kms/latest/APIReference/API_GetPublicKey.html) [和 km](https://docs.aws.amazon.com/kms/latest/APIReference/API_DeriveSharedSecret.html) s:。如果您在实例化密钥环时直接提供发送者的 DER 编码公钥，则只需要对发送者的非对称 [KMS 密钥对DeriveSharedSecret具有 kms:](https://docs.aws.amazon.com/kms/latest/APIReference/API_DeriveSharedSecret.html) 权限。
+ 要使用密`KmsPublicKeyDiscovery`钥协议架构解密记录，您需要对指定的非对称 [KMS 密钥对具有 kms: DeriveSharedSecret](https://docs.aws.amazon.com/kms/latest/APIReference/API_DeriveSharedSecret.html) [和 kms: GetPublicKey](https://docs.aws.amazon.com/kms/latest/APIReference/API_GetPublicKey.html) 权限。

## 创建 AWS KMS ECDH 密钥环
<a name="kms-ecdh-create"></a>

要创建用于加密和解密数据的 AWS KMS ECDH 密钥环，必须使用密钥协议架构。`KmsPrivateKeyToStaticPublicKey`要使用密钥协议架构初始化 AWS KMS ECDH `KmsPrivateKeyToStaticPublicKey` 密钥环，请提供以下值：
+ **发件人 AWS KMS key 身份证**

  必须标识值为的非对称 NIST 推荐的椭圆曲线 (ECC) KMS 密钥对。`KeyUsage` `KEY_AGREEMENT`发送者的私钥用于派生共享密钥。
+ **（可选）发件人的公钥**

  [必须是 DER 编码的 X.509 公钥，也称为 `SubjectPublicKeyInfo` (SPKI)，如 RFC 5280 中所定义。](https://tools.ietf.org/html/rfc5280)

  该 AWS KMS [GetPublicKey](https://docs.aws.amazon.com/kms/latest/APIReference/API_GetPublicKey.html)操作以所需的 DER 编码格式返回非对称 KMS 密钥对的公钥。

  要减少密钥环 AWS KMS 拨打的次数，您可以直接提供发件人的公钥。如果没有为发件人的公钥提供任何值，则密钥环会调用 AWS KMS 以检索发送者的公钥。
+ **收件人的公钥**

  [您必须提供收件人的 DER 编码的 X.509 公钥，也称为 `SubjectPublicKeyInfo` (SPKI)，如 RFC 5280 中所定义。](https://tools.ietf.org/html/rfc5280)

  该 AWS KMS [GetPublicKey](https://docs.aws.amazon.com/kms/latest/APIReference/API_GetPublicKey.html)操作以所需的 DER 编码格式返回非对称 KMS 密钥对的公钥。
+ **曲线规格**

  标识指定密钥对中的椭圆曲线规范。发件人和收件人的密钥对必须具有相同的曲线规格。

  有效值：`ECC_NIST_P256`、`ECC_NIS_P384`、`ECC_NIST_P512`
+ **（可选）授权令牌列表**

  如果您通过授权控制对 AWS KMS ECDH 密钥环中 KMS 密钥的访问[权限](https://docs.aws.amazon.com/kms/latest/developerguide/grants.html)，则在初始化密钥环时必须提供所有必要的授权令牌。

------
#### [ C\$1 / .NET ]

以下示例使用发件人的 KMS 密钥、发件人的公钥和收件人的公钥创建一个 AWS KMS ECDH 密钥环。此示例使用可选`senderPublicKey`参数来提供发送者的公钥。如果您不提供发件人的公钥，则密钥环会调用 AWS KMS 以检索发件人的公钥。发件人和收件人的密钥对都在`ECC_NIST_P256`弯曲中。

```
// Instantiate material providers
var materialProviders = new MaterialProviders(new MaterialProvidersConfig());

// Must be DER-encoded X.509 public keys
var BobPublicKey = new MemoryStream(new byte[] { });
var AlicePublicKey = new MemoryStream(new byte[] { });

// Create the AWS KMS ECDH static keyring
var staticConfiguration = new KmsEcdhStaticConfigurations
{
    KmsPrivateKeyToStaticPublicKey = new KmsPrivateKeyToStaticPublicKeyInput
    {
        SenderKmsIdentifier = "arn:aws:kms:us-west-2:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab",
        SenderPublicKey = BobPublicKey,
        RecipientPublicKey = AlicePublicKey
    }
};
	    
var createKeyringInput = new CreateAwsKmsEcdhKeyringInput
{
    CurveSpec = ECDHCurveSpec.ECC_NIST_P256,
    KmsClient = new AmazonKeyManagementServiceClient(),
    KeyAgreementScheme = staticConfiguration
};

var keyring = materialProviders.CreateAwsKmsEcdhKeyring(createKeyringInput);
```

------
#### [ Java ]

以下示例使用发件人的 KMS 密钥、发件人的公钥和收件人的公钥创建一个 AWS KMS ECDH 密钥环。此示例使用可选`senderPublicKey`参数来提供发送者的公钥。如果您不提供发件人的公钥，则密钥环会调用 AWS KMS 以检索发件人的公钥。发件人和收件人的密钥对都在`ECC_NIST_P256`弯曲中。

```
// Retrieve public keys
// Must be DER-encoded X.509 public keys                                
ByteBuffer BobPublicKey = getPublicKeyBytes("arn:aws:kms:us-west-2:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab");
        ByteBuffer AlicePublicKey = getPublicKeyBytes("arn:aws:kms:us-west-2:111122223333:key/0987dcba-09fe-87dc-65ba-ab0987654321"); 

// Create the AWS KMS ECDH static keyring
        final CreateAwsKmsEcdhKeyringInput senderKeyringInput =
          CreateAwsKmsEcdhKeyringInput.builder()
            .kmsClient(KmsClient.create())
            .curveSpec(ECDHCurveSpec.ECC_NIST_P256)
            .KeyAgreementScheme(
              KmsEcdhStaticConfigurations.builder()
                .KmsPrivateKeyToStaticPublicKey(
                  KmsPrivateKeyToStaticPublicKeyInput.builder()
                    .senderKmsIdentifier("arn:aws:kms:us-west-2:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab")
                    .senderPublicKey(BobPublicKey)
                    .recipientPublicKey(AlicePublicKey)
                    .build()).build()).build();
```

------
#### [ Rust ]

以下示例使用发件人的 KMS 密钥、发件人的公钥和收件人的公钥创建一个 AWS KMS ECDH 密钥环。此示例使用可选`sender_public_key`参数来提供发送者的公钥。如果您不提供发件人的公钥，则密钥环会调用 AWS KMS 以检索发件人的公钥。

```
// Retrieve public keys
// Must be DER-encoded X.509 keys
let public_key_file_content_sender = std::fs::read_to_string(Path::new(EXAMPLE_KMS_ECC_PUBLIC_KEY_FILENAME_SENDER))?;
let parsed_public_key_file_content_sender = parse(public_key_file_content_sender)?;
let public_key_sender_utf8_bytes = parsed_public_key_file_content_sender.contents();

let public_key_file_content_recipient = std::fs::read_to_string(Path::new(EXAMPLE_KMS_ECC_PUBLIC_KEY_FILENAME_RECIPIENT))?;
let parsed_public_key_file_content_recipient = parse(public_key_file_content_recipient)?;
let public_key_recipient_utf8_bytes = parsed_public_key_file_content_recipient.contents();

// Create KmsPrivateKeyToStaticPublicKeyInput
let kms_ecdh_static_configuration_input =
    KmsPrivateKeyToStaticPublicKeyInput::builder()
        .sender_kms_identifier(arn:aws:kms:us-west-2:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab)
        // Must be a UTF8 DER-encoded X.509 public key
        .sender_public_key(public_key_sender_utf8_bytes)
        // Must be a UTF8 DER-encoded X.509 public key
        .recipient_public_key(public_key_recipient_utf8_bytes)
        .build()?;

let kms_ecdh_static_configuration = KmsEcdhStaticConfigurations::KmsPrivateKeyToStaticPublicKey(kms_ecdh_static_configuration_input);

// Instantiate the material providers library
let mpl_config = MaterialProvidersConfig::builder().build()?;
let mpl = mpl_client::Client::from_conf(mpl_config)?;

// Create AWS KMS ECDH keyring
let kms_ecdh_keyring = mpl
    .create_aws_kms_ecdh_keyring()
    .kms_client(kms_client)
    .curve_spec(ecdh_curve_spec)
    .key_agreement_scheme(kms_ecdh_static_configuration)
    .send()
    .await?;
```

------

## 创建 AWS KMS ECDH 发现密钥环
<a name="kms-ecdh-discovery"></a>

解密时，最佳做法是指定 AWS 数据库加密 SDK 可以使用的密钥。要遵循此最佳实践，请使用带有密钥协议架构的 AWS KMS ECDH `KmsPrivateKeyToStaticPublicKey` 密钥环。但是，您也可以创建 AWS KMS ECDH 发现密钥环，即 AWS KMS ECDH 密钥环，该密钥环可以解密任何记录，其中指定 KMS 密钥对的公钥与存储在加密记录的材料描述字段中的*接收者的*公钥相匹配。

**重要**  
使用密`KmsPublicKeyDiscovery`钥协议架构解密记录时，无论谁拥有所有公钥，都将接受所有公钥。

要使用密钥协议架构初始化 AWS KMS ECDH `KmsPublicKeyDiscovery` 密钥环，请提供以下值：
+ **收件人的 AWS KMS key 身份证**

  必须标识值为的非对称 NIST 推荐的椭圆曲线 (ECC) KMS 密钥对。`KeyUsage` `KEY_AGREEMENT`
+ **曲线规格**

  标识收件人的 KMS 密钥对中的椭圆曲线规范。

  有效值：`ECC_NIST_P256`、`ECC_NIS_P384`、`ECC_NIST_P512`
+ **（可选）授权令牌列表**

  如果您通过授权控制对 AWS KMS ECDH 密钥环中 KMS 密钥的访问[权限](https://docs.aws.amazon.com/kms/latest/developerguide/grants.html)，则在初始化密钥环时必须提供所有必要的授权令牌。

------
#### [ C\$1 / .NET ]

以下示例创建了一个 AWS KMS ECDH 发现密钥环，曲线上有 KMS 密钥对。`ECC_NIST_P256`您必须对指定的 [KMS 密钥对拥有 kms: GetPublicKey](https://docs.aws.amazon.com/kms/latest/APIReference/API_GetPublicKey.html) [和 kms: DeriveSharedSecret](https://docs.aws.amazon.com/kms/latest/APIReference/API_DeriveSharedSecret.html) 权限。此密钥环可以解密任何记录，其中指定 KMS 密钥对的公钥与存储在加密记录的材料描述字段中的接收者的公钥相匹配。

```
// Instantiate material providers
var materialProviders = new MaterialProviders(new MaterialProvidersConfig());

// Create the AWS KMS ECDH discovery keyring
var discoveryConfiguration = new KmsEcdhStaticConfigurations
{
    KmsPublicKeyDiscovery = new KmsPublicKeyDiscoveryInput
    {
        RecipientKmsIdentifier = "arn:aws:kms:us-west-2:111122223333:key/0987dcba-09fe-87dc-65ba-ab0987654321"
    }
		    
};
var createKeyringInput = new CreateAwsKmsEcdhKeyringInput
{
    CurveSpec = ECDHCurveSpec.ECC_NIST_P256,
    KmsClient = new AmazonKeyManagementServiceClient(),
    KeyAgreementScheme = discoveryConfiguration
};
var keyring = materialProviders.CreateAwsKmsEcdhKeyring(createKeyringInput);
```

------
#### [ Java ]

以下示例创建了一个 AWS KMS ECDH 发现密钥环，曲线上有 KMS 密钥对。`ECC_NIST_P256`您必须对指定的 [KMS 密钥对拥有 kms: GetPublicKey](https://docs.aws.amazon.com/kms/latest/APIReference/API_GetPublicKey.html) [和 kms: DeriveSharedSecret](https://docs.aws.amazon.com/kms/latest/APIReference/API_DeriveSharedSecret.html) 权限。此密钥环可以解密任何记录，其中指定 KMS 密钥对的公钥与存储在加密记录的材料描述字段中的接收者的公钥相匹配。

```
// Create the AWS KMS ECDH discovery keyring
final CreateAwsKmsEcdhKeyringInput recipientKeyringInput =
  CreateAwsKmsEcdhKeyringInput.builder()
    .kmsClient(KmsClient.create())
    .curveSpec(ECDHCurveSpec.ECC_NIST_P256)
    .KeyAgreementScheme(
      KmsEcdhStaticConfigurations.builder()
        .KmsPublicKeyDiscovery(
          KmsPublicKeyDiscoveryInput.builder()
            .recipientKmsIdentifier("arn:aws:kms:us-west-2:111122223333:key/0987dcba-09fe-87dc-65ba-ab0987654321").build()
        ).build())
    .build();
```

------
#### [ Rust ]

```
// Create KmsPublicKeyDiscoveryInput
let kms_ecdh_discovery_static_configuration_input =
    KmsPublicKeyDiscoveryInput::builder()
        .recipient_kms_identifier(ecc_recipient_key_arn)
        .build()?;

let kms_ecdh_discovery_static_configuration = KmsEcdhStaticConfigurations::KmsPublicKeyDiscovery(kms_ecdh_discovery_static_configuration_input);

// Instantiate the material providers library
let mpl_config = MaterialProvidersConfig::builder().build()?;
let mpl = mpl_client::Client::from_conf(mpl_config)?;

// Create AWS KMS ECDH discovery keyring
let kms_ecdh_discovery_keyring = mpl
    .create_aws_kms_ecdh_keyring()
    .kms_client(kms_client.clone())
    .curve_spec(ecdh_curve_spec)
    .key_agreement_scheme(kms_ecdh_discovery_static_configuration)
    .send()
    .await?;
```

------

# 原始 AES 密钥环
<a name="use-raw-aes-keyring"></a>


****  

|  | 
| --- |
| 我们的客户端加密库已重命名为 AWS 数据库加密 SDK。本开发人员指南仍提供有关 [DynamoDB 加密客户端](legacy-dynamodb-encryption-client.md)的信息。 | 

 AWS 数据库加密 SDK 允许您使用您提供的 AES 对称密钥作为包装密钥来保护您的数据密钥。您需要生成、存储和保护密钥材料，最好是在硬件安全模块（HSM）或密钥管理系统中操作。如果您需要提供包装密钥并在本地或离线加密数据密钥，则请使用原始 AES 密钥环。

原始 AES 密钥环使用 AES-GCM 算法以及您指定为字节数组的包装密钥对数据进行加密。每个原始 AES 密钥环中只能指定一个包装密钥，但每个[多重密钥环](use-multi-keyring.md)中可以包含多个原始 AES 密钥环，该等密钥环可单独纳入或与其他密钥环一同纳入。

**密钥命名空间和名称**

为标识密钥环中的 AES 密钥，原始 AES 密钥环使用您提供的*密钥命名空间*和*密钥名称*。这些值不是机密的。它们以纯文本形式出现在 AWS 数据库加密 SDK 添加到记录中的[材料描述](concepts.md#material-description)中。建议在 HSM 或密钥管理系统中使用密钥命名空间与用于标识该系统中 AES 密钥的密钥名称。

**注意**  
密钥命名空间和密钥名称等同于 `JceMasterKey` 中的*提供程序 ID*（或*提供程序*）和*密钥 ID* 字段。

如果您通过构造不同的密钥环加密和解密给定字段，命名空间和名称值则至关重要。如果解密密钥环中的密钥命名空间和密钥名称与加密密钥环中的密钥命名空间和密钥名称不完全匹配、大小写不一致，即使密钥材料字节数相同，也不会使用解密密钥环。

例如，您可以使用密钥命名空间 `HSM_01` 和密钥名称 `AES_256_012` 定义原始 AES 密钥环。然后使用该密钥环加密部分数据。要解密这些数据，请使用相同的密钥命名空间、密钥名称和密钥材料构造原始 AES 密钥环。

以下示例说明了如何创建原始 AES 密钥。`AESWrappingKey` 变量代表您提供的密钥材料。

------
#### [ Java ]

```
final CreateRawAesKeyringInput keyringInput = CreateRawAesKeyringInput.builder()
        .keyName("AES_256_012")
        .keyNamespace("HSM_01")
        .wrappingKey(AESWrappingKey)
        .wrappingAlg(AesWrappingAlg.ALG_AES256_GCM_IV12_TAG16)
        .build();
final MaterialProviders matProv = MaterialProviders.builder()
        .MaterialProvidersConfig(MaterialProvidersConfig.builder().build())
        .build();
IKeyring rawAesKeyring = matProv.CreateRawAesKeyring(keyringInput);
```

------
#### [ C\$1 / .NET ]

```
var keyNamespace = "HSM_01";
var keyName = "AES_256_012";

// This example uses the key generator in Bouncy Castle to generate the key material.
// In production, use key material from a secure source.
var aesWrappingKey = new MemoryStream(GeneratorUtilities.GetKeyGenerator("AES256").GenerateKey());

// Create the keyring
var keyringInput = new CreateRawAesKeyringInput
{
    KeyNamespace = keyNamespace,
    KeyName = keyName,
    WrappingKey = AESWrappingKey,
    WrappingAlg = AesWrappingAlg.ALG_AES256_GCM_IV12_TAG16
};

var matProv = new MaterialProviders(new MaterialProvidersConfig());
IKeyring rawAesKeyring = matProv.CreateRawAesKeyring(keyringInput);
```

------
#### [ Rust ]

```
let mpl_config = MaterialProvidersConfig::builder().build()?;
let mpl = mpl_client::Client::from_conf(mpl_config)?;
let raw_aes_keyring = mpl
    .create_raw_aes_keyring()
    .key_name("AES_256_012")
    .key_namespace("HSM_01")
    .wrapping_key(aes_key_bytes)
    .wrapping_alg(AesWrappingAlg::AlgAes256GcmIv12Tag16)
    .send()
    .await?;
```

------

# 原始 RSA 密钥环
<a name="use-raw-rsa-keyring"></a>


****  

|  | 
| --- |
| 我们的客户端加密库已重命名为 AWS 数据库加密 SDK。本开发人员指南仍提供有关 [DynamoDB 加密客户端](legacy-dynamodb-encryption-client.md)的信息。 | 

原始 RSA 密钥环使用您提供的 RSA 公有密钥和私有密钥为本地内存中的数据密钥执行非对称加密和解密。您需要生成、存储和保护私有密钥，最好是在硬件安全模块（HSM）或密钥管理系统中操作。加密功能对 RSA 公有密钥下的数据密钥进行加密。解密功能使用私有密钥对数据密钥进行解密。您可以从几种 RSA 填充模式中进行选择。

加密和解密的原始 RSA 密钥环必须包含一个非对称公有密钥和私有密钥对。但是，您可以使用仅具有公有密钥的原始 RSA 密钥环加密数据，并使用仅具有私有密钥的原始 RSA 密钥环解密数据。您可以在[多重密钥环](use-multi-keyring.md)中包含任何原始 RSA 密钥环。如果您为原始 RSA 密钥环配置公有密钥和私有密钥，请确保其属于同一个密钥对。

 Raw RSA 密钥环与 RSA 非对称加密密钥一起使用 AWS Encryption SDK for Java 时，等同于并与之互操作。[JceMasterKey](https://aws.github.io/aws-encryption-sdk-java/com/amazonaws/encryptionsdk/jce/JceMasterKey.html)

**注意**  
原始 RSA 密钥环不支持非对称 KMS 密钥。要使用非对称 RSA KMS 密钥，请构造 [AWS KMS 密钥环](use-kms-keyring.md)。

**命名空间和名称**

为标识密钥环中的 RSA 密钥材料，原始 AES 密钥环使用您提供的*命名空间*和*密钥名称*。这些值不是机密的。它们以纯文本形式出现在 AWS 数据库加密 SDK 添加到记录中的[材料描述](concepts.md#material-description)中。建议在 HSM 或密钥管理系统中使用密钥命名空间与用于标识 RSA 密钥对（或其私有密钥）的密钥名称。

**注意**  
密钥命名空间和密钥名称等同于 `JceMasterKey` 中的*提供程序 ID*（或*提供程序*）和*密钥 ID* 字段。

如果您通过构造不同的密钥环加密和解密给定记录，命名空间和名称值则至关重要。如果解密密钥环中的密钥命名空间和密钥名称与加密密钥环中的密钥命名空间和密钥名称不完全匹配、大小写不一致，即使密钥来自相同的密钥对，也不会使用解密密钥环。

无论密钥环中包含 RSA 公有密钥、RSA 私有密钥还是密钥对中的两个密钥，加密和解密密钥环中密钥材料的密钥命名空间和密钥名称必须相同。例如，假设您使用包含密钥命名空间 `HSM_01` 和密钥名称 `RSA_2048_06` 的 RSA 公有密钥的原始 RSA 密钥环加密数据。要解密数据，请使用私有密钥（或密钥对）、相同的密钥命名空间和名称构造原始 RSA 密钥环。

**填充模式**

您必须为用于加密和解密的原始 RSA 密钥环指定填充模式，或者使用为您指定填充模式的语言实施功能。

 AWS Encryption SDK 支持以下填充模式，受每种语言的限制。我们建议使用 [OAEP](https://tools.ietf.org/html/rfc8017#section-7.1) 填充模式，尤其是带有 SHA-256 和 MGF1 SHA-256 填充的 OAEP。仅支持[PKCS1](https://tools.ietf.org/html/rfc8017#section-7.2)填充模式是为了向后兼容。
+ 带有 SHA-1 和 MGF1 SHA-1 填充的 OAEP
+ 带有 SHA-256 和 MGF1 SHA-256 填充的 OAEP
+ 带有 SHA-384 和 MGF1 SHA-384 填充的 OAEP
+ 带有 SHA-512 和 MGF1 SHA-512 填充的 OAEP
+ PKCS1 v1.5 填充 

以下 Java 示例展示了如何使用 RSA 密钥对的公钥和私钥以及使用 SHA-256 和 MGF1 SHA-256 填充模式的 OAEP 创建原始 RSA 密钥环。`RSAPublicKey` 和 `RSAPrivateKey` 变量代表您提供的密钥材料。

------
#### [ Java ]

```
final CreateRawRsaKeyringInput keyringInput = CreateRawRsaKeyringInput.builder()
        .keyName("RSA_2048_06")
        .keyNamespace("HSM_01")
        .paddingScheme(PaddingScheme.OAEP_SHA256_MGF1)
        .publicKey(RSAPublicKey)
        .privateKey(RSAPrivateKey)
        .build();
final MaterialProviders matProv = MaterialProviders.builder()
        .MaterialProvidersConfig(MaterialProvidersConfig.builder().build())
        .build();
IKeyring rawRsaKeyring = matProv.CreateRawRsaKeyring(keyringInput);
```

------
#### [ C\$1 / .NET ]

```
var keyNamespace = "HSM_01";
var keyName = "RSA_2048_06";

// Get public and private keys from PEM files
var publicKey = new MemoryStream(System.IO.File.ReadAllBytes("RSAKeyringExamplePublicKey.pem"));
var privateKey = new MemoryStream(System.IO.File.ReadAllBytes("RSAKeyringExamplePrivateKey.pem"));

// Create the keyring input
var keyringInput = new CreateRawRsaKeyringInput
{
    KeyNamespace = keyNamespace,
    KeyName = keyName,
    PaddingScheme = PaddingScheme.OAEP_SHA512_MGF1,
    PublicKey = publicKey,
    PrivateKey = privateKey
};

// Create the keyring
var matProv = new MaterialProviders(new MaterialProvidersConfig());
var rawRsaKeyring = matProv.CreateRawRsaKeyring(keyringInput);
```

------
#### [ Rust ]

```
let mpl_config = MaterialProvidersConfig::builder().build()?;
let mpl = mpl_client::Client::from_conf(mpl_config)?;
let raw_rsa_keyring = mpl
    .create_raw_rsa_keyring()
    .key_name("RSA_2048_06")
    .key_namespace("HSM_01")
    .padding_scheme(PaddingScheme::OaepSha256Mgf1)
    .public_key(RSA_public_key)
    .private_key(RSA_private_key)
    .send()
    .await?;
```

------

# 未加工的 ECDH 钥匙圈
<a name="use-raw-ecdh-keyring"></a>


****  

|  | 
| --- |
| 我们的客户端加密库已重命名为 AWS 数据库加密 SDK。本开发人员指南仍提供有关 [DynamoDB 加密客户端](legacy-dynamodb-encryption-client.md)的信息。 | 

**重要**  
Raw ECDH 密钥环仅在材质提供者库的 1.5.0 版本中可用。

Raw ECDH 密钥环使用您提供的椭圆曲线公私钥对来派生出双方之间的共享包装密钥。首先，密钥环使用发送者的私钥、收件人的公钥和 Elliptic Curve Diffie-Hellman (ECDH) 密钥协议算法派生出共享密钥。然后，密钥环使用共享密钥来派生用于保护您的数据加密密钥的共享包装密钥。 AWS 数据库加密 SDK 使用 (`KDF_CTR_HMAC_SHA384`) 派生共享包装密钥的密钥派生函数符合 [NIST 关于密钥派生的建议](https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-108r1-upd1.pdf)。

密钥派生函数返回 64 字节的密钥材料。为确保双方使用正确的密钥材料， AWS 数据库加密 SDK 使用前 32 字节作为承诺密钥，使用最后 32 字节作为共享封装密钥。解密时，如果密钥环无法复制存储在加密记录材料描述字段中的相同承诺密钥和共享包装密钥，则操作将失败。例如，如果您使用配置有 **Alice 私钥和 **Bob** 公钥的**密钥环对记录进行加密，则使用 B **ob 的私钥和 Alice 的****公钥配置的**密钥环将复制相同的承诺密钥和共享包装密钥，并能够解密该记录。如果 Bob 的公钥来自一 AWS KMS key 对，那么 Bob 可以创建 [AWS KMS ECDH 密钥环](use-kms-ecdh-keyring.md)来解密记录。

Raw ECDH 密钥环使用 AES-GCM 使用对称密钥对记录进行加密。然后使用 AES-GCM 使用派生的共享包装密钥对数据密钥进行信封加密。[每个 Raw ECDH 密钥环只能有一个共享包装密钥，但您可以在多密钥环中单独或与其他密钥环一起包含多个 Raw ECDH 密钥环。](use-multi-keyring.md)

您负责生成、存储和保护您的私钥，最好是在硬件安全模块 (HSM) 或密钥管理系统中。发件人和收件人的密钥对在相同的椭圆曲线上。 AWS 数据库加密 SDK 支持以下椭圆曲线规格：
+ `ECC_NIST_P256`
+ `ECC_NIST_P384`
+ `ECC_NIST_P512`

## 创建原始的 ECDH 密钥环
<a name="raw-ecdh-create"></a>

Raw ECDH 密钥环支持三种密钥协议架构：`RawPrivateKeyToStaticPublicKey`、`EphemeralPrivateKeyToStaticPublicKey`和。`PublicKeyDiscovery`您选择的密钥协议架构决定了您可以执行哪些加密操作以及密钥材料的组装方式。

**Topics**
+ [RawPrivateKeyToStaticPublicKey](#raw-ecdh-RawPrivateKeyToStaticPublicKey)
+ [EphemeralPrivateKeyToStaticPublicKey](#raw-ecdh-EphemeralPrivateKeyToStaticPublicKey)
+ [PublicKeyDiscovery](#raw-ecdh-PublicKeyDiscovery)

### RawPrivateKeyToStaticPublicKey
<a name="raw-ecdh-RawPrivateKeyToStaticPublicKey"></a>

使用`RawPrivateKeyToStaticPublicKey`密钥协议架构在密钥环中静态配置发送者的私钥和收件人的公钥。此密钥协议架构可以加密和解密记录。

要使用密钥协议架构初始化 Raw ECDH `RawPrivateKeyToStaticPublicKey` 密钥环，请提供以下值：
+ **发件人的私钥**

  [您必须提供发件人的 PEM 编码私钥（PKCS \$18 PrivateKeyInfo 结构），如 RFC 5958 中所定义。](https://tools.ietf.org/html/rfc5958#section-2)
+ **收件人的公钥**

  [您必须提供收件人的 DER 编码的 X.509 公钥，也称为 `SubjectPublicKeyInfo` (SPKI)，如 RFC 5280 中所定义。](https://tools.ietf.org/html/rfc5280)

  您可以指定非对称密钥协议 KMS 密钥对的公钥，也可以指定在外部生成的密钥对中的 AWS公钥。
+ **曲线规格**

  标识指定密钥对中的椭圆曲线规范。发件人和收件人的密钥对必须具有相同的曲线规格。

  有效值：`ECC_NIST_P256`、`ECC_NIS_P384`、`ECC_NIST_P512`

------
#### [ C\$1 / .NET ]

```
// Instantiate material providers
var materialProviders = new MaterialProviders(new MaterialProvidersConfig());
	    var BobPrivateKey = new MemoryStream(new byte[] { });
	    var AlicePublicKey = new MemoryStream(new byte[] { });

	    // Create the Raw ECDH static keyring
	    var staticConfiguration = new RawEcdhStaticConfigurations()
	    {
		    RawPrivateKeyToStaticPublicKey = new RawPrivateKeyToStaticPublicKeyInput
		    {
			    SenderStaticPrivateKey = BobPrivateKey,
			    RecipientPublicKey = AlicePublicKey
		    }
	    };
	    
	    var createKeyringInput = new CreateRawEcdhKeyringInput() 
	    {
		    CurveSpec = ECDHCurveSpec.ECC_NIST_P256,
		    KeyAgreementScheme = staticConfiguration 
	    };

	    var keyring = materialProviders.CreateRawEcdhKeyring(createKeyringInput);
```

------
#### [ Java ]

以下 Java 示例使用`RawPrivateKeyToStaticPublicKey`密钥协议架构静态配置发送者的私钥和收件人的公钥。两个密钥对都在`ECC_NIST_P256`曲线上。

```
private static void StaticRawKeyring() {
    // Instantiate material providers
    final MaterialProviders materialProviders =
      MaterialProviders.builder()
        .MaterialProvidersConfig(MaterialProvidersConfig.builder().build())
        .build();

    KeyPair senderKeys = GetRawEccKey();
    KeyPair recipient = GetRawEccKey();

    // Create the Raw ECDH static keyring
    final CreateRawEcdhKeyringInput rawKeyringInput =
      CreateRawEcdhKeyringInput.builder()
        .curveSpec(ECDHCurveSpec.ECC_NIST_P256)
        .KeyAgreementScheme(
          RawEcdhStaticConfigurations.builder()
            .RawPrivateKeyToStaticPublicKey(
                RawPrivateKeyToStaticPublicKeyInput.builder()
                  // Must be a PEM-encoded private key
                  .senderStaticPrivateKey(ByteBuffer.wrap(senderKeys.getPrivate().getEncoded()))
                  // Must be a DER-encoded X.509 public key
                  .recipientPublicKey(ByteBuffer.wrap(recipient.getPublic().getEncoded()))
                  .build()
            )
            .build()
        ).build();

    final IKeyring staticKeyring = materialProviders.CreateRawEcdhKeyring(rawKeyringInput);
}
```

------
#### [ Rust ]

以下 Python 示例使用`raw_ecdh_static_configuration`密钥协议架构静态配置发送者的私钥和接收者的公钥。两个密钥对必须位于同一条曲线上。

```
// Create keyring input
let raw_ecdh_static_configuration_input =
    RawPrivateKeyToStaticPublicKeyInput::builder()
        // Must be a UTF8 PEM-encoded private key
        .sender_static_private_key(private_key_sender_utf8_bytes)
        // Must be a UTF8 DER-encoded X.509 public key
        .recipient_public_key(public_key_recipient_utf8_bytes)
        .build()?;

let raw_ecdh_static_configuration = RawEcdhStaticConfigurations::RawPrivateKeyToStaticPublicKey(raw_ecdh_static_configuration_input);

// Instantiate the material providers library
let mpl_config = MaterialProvidersConfig::builder().build()?;
let mpl = mpl_client::Client::from_conf(mpl_config)?;

// Create raw ECDH static keyring
let raw_ecdh_keyring = mpl
    .create_raw_ecdh_keyring()
    .curve_spec(ecdh_curve_spec)
    .key_agreement_scheme(raw_ecdh_static_configuration)
    .send()
    .await?;
```

------

### EphemeralPrivateKeyToStaticPublicKey
<a name="raw-ecdh-EphemeralPrivateKeyToStaticPublicKey"></a>

使用密钥协议架构配置的`EphemeralPrivateKeyToStaticPublicKey`密钥环在本地创建新的密钥对，并为每个加密调用派生一个唯一的共享包装密钥。

此密钥协议架构只能加密记录。要解密使用密`EphemeralPrivateKeyToStaticPublicKey`钥协议架构加密的记录，必须使用配置有相同收件人公钥的发现密钥协议架构。要解密，您可以使用带有密钥协议算法的原始 ECDH 密钥环，或者，如果接收者的公[`PublicKeyDiscovery`](#raw-ecdh-PublicKeyDiscovery)钥来自非对称密钥协议 KMS 密钥对，则可以将 AWS KMS ECDH 密钥环与密钥协议架构一起使用。[KmsPublicKeyDiscovery](use-kms-ecdh-keyring.md#kms-ecdh-discovery)

要使用密钥协议架构初始化 Raw ECDH `EphemeralPrivateKeyToStaticPublicKey` 密钥环，请提供以下值：
+ **收件人的公钥**

  [您必须提供收件人的 DER 编码的 X.509 公钥，也称为 `SubjectPublicKeyInfo` (SPKI)，如 RFC 5280 中所定义。](https://tools.ietf.org/html/rfc5280)

  您可以指定非对称密钥协议 KMS 密钥对的公钥，也可以指定在外部生成的密钥对中的 AWS公钥。
+ **曲线规格**

  标识指定公钥中的椭圆曲线规范。

  加密时，密钥环会在指定曲线上创建新的密钥对，并使用新的私钥和指定的公钥来派生共享的包装密钥。

  有效值：`ECC_NIST_P256`、`ECC_NIS_P384`、`ECC_NIST_P512`

------
#### [ C\$1 / .NET ]

以下示例使用密钥协议架构创建一个 Raw ECDH `EphemeralPrivateKeyToStaticPublicKey` 密钥环。加密后，密钥环将在指定`ECC_NIST_P256`曲线上本地创建一个新的密钥对。

```
// Instantiate material providers
var materialProviders = new MaterialProviders(new MaterialProvidersConfig());
	    var AlicePublicKey = new MemoryStream(new byte[] { });

	    // Create the Raw ECDH ephemeral keyring
	    var ephemeralConfiguration = new RawEcdhStaticConfigurations()
	    {
		    EphemeralPrivateKeyToStaticPublicKey = new EphemeralPrivateKeyToStaticPublicKeyInput
		    {
			    RecipientPublicKey = AlicePublicKey
		    }
	    };
	    
	    var createKeyringInput = new CreateRawEcdhKeyringInput() 
	    {
		    CurveSpec = ECDHCurveSpec.ECC_NIST_P256,
		    KeyAgreementScheme = ephemeralConfiguration
	    };

	    var keyring = materialProviders.CreateRawEcdhKeyring(createKeyringInput);
```

------
#### [ Java ]

以下示例使用密钥协议架构创建一个 Raw ECDH `EphemeralPrivateKeyToStaticPublicKey` 密钥环。加密后，密钥环将在指定`ECC_NIST_P256`曲线上本地创建一个新的密钥对。

```
private static void EphemeralRawEcdhKeyring() {
    // Instantiate material providers
    final MaterialProviders materialProviders =
      MaterialProviders.builder()
        .MaterialProvidersConfig(MaterialProvidersConfig.builder().build())
        .build();

    ByteBuffer recipientPublicKey = getPublicKeyBytes();

    // Create the Raw ECDH ephemeral keyring
    final CreateRawEcdhKeyringInput ephemeralInput =
      CreateRawEcdhKeyringInput.builder()
        .curveSpec(ECDHCurveSpec.ECC_NIST_P256)
        .KeyAgreementScheme(
          RawEcdhStaticConfigurations.builder()
            .EphemeralPrivateKeyToStaticPublicKey(
              EphemeralPrivateKeyToStaticPublicKeyInput.builder()
                .recipientPublicKey(recipientPublicKey)
                .build()
            )
            .build()
        ).build();

    final IKeyring ephemeralKeyring = materialProviders.CreateRawEcdhKeyring(ephemeralInput);
}
```

------
#### [ Rust ]

以下示例使用密钥协议架构创建一个 Raw ECDH `ephemeral_raw_ecdh_static_configuration` 密钥环。加密后，密钥环将在指定曲线上本地创建一个新的密钥对。

```
// Create EphemeralPrivateKeyToStaticPublicKeyInput
let ephemeral_raw_ecdh_static_configuration_input =
    EphemeralPrivateKeyToStaticPublicKeyInput::builder()
        // Must be a UTF8 DER-encoded X.509 public key
        .recipient_public_key(public_key_recipient_utf8_bytes)
        .build()?;

let ephemeral_raw_ecdh_static_configuration =
    RawEcdhStaticConfigurations::EphemeralPrivateKeyToStaticPublicKey(ephemeral_raw_ecdh_static_configuration_input);

// Instantiate the material providers library
let mpl_config = MaterialProvidersConfig::builder().build()?;
let mpl = mpl_client::Client::from_conf(mpl_config)?;

// Create raw ECDH ephemeral private key keyring
let ephemeral_raw_ecdh_keyring = mpl
    .create_raw_ecdh_keyring()
    .curve_spec(ecdh_curve_spec)
    .key_agreement_scheme(ephemeral_raw_ecdh_static_configuration)
    .send()
    .await?;
```

------

### PublicKeyDiscovery
<a name="raw-ecdh-PublicKeyDiscovery"></a>

解密时，最佳做法是指定 AWS 数据库加密 SDK 可以使用的包装密钥。要遵循此最佳实践，请使用同时指定发件人私钥和收件人公钥的 ECDH 密钥环。但是，您也可以创建原始ECDH发现密钥环，即原始ECDH密钥环，该密钥环可以解密任何记录，其中指定密钥的公钥与存储在加密记录的材料描述字段中的接收者的公钥相匹配。此密钥协议架构只能解密记录。

**重要**  
使用密`PublicKeyDiscovery`钥协议架构解密记录时，无论谁拥有所有公钥，都将接受所有公钥。

要使用密钥协议架构初始化 Raw ECDH `PublicKeyDiscovery` 密钥环，请提供以下值：
+ **收件人的静态私钥**

  [您必须提供收件人的 PEM 编码私钥（PKCS \$18 PrivateKeyInfo 结构），如 RFC 5958 中所定义。](https://tools.ietf.org/html/rfc5958#section-2)
+ **曲线规格**

  标识指定私钥中的椭圆曲线规范。发件人和收件人的密钥对必须具有相同的曲线规格。

  有效值：`ECC_NIST_P256`、`ECC_NIS_P384`、`ECC_NIST_P512`

------
#### [ C\$1 / .NET ]

以下示例使用密钥协议架构创建一个 Raw ECDH `PublicKeyDiscovery` 密钥环。该密钥环可以解密任何记录，其中指定私钥的公钥与存储在加密记录的材料描述字段中的接收者的公钥相匹配。

```
// Instantiate material providers
var materialProviders = new MaterialProviders(new MaterialProvidersConfig());
	    var AlicePrivateKey = new MemoryStream(new byte[] { });

	    // Create the Raw ECDH discovery keyring
	    var discoveryConfiguration = new RawEcdhStaticConfigurations()
	    {
		    PublicKeyDiscovery = new PublicKeyDiscoveryInput
		    {
			    RecipientStaticPrivateKey = AlicePrivateKey
		    }
	    };
	    
	    var createKeyringInput = new CreateRawEcdhKeyringInput() 
	    {
		    CurveSpec = ECDHCurveSpec.ECC_NIST_P256,
		    KeyAgreementScheme = discoveryConfiguration 
	    };

	    var keyring = materialProviders.CreateRawEcdhKeyring(createKeyringInput);
```

------
#### [ Java ]

以下示例使用密钥协议架构创建一个 Raw ECDH `PublicKeyDiscovery` 密钥环。该密钥环可以解密任何记录，其中指定私钥的公钥与存储在加密记录的材料描述字段中的接收者的公钥相匹配。

```
private static void RawEcdhDiscovery() {
    // Instantiate material providers
    final MaterialProviders materialProviders =
      MaterialProviders.builder()
        .MaterialProvidersConfig(MaterialProvidersConfig.builder().build())
        .build();

    KeyPair recipient = GetRawEccKey();

    // Create the Raw ECDH discovery keyring
    final CreateRawEcdhKeyringInput rawKeyringInput =
      CreateRawEcdhKeyringInput.builder()
        .curveSpec(ECDHCurveSpec.ECC_NIST_P256)
        .KeyAgreementScheme(
          RawEcdhStaticConfigurations.builder()
            .PublicKeyDiscovery(
              PublicKeyDiscoveryInput.builder()
                // Must be a PEM-encoded private key
                .recipientStaticPrivateKey(ByteBuffer.wrap(sender.getPrivate().getEncoded()))
                .build()
            )
            .build()
        ).build();

    final IKeyring publicKeyDiscovery  = materialProviders.CreateRawEcdhKeyring(rawKeyringInput);
}
```

------
#### [ Rust ]

以下示例使用密钥协议架构创建一个 Raw ECDH `discovery_raw_ecdh_static_configuration` 密钥环。此密钥环可以解密任何消息，其中指定私钥的公钥与存储在消息密文中的收件人的公钥相匹配。

```
// Create PublicKeyDiscoveryInput
let discovery_raw_ecdh_static_configuration_input =
    PublicKeyDiscoveryInput::builder()
        // Must be a UTF8 PEM-encoded private key
        .recipient_static_private_key(private_key_recipient_utf8_bytes)
        .build()?;

let discovery_raw_ecdh_static_configuration =
    RawEcdhStaticConfigurations::PublicKeyDiscovery(discovery_raw_ecdh_static_configuration_input);

// Create raw ECDH discovery private key keyring
let discovery_raw_ecdh_keyring = mpl
    .create_raw_ecdh_keyring()
    .curve_spec(ecdh_curve_spec)
    .key_agreement_scheme(discovery_raw_ecdh_static_configuration)
    .send()
    .await?;
```

------

# 多重密钥环
<a name="use-multi-keyring"></a>


****  

|  | 
| --- |
| 我们的客户端加密库已重命名为 AWS 数据库加密 SDK。本开发人员指南仍提供有关 [DynamoDB 加密客户端](legacy-dynamodb-encryption-client.md)的信息。 | 

您可以将多个密钥环合并为一个多重密钥环。*多重密钥环* 是由一个或多个相同或不同类型的密钥环组成的密钥环。效果与连续使用多个密钥环类似。在使用多重密钥环加密数据时，其任意密钥环中的任意包装密钥都可以对数据进行解密。

在创建多重密钥环以加密数据时，您可以将一个密钥环指定为*生成器密钥环*。所有其他密钥环称为*子密钥环*。生成器密钥环生成并加密明文数据密钥。然后，所有子密钥环中的所有包装密钥都加密相同的明文数据密钥。对于多重密钥环中的每个包装密钥，多重密钥环都返回明文密钥和一个加密的数据密钥。如果生成器密钥环是 [KMS 密钥环](use-kms-keyring.md)，则密钥 AWS KMS 环中的生成器密钥会生成并加密纯文本密钥。然后，密钥环 AWS KMS keys 中的所有其他密钥，以及多密 AWS KMS 钥环中所有子密钥环中的所有封装密钥，都将加密相同的纯文本密钥。

解密时， AWS 数据库加密 SDK 使用密钥环尝试解密其中一个加密的数据密钥。密钥环是按照在多重密钥环中指定的顺序调用的。只要任何密钥环中的任何密钥可以解密加密的数据密钥，处理就会立即停止。

要创建多重密钥环，首先要实例化子密钥环。在此示例中，我们使用 AWS KMS 密钥环和 Raw AES 密钥环，但您可以将任何支持的密钥环组合到一个多密钥环中。

------
#### [ Java ]

```
// 1. Create the raw AES keyring.
final MaterialProviders matProv = MaterialProviders.builder()
        .MaterialProvidersConfig(MaterialProvidersConfig.builder().build())
        .build();
final CreateRawAesKeyringInput createRawAesKeyringInput = CreateRawAesKeyringInput.builder()
        .keyName("AES_256_012")
        .keyNamespace("HSM_01")
        .wrappingKey(AESWrappingKey)
        .wrappingAlg(AesWrappingAlg.ALG_AES256_GCM_IV12_TAG16)
        .build();
IKeyring rawAesKeyring = matProv.CreateRawAesKeyring(createRawAesKeyringInput);

// 2. Create the AWS KMS keyring.
final CreateAwsKmsMrkMultiKeyringInput createAwsKmsMrkMultiKeyringInput = CreateAwsKmsMrkMultiKeyringInput.builder()
        .generator(kmsKeyArn)
        .build();
IKeyring awsKmsMrkMultiKeyring = matProv.CreateAwsKmsMrkMultiKeyring(createAwsKmsMrkMultiKeyringInput);
```

------
#### [ C\$1 / .NET ]

```
// 1. Create the raw AES keyring.
var keyNamespace = "HSM_01";
var keyName = "AES_256_012";
                    
var matProv = new MaterialProviders(new MaterialProvidersConfig());
var createRawAesKeyringInput = new CreateRawAesKeyringInput
{
    KeyName = "keyName",
    KeyNamespace = "myNamespaces",
    WrappingKey = AESWrappingKey,
    WrappingAlg = AesWrappingAlg.ALG_AES256_GCM_IV12_TAG16
};
var rawAesKeyring = matProv.CreateRawAesKeyring(createRawAesKeyringInput);
                
// 2. Create the AWS KMS keyring.
//    We create a MRK multi keyring, as this interface also supports
//    single-region KMS keys,
//    and creates the KMS client for us automatically.
var createAwsKmsMrkMultiKeyringInput = new CreateAwsKmsMrkMultiKeyringInput
{
    Generator = keyArn
};
var awsKmsMrkMultiKeyring = matProv.CreateAwsKmsMrkMultiKeyring(createAwsKmsMrkMultiKeyringInput);
```

------
#### [ Rust ]

```
// 1. Create the raw AES keyring
let mpl_config = MaterialProvidersConfig::builder().build()?;
let mpl = mpl_client::Client::from_conf(mpl_config)?;

let raw_aes_keyring = mpl
    .create_raw_aes_keyring()
    .key_name("AES_256_012")
    .key_namespace("HSM_01")
    .wrapping_key(aes_key_bytes)
    .wrapping_alg(AesWrappingAlg::AlgAes256GcmIv12Tag16)
    .send()
    .await?;                
                
// 2. Create the AWS KMS keyring
let aws_kms_mrk_multi_keyring = mpl
    .create_aws_kms_mrk_multi_keyring()
    .generator(key_arn)
    .send()
    .await?;
```

------

接下来创建多重密钥环并指定其生成器密钥环（如果有）。在此示例中，我们创建了一个多密钥环，其中密钥环是生成器 AWS KMS 密钥环，AES 密钥环是子密钥环。

------
#### [ Java ]

Java `CreateMultiKeyringInput` 构造函数允许您定义生成器密钥环和子密钥环。生成的 `createMultiKeyringInput` 对象不可变。

```
final CreateMultiKeyringInput createMultiKeyringInput = CreateMultiKeyringInput.builder()
        .generator(awsKmsMrkMultiKeyring)
        .childKeyrings(Collections.singletonList(rawAesKeyring))
        .build();
IKeyring multiKeyring = matProv.CreateMultiKeyring(createMultiKeyringInput);
```

------
#### [ C\$1 / .NET ]

 .NET `CreateMultiKeyringInput` 构造函数允许您定义生成器密钥环和子密钥环。生成的 `CreateMultiKeyringInput` 对象不可变。

```
var createMultiKeyringInput = new CreateMultiKeyringInput
{
    Generator = awsKmsMrkMultiKeyring,
    ChildKeyrings = new List<IKeyring> { rawAesKeyring }
};
var multiKeyring = matProv.CreateMultiKeyring(createMultiKeyringInput);
```

------
#### [ Rust ]

```
let multi_keyring = mpl
    .create_multi_keyring()
    .generator(aws_kms_mrk_multi_keyring)
    .child_keyrings(vec![raw_aes_keyring.clone()])
    .send()
    .await?;
```

------

现在，您就可以使用此多重密钥环加密和解密数据了。