

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

# 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\# / .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\# / .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?;
```

------