

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

# 旧版 DynamoDB 加密客户端
<a name="legacy-dynamodb-encryption-client"></a>

2023 年 6 月 9 日，我们的客户端加密库更名为 AWS 数据库加密 SDK。 AWS 数据库加密 SDK 继续支持旧版 DynamoDB 加密客户端版本。有关客户端加密库中随重命名发生更改的不同部分的更多信息，请参阅 [Amazon DynamoDB Encryption Client 重命名](DDBEC-rename.md)。

要迁移到最新版本的适用于 DynamoDB 的 Java 客户端加密库，请参阅 [迁移到版本 3.x](ddb-java-migrate.md)。

**Topics**
+ [AWS 适用于 DynamoDB 的数据库加密 SDK 版本支持](#legacy-support)
+ [DynamoDB 加密客户端的工作原理](DDBEC-legacy-how-it-works.md)
+ [Amazon DynamoDB Encryption Client 概念](DDBEC-legacy-concepts.md)
+ [加密材料提供程序](crypto-materials-providers.md)
+ [Amazon DynamoDB Encryption Client 可用的编程语言](programming-languages.md)
+ [更改数据模型](data-model.md)
+ [排查 DynamoDB 加密客户端应用程序中的问题](troubleshooting.md)

## AWS 适用于 DynamoDB 的数据库加密 SDK 版本支持
<a name="legacy-support"></a>

旧版章节中的主题提供有关适用于 Java 的 DynamoDB 加密客户端版本 1.*x*—2.*x* 以及适用于 Python 的 DynamoDB 加密客户端版本 1.*x*—3.*x* 的信息。

下表所列为在 Amazon DynamoDB 中支持客户端加密的语言和版本。


| 编程语言 | 版本 | SDK 主要版本的生命周期阶段 | 
| --- | --- | --- | 
|  Java  |  版本 1.*x*  |  [End-of-Support 阶段](https://docs.aws.amazon.com/sdkref/latest/guide/maint-policy.html#version-life-cycle)，2022 年 7 月生效  | 
|  Java  |  版本 2.*x*  |  [正式发布](https://docs.aws.amazon.com/sdkref/latest/guide/maint-policy.html#version-life-cycle)（GA）  | 
|  Java  |  版本 3.*x*  |  [正式发布](https://docs.aws.amazon.com/sdkref/latest/guide/maint-policy.html#version-life-cycle)（GA）  | 
|  Python  |  版本 1.*x*  |  [End-of-Support 阶段](https://docs.aws.amazon.com/sdkref/latest/guide/maint-policy.html#version-life-cycle)，2022 年 7 月生效  | 
|  Python  |  版本 2.*x*  |  [End-of-Support 阶段](https://docs.aws.amazon.com/sdkref/latest/guide/maint-policy.html#version-life-cycle)，2022 年 7 月生效  | 
|  Python  |  版本 3.*x*  |  [正式发布](https://docs.aws.amazon.com/sdkref/latest/guide/maint-policy.html#version-life-cycle)（GA）  | 

# DynamoDB 加密客户端的工作原理
<a name="DDBEC-legacy-how-it-works"></a>

**注意**  
我们的客户端加密库已[重命名为 AWS 数据库加密 SDK](DDBEC-rename.md)。以下主题提供有关适用于 Java 的 DynamoDB 加密客户端版本 1.*x*—2.*x* 以及适用于 Python 的 DynamoDB 加密客户端版本 1.*x*—3.*x* 的信息。有关更多信息，请参阅[适用于 DynamoDB 的AWS 数据库加密 SDK 版本支持](legacy-dynamodb-encryption-client.md#legacy-support)。

DynamoDB 加密客户端专门设计为保护存储在 DynamoDB 中的数据。库包含可以直接扩展或使用的安全实施。大多数元素由抽象元素表示，因此可以创建和使用兼容的自定义组件。

**为表项目加密和签名**

负责对表项目进行加密、签名、验证和解密的*项目加密程序*是 DynamoDB 加密客户端的核心。它取得表项目信息，以及要加密和签名的项目说明，它将从您选择并配置的[加密材料提供程序](DDBEC-legacy-concepts.md#concept-material-provider)获取加密材料和加密材料的使用说明。

下图显示了此流程的高级视图。

![\[对 DynamoDB 加密客户端中的项目进行加密和签名\]](http://docs.aws.amazon.com/zh_cn/database-encryption-sdk/latest/devguide/images/arch-encrypt.png)


要对表项目进行加密和签名，DynamoDB 加密客户端需要：
+ **表的相关信息。**它从提供的 [DynamoDB 加密上下文](concepts.md#encryption-context)获取有关表的信息。某些帮助程序从 DynamoDB 获取必需信息并创建 DynamoDB 加密上下文。
**注意**  
*DynamoDB 加密*客户端中的 DynamoDB 加密上下文与 () 和中的加密上下*文*无关。 AWS Key Management Service AWS KMS AWS Encryption SDK
+ **要加密和签名的属性。**它从提供的[属性操作](DDBEC-legacy-concepts.md#legacy-attribute-actions)获取此信息。
+ **加密材料，包括加密密钥和签名密钥。**它从您选择并配置的[加密材料提供程序](DDBEC-legacy-concepts.md#concept-material-provider) (CMP) 获取这些信息。
+ **为项目加密和签名的说明**。CMP 会将加密材料（包括加密和签名算法）使用说明添加到[实际材料描述](DDBEC-legacy-concepts.md#legacy-material-description)。

[项目加密程序](DDBEC-legacy-concepts.md#item-encryptor)将使用所有这些元素为项目加密和签名。此外，项目加密程序将两个属性添加到项目：包含加密和签名说明（实际材料描述）的[材料描述属性](DDBEC-legacy-concepts.md#legacy-material-description)以及包含签名的属性。可以直接与项目加密程序交互，或使用与项目加密程序交互的帮助程序功能以实施安全默认行为。

结果是包含已加密和已签名数据的 DynamoDB 项目。

**验证和解密表项目**

这些组件还一起运行来验证和解密项目，如下图所示。

![\[对 DynamoDB 加密客户端中的项目进行验证和解密\]](http://docs.aws.amazon.com/zh_cn/database-encryption-sdk/latest/devguide/images/arch-decrypt.png)


要验证和解密项目，DynamoDB 加密客户端要相同的组件、配置相同的组件或专门为解密项目设计的组件，如下所示：
+ **来自 [DynamoDB 加密上下文](concepts.md#encryption-context)的有关表的信息**。
+ **要验证和解密的属性。**它将从[属性操作](DDBEC-legacy-concepts.md#legacy-attribute-actions)获取这些属性。
+ 您选择和配置的[加密材料提供程序](DDBEC-legacy-concepts.md#concept-material-provider)（CMP）中的**解密材料，包括验证和解密密钥**。

  已加密项目不包括为它加密所使用的 CMP 的任何记录。您必须提供相同的 CMP、配置相同的 CMP 或设计为解密项目的 CMP。
+ **有关如何加密项目和为项目签名的信息**，包括加密和签名算法。客户端将从项目的[材料描述属性](DDBEC-legacy-concepts.md#legacy-material-description)中获取这些信息。

[项目加密程序](DDBEC-legacy-concepts.md#item-encryptor)将使用所有这些元素验证和解密项目。它还将删除材料描述和签名属性。结果是明文 DynamoDB 项目。

# Amazon DynamoDB Encryption Client 概念
<a name="DDBEC-legacy-concepts"></a>

**注意**  
我们的客户端加密库已[重命名为 AWS 数据库加密 SDK](DDBEC-rename.md)。以下主题提供有关适用于 Java 的 DynamoDB 加密客户端版本 1.*x*—2.*x* 以及适用于 Python 的 DynamoDB 加密客户端版本 1.*x*—3.*x* 的信息。有关更多信息，请参阅[适用于 DynamoDB 的AWS 数据库加密 SDK 版本支持](legacy-dynamodb-encryption-client.md#legacy-support)。

本主题介绍 Amazon DynamoDB Encryption Client 中使用的概念和术语。

要了解 DynamoDB 加密客户端的组件如何交互，请参阅 [DynamoDB 加密客户端的工作原理](DDBEC-legacy-how-it-works.md)。

**Topics**
+ [加密材料提供程序 (CMP)](#concept-material-provider)
+ [项目加密程序](#item-encryptor)
+ [属性操作](#legacy-attribute-actions)
+ [材料描述](#legacy-material-description)
+ [DynamoDB 加密上下文](#legacy-encryption-context)
+ [提供程序存储](#provider-store)

## 加密材料提供程序 (CMP)
<a name="concept-material-provider"></a>

在实施 DynamoDB 加密客户端时，第一批任务中有一个任务是[选择加密材料提供程序](crypto-materials-providers.md)（CMP）（又称为*加密材料提供程序*）。您的选择决定了剩下的大部分实施操作。

*加密材料提供程序* (CMP) 收集、汇编并返回[项目加密程序](#item-encryptor)用于为表项目加密和签名的加密材料。CMP 确定要使用的加密算法以及如何生成和保护加密和签名密钥。

CMP 与项目加密程序交互。项目加密程序从 CMP 请求加密或解密材料，而 CMP 将这些材料返回给项目加密程序。然后，项目加密程序使用加密材料为项目加密和签名，或验证和解密项目。

在配置客户端时指定 CMP。您可以创建兼容的自定义 CMP，也可以使用库 CMPs 中的众多自定义 CMP 之一。大多数 CMPs 都适用于多种编程语言。

## 项目加密程序
<a name="item-encryptor"></a>

*项目加密程序*是为 DynamoDB 加密客户端执行加密操作的低级别组件。它从[加密材料提供程序](#concept-material-provider) (CMP) 请求加密材料，然后使用 CMP 返回的材料为表项目加密和签名，或验证和解密表项目。

可以直接与项目加密程序交互或使用库提供的帮助程序。例如，适用于 Java 的 DynamoDB 加密客户端包含可与 `DynamoDBMapper` 一起使用的 `AttributeEncryptor` 帮助程序类，而不是直接与 `DynamoDBEncryptor` 项目加密程序交互。Python 库包含与项目加密程序交互的 `EncryptedTable`、`EncryptedClient` 和 `EncryptedResource` 帮助程序类。

## 属性操作
<a name="legacy-attribute-actions"></a>

*属性操作*告知项目加密程序将对项目的每个属性执行哪些操作。

属性操作值可以是以下任何值：
+ **加密和签名** – 加密属性值。在项目签名中包含属性（名称和值）。
+ **仅签名** – 在项目签名中包含属性。
+ **不执行任何操作** – 不为属性加密或签名。

对于可能存储敏感数据的任何属性，请使用 **Encrypt and sign (加密和签名)**。对于主键属性（分区键和排序键），使用 **Sign only**。不会为[材料描述属性](#legacy-material-description)和签名属性签名或加密。无需为这些属性指定属性操作。

仔细选择属性操作。如有怀疑，请使用 **Encrypt and sign (加密和签名)**。一旦使用 DynamoDB 加密客户端来保护表项，就无法在不冒签名验证错误风险的情况下更改属性的操作。有关更多信息，请参阅 [更改数据模型](data-model.md)。

**警告**  
请勿加密主键属性。它们必须保留为明文，以便 DynamoDB 查找项目而无需运行全表扫描。

如果 [DynamoDB 加密上下文](concepts.md#encryption-context)标识您的主键属性，则客户端将在您尝试加密这些属性时引发错误。

对于每种编程语言而言，用于指定属性操作的技术各不相同。此技术还可能特定于使用的帮助程序类。

有关详细信息，请参阅编程语言对应的文档。
+ [Python](python-using.md#python-attribute-actions)
+ [Java](java-using.md#attribute-actions-java)

## 材料描述
<a name="legacy-material-description"></a>

已加密表项目的*材料描述* 包含有关如何为表项目加密和签名的信息（如加密算法）。[加密材料提供程序](#concept-material-provider) (CMP) 将在汇编用于加密和签名的加密材料时记录材料描述。之后，当它需要汇编加密材料以验证和解密项目时，它将使用材料描述作为指南。

在 DynamoDB 加密客户端中，材料描述引用三个相关元素：

**请求的材料描述**  
某些[加密材料提供程序](#concept-material-provider) (CMPs) 允许您指定高级选项，例如加密算法。要指明您的选择，请将名称-值对添加到表项目加密请求中 [DynamoDB 加密上下文](concepts.md#encryption-context)的材料描述属性中。此元素也称为*请求的材料描述*。请求的材料描述中的有效值由您选择的 CMP 定义。  
由于材料描述会覆盖安全默认值，因此建议忽略请求的材料描述，除非有不得已的原因要使用它。

**实际材料描述**  
[加密材料提供者 (CMPs) 返回的材料](#concept-material-provider)描述称为*实际材料描述*。它描述 CMP 在汇编加密材料时使用的实际值。它一般包括请求的描述材料（如有），请求的描述材料有增加和更改。

**材料描述属性**  
客户端将实际材料描述保存在已加密项目的*材料描述属性* 中。材料描述属性名称为 `amzn-ddb-map-desc` 并且其值为实际材料描述。客户端将使用材料描述属性中的值验证和解密项目。

## DynamoDB 加密上下文
<a name="legacy-encryption-context"></a>

*DynamoDB 加密上下文* 为[加密材料提供程序](#concept-material-provider)（CMP）提供有关表和项目的信息。在高级实施中，DynamoDB 加密上下文可以包括[请求的材料描述](#legacy-material-description)。

在对表项目进行加密时，DynamoDB 加密上下文将以加密方式绑定到加密的属性值。当您解密时，如果 DynamoDB 加密上下文与用于加密的 DynamoDB 加密上下文不是区分大小写的完全匹配，则解密操作将失败。如果您与[项目加密程序](#item-encryptor)直接交互，则必须在调用加密或解密方法时提供 DynamoDB 加密上下文。大多数帮助程序将创建 DynamoDB 加密上下文。

**注意**  
*DynamoDB 加密*客户端中的 DynamoDB 加密上下文与 () 和中的加密上下*文*无关。 AWS Key Management Service AWS KMS AWS Encryption SDK

DynamoDB 加密上下文可以包含以下字段。所有字段和值均为可选项。
+ 表名
+ 分区键名称
+ 排序键名称
+ 属性名称/值对
+ [请求的材料描述](#legacy-material-description)

## 提供程序存储
<a name="provider-store"></a>

提供*商存储*是返回[加密材料提供者](#concept-material-provider) (CMPs) 的组件。提供商商店可以创建 CMPs 或从其他来源（例如其他提供商商店）获取它们。提供商存储将其创建的 CMPs 版本保存在永久存储中，其中每个存储的 CMP 都由请求者的材料名称和版本号标识。

DynamoDB 加密客户端中的[最新提供](most-recent-provider.md)程序来自提供程序存储，但您可以使用提供程序存储为 CMPs 任何组件提供该提供程序。 CMPs 每个最新提供程序都与一个提供商存储相关联，但一个提供商存储可以 CMPs 向多个主机的多个请求者提供服务。

提供商商店按需创建新版本，并返回新版本和现有版本。 CMPs 它还将返回指定材料名称的最新版本号。这使请求者知道提供程序存储何时具有它可请求的 CMP 的新版本。

DynamoDB 加密客户端包括[ MetaStore](most-recent-provider.md#about-metastore)一个，它是一个提供商存储，它使用存储在 DynamoDB 中并使用内部 DynamoDB 加密客户端加密的密钥创建 Wr CMPs apped。

**了解更多：**
+ 提供程序存储：[Java](https://aws.github.io/aws-dynamodb-encryption-java/com/amazonaws/services/dynamodbv2/datamodeling/encryption/providers/store/ProviderStore.html)、[Python](https://github.com/aws/aws-dynamodb-encryption-python/blob/master/src/dynamodb_encryption_sdk/material_providers/store/__init__.py)
+ MetaStore: [Java](https://aws.github.io/aws-dynamodb-encryption-java/com/amazonaws/services/dynamodbv2/datamodeling/encryption/providers/store/MetaStore.html)、[Python](https://aws-dynamodb-encryption-python.readthedocs.io/en/latest/lib/materials_providers/metastore.html#module-dynamodb_encryption_sdk.material_providers.store.meta)

# 加密材料提供程序
<a name="crypto-materials-providers"></a>

**注意**  
我们的客户端加密库已[重命名为 AWS 数据库加密 SDK](DDBEC-rename.md)。以下主题提供有关适用于 Java 的 DynamoDB 加密客户端版本 1.*x*—2.*x* 以及适用于 Python 的 DynamoDB 加密客户端版本 1.*x*—3.*x* 的信息。有关更多信息，请参阅[适用于 DynamoDB 的AWS 数据库加密 SDK 版本支持](legacy-dynamodb-encryption-client.md#legacy-support)。

您在使用 DynamoDB 加密客户端时所做的最重要的决策是选择[加密材料提供程序](DDBEC-legacy-concepts.md#concept-material-provider)（CMP）。CMP 组装加密材料并将其返回到项目加密程序。它还确定如何生成加密密钥和签名密钥，新密钥材料是否对于每个项目进行生成或重复使用以及所使用的加密和签名算法。

您可以选择 DynamoDB 加密客户端库中提供的实施中的 CMP 或构建兼容的自定义 CMP。您的 CMP 选择还可能取决于使用的[编程语言](programming-languages.md)。

本主题介绍了最常见的内容， CMPs 并提供了一些建议，以帮助您为应用程序选择最佳方案。

**Direct KMS 材料提供程序**  
Direct KMS 材料提供程序借助 [AWS KMS key](https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#master_keys) 保护您的表项目，该主密钥绝不会让 [AWS Key Management Service](https://docs.aws.amazon.com/kms/latest/developerguide/)（AWS KMS）处于不加密状态。您的应用程序不必生成或管理任何加密材料。由于该 AWS KMS key 提供程序使用为每个项目生成唯一的加密和签名密钥，因此它 AWS KMS 每次加密或解密项目时都会调用。  
如果您使用 AWS KMS 并且每笔交易一次 AWS KMS 调用适合您的应用程序，那么此提供商是一个不错的选择。  
有关更多信息，请参阅 [Direct KMS 材料提供程序](direct-kms-provider.md)。

**已包装的材料提供程序（已包装的 CMP）**  
利用已包装的材料提供程序（已包装的 CMP），您可以在 DynamoDB 加密客户端外部生成和管理包装密钥和签名密钥。  
已包装的 CMP 会为每个项目生成唯一加密密钥。然后，它会使用您提供的包装（或解开包装）密钥和签名密钥。因此，您可确定如何生成包装密钥和签名密钥以及这些密钥对于每个项目是唯一的还是可重复使用。Wrapped CMP 是 Di [rect KMS 提供程序](direct-kms-provider.md)的安全替代方案，适用于不使用加密材料 AWS KMS 且可以安全管理加密材料的应用程序。  
有关更多信息，请参阅 [已包装的材料提供程序](wrapped-provider.md)。

**最新提供程序**  
*最新提供程序*是一个[加密材料提供程序](DDBEC-legacy-concepts.md#concept-material-provider)（CMP），旨在处理[提供程序存储](DDBEC-legacy-concepts.md#provider-store)。它 CMPs从提供商商店获取，并从中获取返回的加密材料。 CMPs最新提供程序通常使用每个 CMP 来满足加密材料的多个请求，但您可以使用提供程序存储的功能来控制可重复使用材料的范围，决定轮换其 CMP 的频率以及甚至在不更改最新提供程序的情况下更改所使用的 CMP 的类型。  
您可以结合使用最新提供程序与任何兼容的提供程序存储。DynamoDB 加密客户端包括 MetaStore一个，这是一个返回 Wrapped 的提供商存储。 CMPs  
对于需要最大程度地减少对加密源的调用的应用程序，以及能够在不违反应用程序的安全性要求的情况下重复使用某些加密材料的应用程序，最新提供程序是个很好的选择。例如，它允许您在 in [AWS Key Management Service](https://docs.aws.amazon.com/kms/latest/developerguide/)(AWS KMS) 下保护您的加密材料，而无需[AWS KMS key](https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#master_keys)在 AWS KMS 每次加密或解密项目时都调用。  
有关更多信息，请参阅 [最新提供程序](most-recent-provider.md)。

**静态材料提供程序**  
静态材料提供商专为测试、 proof-of-concept演示和传统兼容性而设计。它不会为每个项目生成任何唯一加密材料。它将返回您提供的相同加密密钥和签名密钥，而且这些密钥会直接用于加密、解密和签署您的表项目。  
Java 库中的[非对称静态提供程序](https://aws.github.io/aws-dynamodb-encryption-java/com/amazonaws/services/dynamodbv2/datamodeling/encryption/providers/AsymmetricStaticProvider.html)不是一种静态提供程序。它仅提供[已包装的 CMP](wrapped-provider.md) 的替代构造函数。它在生产使用时是安全的，但您应尽可能地直接使用已包装的 CMP。

**Topics**
+ [Direct KMS 材料提供程序](direct-kms-provider.md)
+ [已包装的材料提供程序](wrapped-provider.md)
+ [最新提供程序](most-recent-provider.md)
+ [静态材料提供程序](static-provider.md)

# Direct KMS 材料提供程序
<a name="direct-kms-provider"></a>

**注意**  
我们的客户端加密库已[重命名为 AWS 数据库加密 SDK](DDBEC-rename.md)。以下主题提供有关适用于 Java 的 DynamoDB 加密客户端版本 1.*x*—2.*x* 以及适用于 Python 的 DynamoDB 加密客户端版本 1.*x*—3.*x* 的信息。有关更多信息，请参阅[适用于 DynamoDB 的AWS 数据库加密 SDK 版本支持](legacy-dynamodb-encryption-client.md#legacy-support)。

*Direct KMS 材料提供程序*（Direct KMS 提供程序）借助从不让 [AWS Key Management Service](https://docs.aws.amazon.com/kms/latest/developerguide/)（AWS KMS）处于不加密状态的 [AWS KMS key](https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#master_keys) 保护您的表项目。此[加密材料提供程序](DDBEC-legacy-concepts.md#concept-material-provider)为每个表项目返回唯一的加密密钥和签名密钥。为此，它会在您 AWS KMS 每次加密或解密项目时调用。

如果您以高频率和大规模处理 DynamoDB 项目，则可能会超出限制，从而导致处理 AWS KMS [requests-per-second延](https://docs.aws.amazon.com/kms/latest/developerguide/limits.html#requests-per-second)迟。如果需要超出限制，请在 [AWS 支持 中心](https://console.aws.amazon.com/support/home)并创建案例。您也可以考虑使用密钥重复次数使用有限的加密材料提供程序，例如[最新提供程序](most-recent-provider.md)。

要使用 Direcrypt KMS 提供程序 AWS 账户，调用者必须至少拥有[一个](https://aws.amazon.com/premiumsupport/knowledge-center/create-and-activate-aws-account/)权限 AWS KMS key，才能在上调用[GenerateDataKey](https://docs.aws.amazon.com/kms/latest/APIReference/API_GenerateDataKey.html)和[解密](https://docs.aws.amazon.com/kms/latest/APIReference/API_Decrypt.html)操作。 AWS KMS key AWS KMS key 必须是对称加密密钥；DynamoDB 加密客户端不支持非对称加密。如果您使用的是 [DynamoDB 全局表](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GlobalTables.html)，则可能需要指定一个 [AWS KMS 多区域密钥](https://docs.aws.amazon.com/kms/latest/developerguide/multi-region-keys-overview.html)。有关更多信息，请参阅 [使用方法](#provider-kms-how-to-use)。

**注意**  
当您使用 Direct KMS 提供程序时，您的主密钥属性的名称和值将以纯文本形式显示在[AWS KMS 加密上下文](https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#encrypt_context)和相关 AWS CloudTrail AWS KMS 操作日志中。但是，DynamoDB 加密客户端从不公开任意加密属性值的明文。

直接 KMS 提供程序是 DynamoDB [加密客户端支持的几个加密材料提供商](DDBEC-legacy-concepts.md#concept-material-provider) (CMPs) 之一。有关另一个的信息 CMPs，请参阅[加密材料提供程序](crypto-materials-providers.md)。

**有关示例代码，请参阅：**
+ Java：[AwsKmsEncryptedItem](https://github.com/aws/aws-dynamodb-encryption-java/blob/master/examples/src/main/java/com/amazonaws/examples/AwsKmsEncryptedItem.java)
+ Python: [aws-kms-encrypted-table](https://github.com/aws/aws-dynamodb-encryption-python/blob/master/examples/src/dynamodb_encryption_sdk_examples/aws_kms_encrypted_table.py)，[aws-kms-encrypted-item](https://github.com/aws/aws-dynamodb-encryption-python/blob/master/examples/src/dynamodb_encryption_sdk_examples/aws_kms_encrypted_item.py)

**Topics**
+ [使用方法](#provider-kms-how-to-use)
+ [工作原理](#provider-kms-how-it-works)

## 使用方法
<a name="provider-kms-how-to-use"></a>

要创建 Direct KMS 提供程序，请使用密钥 ID 参数在您的账户中指定对称加密 [KMS 密钥](https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#master_keys)。密钥 ID 参数的值可以是 AWS KMS key的密钥 ID、密钥 ARN、别名名称或别名 ARN。有关密钥标识符的详细信息，请参阅《AWS Key Management Service 开发人员指南》**中的[密钥标识符](https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#key-id)。

Direct KMS 提供程序需要对称的加密 KMS 密钥。不能使用非对称 KMS 密钥。但是，可以使用多区域 KMS 键、包含导入的密钥材料的 KMS 密钥，或自定义密钥存储中的 KMS 密钥。您必须拥有 [KMS 密钥的 kms: GenerateDataKey](https://docs.aws.amazon.com/kms/latest/APIReference/API_GenerateDataKey.html) 和 [kms: decrypt](https://docs.aws.amazon.com/kms/latest/APIReference/API_Decrypt.html) 权限。因此，您必须使用客户托管的密钥，而不是托 AWS 管或 AWS 拥有的 KMS 密钥。

适用于 Python 的 DynamoDB 加密客户端在密钥 ID 参数值（如果包含密钥 ID 参数值）中确定从该区域 AWS KMS 调用的区域。否则，它将使用 AWS KMS 客户端中的区域（如果您指定）或您在中配置的区域 适用于 Python (Boto3) 的 AWS SDK。有关 Python 中区域选择的信息，请参阅 Python AWS 开发工具包 (Boto3) API 参考中的[配置](https://boto3.amazonaws.com/v1/documentation/api/latest/guide/configuration.html)。

如果您指定的客户端包含区域，则适用于 Java 的 DynamoDB 加密客户端 AWS KMS 会确定从客户端中的区域进行 AWS KMS 调用的区域。否则，它将使用您在 适用于 Java 的 AWS SDK中配置的区域。有关中区域选择的信息 适用于 Java 的 AWS SDK，请参阅《 适用于 Java 的 AWS SDK 开发者指南》中的[AWS 区域 选择](https://docs.aws.amazon.com/sdk-for-java/v1/developer-guide/java-dg-region-selection.html)。

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

```
// Replace the example key ARN and Region with valid values for your application
final String keyArn = 'arn:aws:kms:us-west-2:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab'
final String region = 'us-west-2'
      
final AWSKMS kms = AWSKMSClientBuilder.standard().withRegion(region).build();
final DirectKmsMaterialProvider cmp = new DirectKmsMaterialProvider(kms, keyArn);
```

------
#### [ Python ]

以下示例使用密钥 ARN 指定 AWS KMS key。如果您的密钥标识符不包括 AWS 区域，则 DynamoDB 加密客户端将从已配置的 Botocore 会话（如果有）或 Boto 默认会话中获取区域。

```
# Replace the example key ID with a valid value
kms_key = 'arn:aws:kms:us-west-2:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab'
kms_cmp = AwsKmsCryptographicMaterialsProvider(key_id=kms_key)
```

------

如果您使用的是 [Amazon DynamoDB 全局](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GlobalTables.html)表，我们建议您使用多区域密钥对数据进行 AWS KMS 加密。多区域密钥不同 AWS 区域 ，可以互换使用，因为它们具有相同的密钥 ID 和密钥材料。 AWS KMS keys 有关详细信息，请参阅《AWS Key Management Service 开发人员指南》**中的[使用多区域密钥](https://docs.aws.amazon.com/kms/latest/developerguide/multi-region-keys-overview.html)。

**注意**  
如果您使用的是全局表[版本 2017.11.29](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/globaltables.V1.html)，则必须设置属性操作，这样，保留的复制字段就不会被加密或签名。有关更多信息，请参阅 [旧版本全局表存在的问题](troubleshooting.md#fix-global-tables)。

要在 DynamoDB 加密客户端中使用多区域密钥，请创建多区域密钥并将其复制到应用程序运行所在的区域。然后将 Direct KMS 提供程序配置为使用 DynamoDB 加密客户端调用 AWS KMS所在区域中的多区域密钥。

以下示例将 DynamoDB 加密客户端配置为在美国东部（弗吉尼亚州北部）（us-east-1）区域中的加密数据，并使用多区域密钥，在美国西部（俄勒冈州）（us-west-2）区域中对其进行解密。

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

在此示例中，DynamoDB 加密客户端在客户端中获取从该区域进行 AWS KMS 调用的区域。 AWS KMS `keyArn` 值标识同一区域中的多区域密钥。

```
// Encrypt in us-east-1

// Replace the example key ARN and Region with valid values for your application
final String usEastKey = 'arn:aws:kms:us-east-1:111122223333:key/mrk-1234abcd12ab34cd56ef1234567890ab'
final String region = 'us-east-1'
      
final AWSKMS kms = AWSKMSClientBuilder.standard().withRegion(region).build();
final DirectKmsMaterialProvider cmp = new DirectKmsMaterialProvider(kms, usEastKey);
```

```
// Decrypt in us-west-2

// Replace the example key ARN and Region with valid values for your application
final String usWestKey = 'arn:aws:kms:us-west-2:111122223333:key/mrk-1234abcd12ab34cd56ef1234567890ab'
final String region = 'us-west-2'
      
final AWSKMS kms = AWSKMSClientBuilder.standard().withRegion(region).build();
final DirectKmsMaterialProvider cmp = new DirectKmsMaterialProvider(kms, usWestKey);
```

------
#### [ Python ]

在此示例中，DynamoDB 加密客户端在密钥 ARN 中获取了从该区域进行 AWS KMS 呼叫的区域。

```
# Encrypt in us-east-1

# Replace the example key ID with a valid value
us_east_key = 'arn:aws:kms:us-east-1:111122223333:key/mrk-1234abcd12ab34cd56ef1234567890ab'
kms_cmp = AwsKmsCryptographicMaterialsProvider(key_id=us_east_key)
```

```
# Decrypt in us-west-2

# Replace the example key ID with a valid value
us_west_key = 'arn:aws:kms:us-west-2:111122223333:key/mrk-1234abcd12ab34cd56ef1234567890ab'
kms_cmp = AwsKmsCryptographicMaterialsProvider(key_id=us_west_key)
```

------

## 工作原理
<a name="provider-kms-how-it-works"></a>

Direct KMS 提供程序返回受您指定的 AWS KMS key 保护的加密密钥和签名密钥，如下图所示。

![\[DynamoDB 加密客户端中 Direct KMS 提供程序的输入、处理和输出\]](http://docs.aws.amazon.com/zh_cn/database-encryption-sdk/latest/devguide/images/directKMS.png)

+ 要生成加密材料，Direct KMS 提供程序会要求 AWS KMS 使用您指定的为每个项目[生成一个 AWS KMS key 唯一的数据密钥](https://docs.aws.amazon.com/kms/latest/APIReference/API_GenerateDataKey.html)。它从[数据密钥](https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#data-keys)的明文副本中派生项目的加密密钥和签名密钥，然后返回加密密钥和签名密钥以及加密的数据密钥，后者存储在项目的[材料说明属性](DDBEC-legacy-concepts.md#legacy-material-description)中。

  项目加密程序使用加密密钥和签名密钥并尽快将它们从内存中删除。仅其派生自的数据密钥的加密副本保存在加密项目中。
+ 要生成解密材料，Direct KMS 提供商会要求 AWS KMS 解密加密的数据密钥。然后，它从明文数据密钥派生验证密钥和签名密钥，然后将这些密钥返回至项目加密程序。

  项目加密程序会验证项目，而且如果验证成功，会解密加密的值。然后，它会尽快从内存中删除这些密钥。

### 获取加密材料
<a name="direct-kms-get-encryption-materials"></a>

本部分详细介绍了 Direct KMS 提供程序收到来自[项目加密程序](DDBEC-legacy-concepts.md#item-encryptor)的加密材料请求时的输入、输出和处理。

**输入**（来自应用程序）
+ 的密钥 ID AWS KMS key。

**输入**（来自项目加密程序）
+ [DynamoDB 加密上下文](concepts.md#encryption-context)

**输出**（至项目加密程序）
+ 加密密钥（明文）
+ 签名密钥
+ 在[实际材料描述](DDBEC-legacy-concepts.md#legacy-material-description)中：这些值保存在客户端将添加到项目的材料描述属性中。
  + amzn-ddb-env-key: Base64 编码的数据密钥由加密 AWS KMS key
  + amzn-ddb-env-alg: 加密算法，默认为 [AES/256](https://csrc.nist.gov/projects/cryptographic-standards-and-guidelines/archived-crypto-projects/aes-development)
  + amzn-ddb-sig-alg: 签名算法，默认情况下，[Hmac /256 SHA256](https://en.wikipedia.org/wiki/HMAC)
  + amzn-ddb-wrap-alg: kms

**Processing**

1. Direct KMS 提供者发送 AWS KMS 请求，要求使用指定的 AWS KMS key 为该项目[生成唯一的数据密钥](https://docs.aws.amazon.com/kms/latest/APIReference/API_GenerateDataKey.html)。该操作会返回明文密钥以及由 AWS KMS key加密的副本。这称为*初始密钥材料*。

   请求包括 [AWS KMS 加密上下文](https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#encrypt_context)中的以下明文值。这些非密钥值以加密方式绑定到加密对象，因此，解密时需要相同的加密上下文。您可以使用这些值 AWS KMS 在[AWS CloudTrail 日志](https://docs.aws.amazon.com/kms/latest/developerguide/monitoring-overview.html)中标识对的调用。
   + amzn-ddb-env-alg — 加密算法，默认为 AES/256
   + amzn-ddb-sig-alg — 签名算法，默认为 Hmac /256 SHA256
   + （可选） aws-kms-table— *table name*
   + （可选）*partition key name*—*partition key value*（二进制值采用 Base64 编码）
   + （可选）*sort key name*—*sort key value*（二进制值采用 Base64 编码）

   直接 KMS 提供程序从该项目的 [DynamoDB AWS KMS 加密上下文中获取加密](concepts.md#encryption-context)上下文的值。如果 DynamoDB 加密上下文不包含值（例如表名），则加密上下文中将省略该名称/值对。 AWS KMS 

1. Direct KMS 提供程序从数据密钥派生对称加密密钥和签名密钥。默认情况下，它使用[安全哈希算法 (SHA) 256](https://en.wikipedia.org/wiki/SHA-2) 和[RFC5869 基于 HMAC 的密钥派生函数来派](https://tools.ietf.org/html/rfc5869)生 256 位 AES 对称加密密钥和 256 位 HMAC-SHA-256 签名密钥。

1. Direct KMS 提供程序将输出返回到项目加密程序。

1. 项目加密程序通过使用在实际材料说明中指定的算法，使用加密密钥加密指定的属性并使用签名密钥签署它们。它会尽快从内存中删除明文密钥。

### 获取解密材料
<a name="direct-kms-get-decryption-materials"></a>

本部分详细介绍了 Direct KMS 提供程序在从[项目加密程序](DDBEC-legacy-concepts.md#item-encryptor)收到解密材料的请求时的输入、输出和处理。

**输入**（来自应用程序）
+ 的密钥 ID AWS KMS key。

  密钥 ID 的值可以是 AWS KMS key的密钥 ID、密钥 ARN、别名名称或别名 ARN。未包含在密钥 ID 中的任何值，如区域，必须在 [AWS 命名配置文件](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-files.html#cli-configure-files-using-profiles)中可用。密钥 ARN 提供了 AWS KMS 需要的所有值。

**输入**（来自项目加密程序）
+ 包含材料描述属性内容的 [DynamoDB 加密上下文](concepts.md#encryption-context)的副本。

**输出**（至项目加密程序）
+ 加密密钥（明文）
+ 签名密钥

**Processing**

1. Direct KMS 提供程序从加密项目中的材料描述属性获取加密数据密钥。

1. 它要求 AWS KMS 使用指定的 AWS KMS key 来[解密加密的数据密](https://docs.aws.amazon.com/kms/latest/APIReference/API_GenerateDataKey.html)钥。此操作会返回明文密钥。

   此请求必须使用用于生成和加密数据密钥的相同的 [AWS KMS 加密上下文](https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#encrypt_context)。
   + aws-kms-table – *table name*
   + *partition key name*—*partition key value*（二进制值采用 Base64 编码）
   + （可选）*sort key name*—*sort key value*（二进制值采用 Base64 编码）
   + amzn-ddb-env-alg — 加密算法，默认为 AES/256
   + amzn-ddb-sig-alg — 签名算法，默认为 Hmac /256 SHA256

1. Direct KMS 提供商使用[安全哈希算法 (SHA) 256](https://en.wikipedia.org/wiki/SHA-2) 和[RFC5869 基于 HMAC 的密钥派生函数](https://tools.ietf.org/html/rfc5869)从数据密钥中派生 256 位 AES 对称加密密钥和 256 位 HMAC-SHA-256 签名密钥。

1. Direct KMS 提供程序将输出返回到项目加密程序。

1. 项目加密程序将使用此签名密钥验证项目。如果它成功，则会使用对称加密密钥来解决加密的属性值。这些操作使用在实际材料说明中指定的加密和签名算法。项目加密程序它会尽快从内存中删除明文密钥。

# 已包装的材料提供程序
<a name="wrapped-provider"></a>

**注意**  
我们的客户端加密库已[重命名为 AWS 数据库加密 SDK](DDBEC-rename.md)。以下主题提供有关适用于 Java 的 DynamoDB 加密客户端版本 1.*x*—2.*x* 以及适用于 Python 的 DynamoDB 加密客户端版本 1.*x*—3.*x* 的信息。有关更多信息，请参阅[适用于 DynamoDB 的AWS 数据库加密 SDK 版本支持](legacy-dynamodb-encryption-client.md#legacy-support)。

利用*已包装的材料提供程序*（已包装的 CMP），您可以通过 DynamoDB 加密客户端的任何源使用包装密钥和签名密钥。Wrapped CMP 不依赖于任何 AWS 服务。但是，必须在客户端之外生成和管理包装密钥与签名密钥，包括提供正确的密钥来验证和解密项目。

已包装的 CMP 将为每个项目生成一个唯一项目加密密钥。它使用提供的包装密钥包装项目加密密钥并将已包装的项目加密密钥保存在项目的[材料描述属性](DDBEC-legacy-concepts.md#legacy-material-description)中。由于包装密钥和签名密钥是您提供的，因此由您确定包装密钥和签名密钥的生成方式以及这些密钥对每个项目是否唯一或是否会重复使用。

已包装的 CMP 是安全实现，并且是可管理加密材料的应用程序的不二选择。

Wrapped CMP 是 DynamoDB [加密客户端支持的几个加密材料提供程序](DDBEC-legacy-concepts.md#concept-material-provider) (CMPs) 之一。有关另一个的信息 CMPs，请参阅[加密材料提供程序](crypto-materials-providers.md)。

**有关示例代码，请参阅：**
+ Java：[AsymmetricEncryptedItem](https://github.com/aws/aws-dynamodb-encryption-java/blob/master/examples/src/main/java/com/amazonaws/examples/AsymmetricEncryptedItem.java)
+ Python: [wrapped-rsa-encrypted-table](https://github.com/aws/aws-dynamodb-encryption-python/blob/master/examples/src/dynamodb_encryption_sdk_examples/wrapped_rsa_encrypted_table.py)，[wrapped-symmetric-encrypted-table](https://github.com/aws/aws-dynamodb-encryption-python/blob/master/examples/src/dynamodb_encryption_sdk_examples/wrapped_symmetric_encrypted_table.py)

**Topics**
+ [使用方法](#wrapped-cmp-how-to-use)
+ [工作原理](#wrapped-cmp-how-it-works)

## 使用方法
<a name="wrapped-cmp-how-to-use"></a>

要创建已包装的 CMP，请指定包装密钥（加密时需要）、解开包装密钥（解密时需要）以及签名密钥。加密和解密项目时，必须提供密钥。

包装密钥、解开包装密钥和签名密钥可以是对称密钥或非对称密钥对。

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

```
// This example uses asymmetric wrapping and signing key pairs
final KeyPair wrappingKeys = ...
final KeyPair signingKeys = ...

final WrappedMaterialsProvider cmp = 
    new WrappedMaterialsProvider(wrappingKeys.getPublic(),
                                 wrappingKeys.getPrivate(),
                                 signingKeys);
```

------
#### [ Python ]

```
# This example uses symmetric wrapping and signing keys
wrapping_key = ...
signing_key  = ...

wrapped_cmp = WrappedCryptographicMaterialsProvider(
    wrapping_key=wrapping_key,
    unwrapping_key=wrapping_key,
    signing_key=signing_key
)
```

------

## 工作原理
<a name="wrapped-cmp-how-it-works"></a>

已包装的 CMP 将为每个项目生成一个新的项目加密密钥。它将使用提供的包装密钥、解开包装密钥和签名密钥，如下图中所示。

![\[DynamoDB 加密客户端中已包装材料提供程序的输入、处理和输出\]](http://docs.aws.amazon.com/zh_cn/database-encryption-sdk/latest/devguide/images/wrappedCMP.png)


### 获取加密材料
<a name="wrapped-cmp-get-encryption-materials"></a>

本部分详述了已包装的材料提供程序（已包装的 CMP）在收到加密材料请求时的输入、输出和处理。

**输入**（来自应用程序）
+ 包装密钥：[高级加密标准](https://en.wikipedia.org/wiki/Advanced_Encryption_Standard) (AES) 对称密钥或 [RSA](https://en.wikipedia.org/wiki/RSA_(cryptosystem)) 公钥。在加密任何属性值时都需要。否则，它为可选项，将忽略。
+ 解开包装密钥：可选，将忽略。
+ 签名密钥

**输入**（来自项目加密程序）
+ [DynamoDB 加密上下文](concepts.md#encryption-context)

**输出**（至项目加密程序）：
+ 明文项目加密密钥
+ 签名密钥（保持不变）
+ [实际材料描述](DDBEC-legacy-concepts.md#legacy-material-description)：这些值保存在客户端添加到项目的[材料描述属性](DDBEC-legacy-concepts.md#legacy-material-description)中。
  + `amzn-ddb-env-key`：Base64 编码的已包装项目加密密钥
  + `amzn-ddb-env-alg`：用于加密项目的加密算法。默认值为 AES-256-CBC。
  + `amzn-ddb-wrap-alg`：已包装的 CMP 用于包装项目加密密钥的包装算法。如果包装密钥为 AES 密钥，则将使用未填充的 `AES-Keywrap` 包装此密钥，如 [RFC 3394](https://tools.ietf.org/html/rfc3394.html) 中所定义。如果包装密钥是 RSA 密钥，则使用带填充的 RSA OAEP 对密钥进行加密。 MGF1 

**Processing**

加密项目时，将传入包装密钥和签名密钥。解开包装密钥为可选项，将忽略。

1. 已包装的 CMP 将为每个表项目生成一个唯一对称项目加密密钥。

1. 它使用指定的包装密钥包装项目加密密钥。之后，它将尽快从内存中删除此密钥。

1. 它将返回明文项目加密密钥、提供的签名密钥、包含已包装项目加密密钥的[实际材料描述](DDBEC-legacy-concepts.md#legacy-material-description)以及加密算法和包装算法。

1. 项目加密程序将使用此明文加密密钥加密项目。它使用提供的签名密钥为项目签名。之后，它将尽快从内存中删除明文密钥。它将实际材料描述中的字段（包括已包装的加密密钥 (`amzn-ddb-env-key`)）复制到项目的材料描述属性中。

### 获取解密材料
<a name="wrapped-cmp-get-decryption-materials"></a>

本部分详述了已包装的材料提供程序（已包装的 CMP）在收到解密材料请求时的输入、输出和处理。

**输入**（来自应用程序）
+ 包装密钥：可选，将忽略。
+ 解开包装密钥：同一[高级加密标准](https://en.wikipedia.org/wiki/Advanced_Encryption_Standard) (AES) 对称密钥或对应加密所用 RSA 公有密钥的 [RSA](https://en.wikipedia.org/wiki/RSA_(cryptosystem)) 私有密钥。在加密任何属性值时都需要。否则，它为可选项，将忽略。
+ 签名密钥

**输入**（来自项目加密程序）
+ 包含材料描述属性内容的 [DynamoDB 加密上下文](concepts.md#encryption-context)的副本。

**输出**（至项目加密程序）
+ 明文项目加密密钥
+ 签名密钥（保持不变）

**Processing**

解密项目时，将传入解开包装密钥和签名密钥。包装密钥为可选项，将忽略。

1. 已包装的 CMP 将从项目的材料描述属性中获取已包装的项目加密密钥。

1. 它使用解开包装密钥和算法解开包装项目加密密钥。

1. 它将明文项目加密密钥、签名密钥以及加密和签名算法返回项目加密程序。

1. 项目加密程序将使用此签名密钥验证项目。如果验证成功，则项目加密程序将使用项目加密密钥解密项目。之后，它将尽快从内存中删除明文密钥。

# 最新提供程序
<a name="most-recent-provider"></a>

**注意**  
我们的客户端加密库已[重命名为 AWS 数据库加密 SDK](DDBEC-rename.md)。以下主题提供有关适用于 Java 的 DynamoDB 加密客户端版本 1.*x*—2.*x* 以及适用于 Python 的 DynamoDB 加密客户端版本 1.*x*—3.*x* 的信息。有关更多信息，请参阅[适用于 DynamoDB 的AWS 数据库加密 SDK 版本支持](legacy-dynamodb-encryption-client.md#legacy-support)。

*最新提供程序*是一个[加密材料提供程序](DDBEC-legacy-concepts.md#concept-material-provider)（CMP），旨在处理[提供程序存储](DDBEC-legacy-concepts.md#provider-store)。它 CMPs 从提供商商店获取，并从中获取返回的加密材料。 CMPs它通常使用每个 CMP 来满足针对加密材料的多个请求。但您可以使用其提供程序存储的功能来控制材料被重复使用的程度，确定其 CMP 被轮换的频率甚至是更改它使用的 CMP 的类型而不更改最新提供程序。

**注意**  
与“最新提供程序”的 `MostRecentProvider` 符号关联的代码可能会在进程的生命周期内将加密材料存储在内存中。它可能会使调用方使用他们不再有权使用的密钥。  
`MostRecentProvider` 符号在受支持的较早版本的 DynamoDB 加密客户端中已被弃用，并已从 2.0.0 版本中移除。它被 `CachingMostRecentProvider` 符号所取代。有关更多信息，请参阅 [最新提供程序的更新](#mrp-versions)。

对于需要最大程度地减少对提供程序存储及其加密源的调用的应用程序，以及能够在不违反应用程序的安全性要求的情况下重复使用某些加密材料的应用程序，最新提供程序是一个很好的选择。例如，它允许您在 in [AWS Key Management Service](https://docs.aws.amazon.com/kms/latest/developerguide/)(AWS KMS) 下保护您的加密材料，而无需[AWS KMS key](https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#master_keys)在 AWS KMS 每次加密或解密项目时都调用。

您选择的提供商存储决定了最新提供程序使用的类型以及它获得新 CMP 的频率。 CMPs 您可以将任何兼容的提供程序存储与最新提供程序结合使用，包括您设计的自定义提供程序存储。

DynamoDB 加密客户端包括*MetaStore*一个用于创建和[返回包装材料提供者（已包装](wrapped-provider.md)）的。 CMPs将其生成的 Wrap CMPs ped 的多个版本 MetaStore 保存在内部 DynamoDB 表中，并通过 DynamoDB 加密客户端的内部实例使用客户端加密对其进行保护。

您可以将配置 MetaStore 为使用任何类型的内部 CMP 来保护表中的材料，包括生成受您保护的加密材料的 Di [rect KMS 提供程序](direct-kms-provider.md) AWS KMS key、使用您提供的封装和签名密钥的 Wrapped CMP，或者您设计的兼容自定义 CMP。

**有关示例代码，请参阅：**
+ Java：[MostRecentEncryptedItem](https://github.com/aws/aws-dynamodb-encryption-java/blob/master/examples/src/main/java/com/amazonaws/examples/MostRecentEncryptedItem.java)
+ Python：[most\$1recent\$1provider\$1encrypted\$1table](https://github.com/aws/aws-dynamodb-encryption-python/blob/master/examples/src/dynamodb_encryption_sdk_examples/most_recent_provider_encrypted_table.py)

**Topics**
+ [使用方法](#mrp-how-to-use-it)
+ [工作原理](#mrp-how-it-works)
+ [最新提供程序的更新](#mrp-versions)

## 使用方法
<a name="mrp-how-to-use-it"></a>

要创建最新提供程序，您需要创建和配置一个提供程序存储，然后创建使用该提供程序存储的最新提供程序。

[以下示例说明如何创建使用的最新提供程序， MetaStore 并使用直接 KMS 提供程序提供的加密材料保护其内部 DynamoDB 表中的版本。](direct-kms-provider.md)这些示例使用 [`CachingMostRecentProvider`](#mrp-versions) 符号。

每个最新提供程序都有一个用于在 MetaStore 表 CMPs 中标识其名称的名称、一个 [time-to-live](#most-recent-provider-ttl)(TTL) 设置和一个决定缓存可以容纳多少条目的缓存大小设置。这些示例将缓存大小设置为 1000 个条目，并将 TTL 设置为 60 秒。

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

```
// Set the name for MetaStore's internal table
final String keyTableName = 'metaStoreTable'

// Set the Region and AWS KMS key
final String region = 'us-west-2'
final String keyArn = 'arn:aws:kms:us-west-2:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab'

// Set the TTL and cache size
final long ttlInMillis = 60000;
final long cacheSize = 1000;

// Name that identifies the MetaStore's CMPs in the provider store
final String materialName = 'testMRP'

// Create an internal DynamoDB client for the MetaStore
final AmazonDynamoDB ddb = AmazonDynamoDBClientBuilder.standard().withRegion(region).build();

// Create an internal Direct KMS Provider for the MetaStore
final AWSKMS kms = AWSKMSClientBuilder.standard().withRegion(region).build();
final DirectKmsMaterialProvider kmsProv = new DirectKmsMaterialProvider(kms, keyArn);

// Create an item encryptor for the MetaStore,
// including the Direct KMS Provider
final DynamoDBEncryptor keyEncryptor = DynamoDBEncryptor.getInstance(kmsProv);

// Create the MetaStore
final MetaStore metaStore = new MetaStore(ddb, keyTableName, keyEncryptor);

//Create the Most Recent Provider
final CachingMostRecentProvider cmp = new CachingMostRecentProvider(metaStore, materialName, ttlInMillis, cacheSize);
```

------
#### [ Python ]

```
# Designate an AWS KMS key
kms_key_id = 'arn:aws:kms:us-west-2:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab'

# Set the name for MetaStore's internal table
meta_table_name = 'metaStoreTable'

# Name that identifies the MetaStore's CMPs in the provider store
material_name = 'testMRP'

# Create an internal DynamoDB table resource for the MetaStore
meta_table = boto3.resource('dynamodb').Table(meta_table_name)

# Create an internal Direct KMS Provider for the MetaStore
kms_cmp = AwsKmsCryptographicMaterialsProvider(key_id=kms_key_id)
    
# Create the MetaStore with the Direct KMS Provider
meta_store = MetaStore(
    table=meta_table,
    materials_provider=kms_cmp
)

# Create a Most Recent Provider using the MetaStore
#    Sets the TTL (in seconds) and cache size (# entries)
most_recent_cmp = MostRecentProvider(
    provider_store=meta_store,
    material_name=material_name,
    version_ttl=60.0,
    cache_size=1000
)
```

------

## 工作原理
<a name="mrp-how-it-works"></a>

最新提供商 CMPs 来自提供商商店。然后，它使用 CMP 生成由它返回到项目加密程序的加密材料。

### 关于最新提供程序
<a name="about-mrp"></a>

最新提供程序从[提供程序存储](DDBEC-legacy-concepts.md#provider-store)中获得[加密材料提供程序](DDBEC-legacy-concepts.md#concept-material-provider)（CMP）。然后，它使用 CMP 生成由它返回的加密材料。每个最新提供商都与一个提供商商店相关联，但一个提供商商店可以 CMPs 向多个主机上的多个提供商提供服务。

最新提供程序可与来自任何提供程序存储的任何兼容的 CMP 一起使用。它从 CMP 请求加密或解密材料，并将输出返回给项目加密程序。而不执行任何加密操作。

为了从其提供程序存储请求 CMP，最新提供程序将提供其材料名称以及要使用的现有 CMP 的版本。对于加密材料，最新提供程序始终请求最高（“最新”）版本。对于解密材料，它请求用于创建加密材料的 CMP 的版本，如下图所示。

![\[最新提供程序\]](http://docs.aws.amazon.com/zh_cn/database-encryption-sdk/latest/devguide/images/most-recent-provider-1.png)


最新提供程序将提供程序存储返回的 CMPs 版本保存在内存中的本地 “最近最少使用” (LRU) 缓存中。缓存使最新提供商能够获取所需的内容 CMPs ，而无需为每件商品调用提供商商店。您可以按需清除该缓存。

最新提供程序使用可配置的[time-to-live值](#most-recent-provider-ttl)，您可以根据应用程序的特性进行调整。

### 关于 MetaStore
<a name="about-metastore"></a>

您可以将最新提供程序与任何提供程序存储结合使用，包括兼容的自定义提供程序存储。DynamoDB 加密客户端包括 MetaStore一个安全实现，您可以对其进行配置和自定义。

A *MetaStore*是一个[提供商存储](DDBEC-legacy-concepts.md#provider-store)，用于创建并返回使用 Wr [ap CMPs](wrapped-provider.md) ped CMPs 所需的包装密钥、解包密钥和签名密钥配置的 Wrapped。对于最新提供商来说，A MetaStore 是一个安全的选项，因为 Wrapped CMPs 总是为每个项目生成唯一的项目加密密钥。只有保护项目加密密钥和签名密钥的包装密钥才会被重用。

下图显示了的组件 MetaStore 及其与最新提供程序的交互方式。

![\[A MetaStore\]](http://docs.aws.amazon.com/zh_cn/database-encryption-sdk/latest/devguide/images/most-recent-provider-2.png)


 MetaStore 生成 Wrapped CMPs，然后将它们（以加密形式）存储在内部 DynamoDB 表中。分区键是最新提供程序材料的名称；排序键则是其版本号。该表中的材料由内部 DynamoDB 加密客户端保护，包括一个项目加密程序和内部[加密材料提供程序](DDBEC-legacy-concepts.md#concept-material-provider)（CMP）。

您可以在中使用任何类型的内部 CMP MetaStore，包括[直接 KMS 提供程序](wrapped-provider.md)、包含您提供的加密材料的 Wrapped CMP 或兼容的自定义 CMP。如果您的内部 CMP MetaStore 是直接 KMS 提供商，则您的可重复使用的封装和签名密钥将受到 [AWS KMS key](https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#master_keys)in [AWS Key Management Service](https://docs.aws.amazon.com/kms/latest/developerguide/)(AWS KMS) 的保护。 AWS KMS 每次向其内部表添加新的 CMP 版本或从其内部表中获取 CMP 版本时，都会 MetaStore 调用。

### 设置一个 time-to-live值
<a name="most-recent-provider-ttl"></a>

您可以为创建的每个最新提供程序设置一个 time-to-live (TTL) 值。通常情况下，请在您的应用程序中使用实用的最低 TTL 值。

最新提供程序的 `CachingMostRecentProvider` 符号中的 TTL 值的使用已更改。

**注意**  
最新提供程序的 `MostRecentProvider` 符号在受支持的较早版本的 DynamoDB 加密客户端中已被弃用，并已从 2.0.0 版本中移除。它被 `CachingMostRecentProvider` 符号所取代。建议您尽快更新代码。有关更多信息，请参阅 [最新提供程序的更新](#mrp-versions)。

**`CachingMostRecentProvider`**  
`CachingMostRecentProvider` 以两种不同的方式使用 TTL 值。  
+ TTL 决定了最新提供程序在提供程序存储中检查新版本的 CMP 的频率。如果有新版本可用，最新提供程序将会替换其 CMP 并刷新其加密材料。否则，它将继续使用它的当前 CMP 和加密材料。
+ TTL 决定了可以在缓存 CMPs 中使用多长时间。在使用缓存的 CMP 进行加密之前，最新提供程序会评估其在缓存中存在的时间。如果 CMP 缓存时间超过 TTL，则 CMP 将从缓存中被驱逐，最新提供程序将从其提供程序存储中获取最新版本的新 CMP。

**`MostRecentProvider`**  
在 `MostRecentProvider` 中，TTL 决定了最新提供程序在提供程序存储中检查新版本的 CMP 的频率。如果有新版本可用，最新提供程序将会替换其 CMP 并刷新其加密材料。否则，它将继续使用它的当前 CMP 和加密材料。

TTL 并不能确定新的 CMP 版本的创建频率。您可以通过[轮换加密材料](#most-recent-provider-rotate)来创建新的 CMP 版本。

理想的 TTL 值将因应用程序及其延迟和可用性目标而异。低 TTL 可缩短加密材料在内存中的存储时间，从而改善安全状况。而且，TTL 低时，会更频繁地刷新关键信息。例如，如果您的内部 CMP 是 [Direct KMS 提供程序](direct-kms-provider.md)，它会更频繁地验证调用方是否仍有权使用 AWS KMS key。

但是，如果 TTL 过短，频繁调用提供程序存储可能会增加您的成本，并导致您的提供程序存储限制来自您的应用程序和共享您的服务账户的其他应用程序的请求。通过将 TTL 与轮换加密材料的速度进行协调，可能也会让您受益。

测试期间，在不同工作负载下更改 TTL 和缓存大小，直到找到适合您的应用程序以及您的安全和性能标准的配置。

### 轮换加密材料
<a name="most-recent-provider-rotate"></a>

当最新提供程序需要加密材料时，它始终使用其所知道的最新版本的 CMP。它检查新版本的频率由您在配置最新提供程序时设置的 [time-to-live](#most-recent-provider-ttl)(TTL) 值决定。

当 TTL 到期时，最新提供程序会在提供程序存储中检查新版本的 CMP。如果有可用版本，则最新提供程序会获取它并替换其缓存中的 CMP。它将使用此 CMP 及其加密材料，直到发现提供程序存储有更新的版本。

要让提供程序存储为最新提供程序创建新版本的 CMP，请使用最新提供程序的材料名称调用提供程序存储的“创建新提供程序”操作。提供程序存储将创建一个新 CMP 并在其内部存储中以更高的版本号保存加密复本。（它还将返回 CMP，但您可以丢弃它。） 因此，下次最新提供程序向提供程序商店查询其最大版本号时 CMPs，它会获得新的更大版本号，并在随后向存储请求时使用该版本号来查看是否创建了新版本的 CMP。

您可以基于时间、已处理的项目或属性数或者对您的应用程序有意义的其他指标计划您的“创建新提供程序”调用。

### 获取加密材料
<a name="most-recent-provider-encrypt"></a>

最新提供程序使用以下过程（如图所示）来获取它返回到项目加密程序的加密材料。输出取决于提供程序存储返回的 CMP 的类型。最新提供程序可以使用任何兼容的提供程序存储，包括 DynamoDB 加密客户端中包含的。 MetaStore 

![\[DynamoDB 加密客户端中最新提供程序的输入、处理和输出\]](http://docs.aws.amazon.com/zh_cn/database-encryption-sdk/latest/devguide/images/most-recent-provider-provider-store.png)


使用[`CachingMostRecentProvider`符号](#mrp-versions)创建最新提供程序时，需要指定提供程序存储区、最新提供程序的名称和 [time-to-live](#most-recent-provider-ttl)(TTL) 值。您也可以选择指定缓存大小，该大小决定缓存中可以存在的最大加密材料数量。

当项目加密程序向最新提供程序请求加密材料时，最新提供程序首先会在其缓存中搜索其 CMP 的最新版本。
+ 如果它在缓存中找到了最新版本的 CMP 且 CMP 没有超出 TTL 值，则最新提供程序将使用 CMP 来生成加密材料。然后，它将加密材料返回到项目加密程序。此操作不需要调用提供程序存储。
+ 如果最新版本的 CMP 不在其缓存中，或者如果它在缓存中但已超出其 TTL 值，则最新提供程序将从其提供程序存储请求 CMP。该请求包含最新提供程序材料名称以及它知道的最高版本号。

  1. 提供程序存储从其持久性存储返回 CMP。如果提供程序存储是 MetaStore，则使用最新提供程序材料名称作为分区键，使用版本号作为排序键，从其内部 DynamoDB 表中获取加密的 Wrapped CMP。 MetaStore 使用其内部项目加密器和内部 CMP 来解密 Wrapped CMP。然后，它将明文 CMP 返回到最新提供程序。如果内部 CMP 是 [Direct KMS 提供程序](direct-kms-provider.md)，此步骤将包含对 [AWS Key Management Service](https://docs.aws.amazon.com/kms/latest/developerguide/) (AWS KMS) 的调用。

  1. CMP 将 `amzn-ddb-meta-id` 域添加到[实际材料描述](DDBEC-legacy-concepts.md#legacy-material-description)。该域的值是 CMP 在其内部表中的材料名称和版本。提供程序存储将 CMP 返回到最新提供程序。

  1. 最新提供程序在内存中缓存 CMP。

  1. 最新提供程序使用 CMP 生成加密材料。然后，它将加密材料返回到项目加密程序。

### 获取解密材料
<a name="most-recent-provider-decrypt"></a>

当项目加密程序向最新提供程序请求解密材料时，最新提供程序将使用以下过程来获取并返回这些材料。

1. 最新提供程序向提供程序存储询问用于加密项目的加密材料的版本号。提供程序存储传入来自项目的[材料描述属性](DDBEC-legacy-concepts.md#legacy-material-description)的实际材料描述。

1. 提供程序存储从实际材料描述中的 `amzn-ddb-meta-id` 域获取加密 CMP 版本号并将其返回到最新提供程序。

1. 最新提供程序在缓存中搜索用于加密和签署项目的 CMP 版本。
+ 如果发现缓存中存在匹配版本的 CMP，并且 CMP 未超过 [time-to-live (TTL) 值](#most-recent-provider-ttl)，则最新提供程序会使用 CMP 生成解密材料。然后，它将解密材料返回到项目加密程序。此操作不需要调用提供程序存储或任何其他 CMP。
+ 如果匹配版本的 CMP 不在其缓存中，或者如果缓存的 AWS KMS key 已超出其 TTL 值，则最新提供程序将从其提供程序存储请求 CMP。它将在请求中发送其材料名称和加密 CMP 版本号。

  1. 提供程序存储将最新提供程序名称用作分区键并将版本号用作排序键，以便在其持久性存储中搜索 CMP。
     + 如果名称和版本号不在其持久性存储中，提供程序存储将引发异常。如果提供程序存储用于生成 CMP，那么 CMP 应该存储在其持久性存储中，除非它被意外删除。
     + 如果具有匹配的名称和版本号的 CMP 位于提供程序存储的持久性存储中，提供程序存储会将指定 CMP 返回到最新提供程序。

       如果提供商存储是 MetaStore，则它会从其 DynamoDB 表中获取加密的 CMP。然后，它从其内部 CMP 获取加密材料以解密已加密的 CMP，再将 CMP 返回到最新提供程序。如果内部 CMP 是 [Direct KMS 提供程序](direct-kms-provider.md)，此步骤将包含对 [AWS Key Management Service](https://docs.aws.amazon.com/kms/latest/developerguide/) (AWS KMS) 的调用。

  1. 最新提供程序在内存中缓存 CMP。

  1. 最新提供程序使用 CMP 生成解密材料。然后，它将解密材料返回到项目加密程序。

## 最新提供程序的更新
<a name="mrp-versions"></a>

最新提供程序的符号已从 `MostRecentProvider` 更改为 `CachingMostRecentProvider`。

**注意**  
`MostRecentProvider` 符号代表最新提供程序，在适用于 Java 的 DynamoDB 加密客户端 1.15 版本和适用于 Python 的 DynamoDB 加密客户端 1.3 版本中已被弃用，并已从两种语言实现的 DynamoDB 加密客户端 2.0.0 版本中移除。可改用 `CachingMostRecentProvider`。

`CachingMostRecentProvider` 实现了以下更改：
+ 当加密材料在内存中的时间超过配置的 [time-to-live (TTL)](#most-recent-provider-ttl) 值时，会`CachingMostRecentProvider`定期将其从内存中删除。

  `MostRecentProvider` 可能会在进程的整个生命周期内将加密材料存储在内存中。因此，最新提供程序可能不知道授权更改。它可能会在调用方使用加密密钥的权限被撤消后使用它们。

  如果您无法更新到此新版本，则可以通过定期在缓存上调用 `clear()` 方法来获得类似的效果。此方法将手动刷新缓存内容，并要求最新提供程序请求新的 CMP 和新的加密材料。
+ `CachingMostRecentProvider` 还包括缓存大小设置，该设置可让您更好地控制缓存。

要更新到 `CachingMostRecentProvider`，您必须更改代码中的符号名称。在所有其他方面，`CachingMostRecentProvider` 完全向后兼容 `MostRecentProvider`。您无需重新加密任何表项目。

但是，`CachingMostRecentProvider` 会生成更多对底层密钥基础设施的调用。它在每个 time-to-live (TTL) 间隔中至少调用一次提供商存储区。具有大量活动状态 CMPs （由于频繁轮换）的应用程序或具有大型队列的应用程序最有可能对这种变化很敏感。

在发布更新后的代码之前，请对其进行全面测试，确保更频繁的调用不会损害您的应用程序或导致提供商所依赖的服务（例如 AWS Key Management Service (AWS KMS) 或 Amazon DynamoDB）的限制。要缓解任何性能问题，请`CachingMostRecentProvider`根据您观察到 time-to-live的性能特征调整缓存大小和缓存的大小。有关指南，请参阅[设置一个 time-to-live值](#most-recent-provider-ttl)。

# 静态材料提供程序
<a name="static-provider"></a>

**注意**  
我们的客户端加密库已[重命名为 AWS 数据库加密 SDK](DDBEC-rename.md)。以下主题提供有关适用于 Java 的 DynamoDB 加密客户端版本 1.*x*—2.*x* 以及适用于 Python 的 DynamoDB 加密客户端版本 1.*x*—3.*x* 的信息。有关更多信息，请参阅[适用于 DynamoDB 的AWS 数据库加密 SDK 版本支持](legacy-dynamodb-encryption-client.md#legacy-support)。

*静态材料提供商*（Static CMP）是一个非常简单的[加密材料提供商](DDBEC-legacy-concepts.md#concept-material-provider)（CMP），用于测试、 proof-of-concept演示和传统兼容性。

要使用静态 CMP 加密表项目，请提供[高级加密标准](https://en.wikipedia.org/wiki/Advanced_Encryption_Standard) (AES) 对称加密和签名密钥或密钥对。必须提供相同的密钥才能解密加密的项目。静态 CMP 不会执行任何加密操作。相反，它会将提供的加密密钥原封不动地传递给项目加密程序。项目加密程序将直接使用此加密密钥加密项目。然后，它将直接使用签名密钥为项目签名。

由于静态 CMP 不会生成任何唯一加密材料，因此将使用同一加密密钥加密且通过同一签名密钥签名您处理的所有表项目。当使用同一密钥加密众多项目中的属性值或使用同一密钥或密钥对为所有项目签名时，将面临超出密钥加密限制的风险。

**注意**  
Java 库中的[非对称静态提供程序](https://aws.github.io/aws-dynamodb-encryption-java/com/amazonaws/services/dynamodbv2/datamodeling/encryption/providers/AsymmetricStaticProvider.html)不是一种静态提供程序。它仅提供[已包装的 CMP](wrapped-provider.md) 的替代构造函数。它对生产使用是安全的，但应尽可能直接使用已包装的 CMP。

静态 CMP 是 DynamoDB [加密客户端支持的几个加密材料提供程序](DDBEC-legacy-concepts.md#concept-material-provider) (CMPs) 之一。有关另一个的信息 CMPs，请参阅[加密材料提供程序](crypto-materials-providers.md)。

**有关示例代码，请参阅：**
+ Java：[SymmetricEncryptedItem](https://github.com/aws/aws-dynamodb-encryption-java/blob/master/examples/src/main/java/com/amazonaws/examples/SymmetricEncryptedItem.java)

**Topics**
+ [使用方法](#static-cmp-how-to-use)
+ [工作原理](#static-cmp-how-it-works)

## 使用方法
<a name="static-cmp-how-to-use"></a>

要创建静态提供程序，请提供加密密钥或密钥对和签名密钥或密钥对。需要提供密钥材料才能加密和解密表项目。

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

```
// To encrypt
SecretKey cek = ...;        // Encryption key
SecretKey macKey =  ...;    // Signing key
EncryptionMaterialsProvider provider = new SymmetricStaticProvider(cek, macKey);

// To decrypt
SecretKey cek = ...;        // Encryption key
SecretKey macKey =  ...;    // Verification key
EncryptionMaterialsProvider provider = new SymmetricStaticProvider(cek, macKey);
```

------
#### [ Python ]

```
# You can provide encryption materials, decryption materials, or both
encrypt_keys = EncryptionMaterials(
    encryption_key = ...,
    signing_key = ...
)

decrypt_keys = DecryptionMaterials(
    decryption_key = ...,
    verification_key = ...
)

static_cmp = StaticCryptographicMaterialsProvider(
    encryption_materials=encrypt_keys
    decryption_materials=decrypt_keys
)
```

------

## 工作原理
<a name="static-cmp-how-it-works"></a>

静态提供程序将提供的加密和签名密钥传递到项目加密程序，而后项目加密程序直接使用这些密钥为表项目加密和签名。除非为每个项目提供了不同的密钥，否则对所有项目使用相同的密钥。

![\[DynamoDB 加密客户端中静态材料提供程序的输入、处理和输出\]](http://docs.aws.amazon.com/zh_cn/database-encryption-sdk/latest/devguide/images/staticCMP.png)


### 获取加密材料
<a name="static-cmp-get-encryption-materials"></a>

本部分详述了静态材料提供程序（静态 CMP）在收到加密材料请求时的输入、输出和处理。

**输入**（来自应用程序）
+ 加密密钥 – 这必须是对称密钥（如[高级加密标准](https://tools.ietf.org/html/rfc3394.html)（AES）密钥）。
+ 签名密钥 – 这可以是对称密钥或非对称密钥对。

**输入**（来自项目加密程序）
+ [DynamoDB 加密上下文](concepts.md#encryption-context)

**输出**（至项目加密程序）
+ 作为输入传递的加密密钥。
+ 作为输入传递的签名密钥。
+ 实际材料描述：[请求的材料描述](DDBEC-legacy-concepts.md#legacy-material-description)（如有），不做更改。

### 获取解密材料
<a name="static-cmp-get-decryption-materials"></a>

本部分详述了静态材料提供程序（静态 CMP）在收到解密材料请求时的输入、输出和处理。

尽管它获取加密材料和获取解密材料的方法不同，但此行为是相同的。

**输入**（来自应用程序）
+ 加密密钥 – 这必须是对称密钥（如[高级加密标准](https://tools.ietf.org/html/rfc3394.html)（AES）密钥）。
+ 签名密钥 – 这可以是对称密钥或非对称密钥对。

**输入**（来自项目加密程序）
+ [DynamoDB 加密上下文](concepts.md#encryption-context)（未使用）

**输出**（至项目加密程序）
+ 作为输入传递的加密密钥。
+ 作为输入传递的签名密钥。

# Amazon DynamoDB Encryption Client 可用的编程语言
<a name="programming-languages"></a>

**注意**  
我们的客户端加密库已[重命名为 AWS 数据库加密 SDK](DDBEC-rename.md)。以下主题提供有关适用于 Java 的 DynamoDB 加密客户端版本 1.*x*—2.*x* 以及适用于 Python 的 DynamoDB 加密客户端版本 1.*x*—3.*x* 的信息。有关更多信息，请参阅[适用于 DynamoDB 的AWS 数据库加密 SDK 版本支持](legacy-dynamodb-encryption-client.md#legacy-support)。

Amazon DynamoDB Encryption Client 适用于以下编程语言。特定于语言的库各不相同，但生成的实现是可互操作的。例如，您可以使用 Java 客户端加密（和签署）项目，并使用 Python 客户端解密项目。

有关更多信息，请参阅相应主题。

**Topics**
+ [Java](java.md)
+ [Python](python.md)

# 适用于 Java 的 Amazon DynamoDB Encryption Client
<a name="java"></a>

**注意**  
我们的客户端加密库已[重命名为 AWS 数据库加密 SDK](DDBEC-rename.md)。以下主题提供有关适用于 Java 的 DynamoDB 加密客户端版本 1.*x*—2.*x* 以及适用于 Python 的 DynamoDB 加密客户端版本 1.*x*—3.*x* 的信息。有关更多信息，请参阅[适用于 DynamoDB 的AWS 数据库加密 SDK 版本支持](legacy-dynamodb-encryption-client.md#legacy-support)。

本主题介绍了如何安装和使用适用于 Java 的 Amazon DynamoDB Encryption Client。[https://github.com/aws/aws-dynamodb-encryption-java/tree/master/examples](https://github.com/aws/aws-dynamodb-encryption-java/tree/master/examples)

**注意**  
版本 1. *x*。 适用于 Java 的 DynamoDB 加密客户端中的 *x* 已于 2022 [end-of-support 年](what-is-database-encryption-sdk.md#support) 7 月开始分阶段生效。请尽快升级到更新的版本。

**Topics**
+ [先决条件](#java-prerequisites)
+ [安装](#java-installation)
+ [使用适用于 Java 的 DynamoDB 加密客户端](java-using.md)
+ [Java 示例](java-examples.md)

## 先决条件
<a name="java-prerequisites"></a>

在安装适用于 Java 的 Amazon DynamoDB Encryption Client 之前，请确保满足以下先决条件。

**Java 开发环境**  
您需要使用 Java 8 或更高版本。在 Oracle 网站上，转到 [Java SE 下载](https://www.oracle.com/java/technologies/downloads/)，然后下载并安装 Java SE Development Kit (JDK)。  
如果使用 Oracle JDK，您还必须下载并安装 [Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files](http://www.oracle.com/java/technologies/javase-jce8-downloads.html)。

**适用于 Java 的 AWS SDK**  
即使您的应用程序未与 DynamoDB 交互，DynamoDB 加密客户端也需要的 DynamoDB 模块。 适用于 Java 的 AWS SDK 可以安装整个开发工具包或仅安装此模块。如果使用的是 Maven，则将 `aws-java-sdk-dynamodb` 添加到 `pom.xml` 文件。  
有关安装和配置的更多信息 适用于 Java 的 AWS SDK，请参阅[适用于 Java 的 AWS SDK](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/getting-started.html)。

## 安装
<a name="java-installation"></a>

您可以通过下列方式安装适用于 Java 的 Amazon DynamoDB Encryption Client。

**手动方式**  
要安装适用于 Java 的 Amazon DynamoDB 加密客户端，请克隆或下载存储库。[aws-dynamodb-encryption-java](https://github.com/aws/aws-dynamodb-encryption-java/) GitHub 

**使用 Apache Maven**  
适用于 Java 的 Amazon DynamoDB Encryption Client 通过 [Apache Maven](https://maven.apache.org/) 提供，并具有以下依赖项定义。  

```
<dependency>
  <groupId>com.amazonaws</groupId>
  <artifactId>aws-dynamodb-encryption-java</artifactId>
  <version>version-number</version>
</dependency>
```

安装完软件开发工具包后，请先查看本指南中的示例代码并打开 D [ynamoDB 加密客户端 Jav](https://aws.github.io/aws-dynamodb-encryption-java/) adoc。 GitHub

# 使用适用于 Java 的 DynamoDB 加密客户端
<a name="java-using"></a>

**注意**  
我们的客户端加密库已[重命名为 AWS 数据库加密 SDK](DDBEC-rename.md)。以下主题提供有关适用于 Java 的 DynamoDB 加密客户端版本 1.*x*—2.*x* 以及适用于 Python 的 DynamoDB 加密客户端版本 1.*x*—3.*x* 的信息。有关更多信息，请参阅[适用于 DynamoDB 的AWS 数据库加密 SDK 版本支持](legacy-dynamodb-encryption-client.md#legacy-support)。

本主题介绍了 Java 中的 DynamoDB 加密客户端的可能在其他编程语言实施中找不到的一些功能。

[https://github.com/aws/aws-dynamodb-encryption-java/tree/master/examples](https://github.com/aws/aws-dynamodb-encryption-java/tree/master/examples)



**Topics**
+ [项目加密程序](#attribute-encryptor)
+ [配置保存行为](#save-behavior)
+ [Java 中的属性操作](#attribute-actions-java)
+ [覆盖表名称](#override-table-name)

## 物品加密器： AttributeEncryptor 和 Dynamo DBEncryptor
<a name="attribute-encryptor"></a>

[Java 中的 DynamoDB 加密客户端有[两个项目](DDBEC-legacy-concepts.md#item-encryptor)加密器：较低级别的 Dynamo 和。DBEncryptor [AttributeEncryptor](#attribute-encryptor)](https://aws.github.io/aws-dynamodb-encryption-java/com/amazonaws/services/dynamodbv2/datamodeling/encryption/DynamoDBEncryptor.html)

`AttributeEncryptor`是一个帮助程序类，可帮助您在 [DynamoD](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBMapper.Methods.html) B DBMapper 加密客户端`DynamoDB Encryptor`中 适用于 Java 的 AWS SDK 使用 Dynamo。如果您结合使用 `AttributeEncryptor` 和 `DynamoDBMapper`，则当您保存项目时，它会透明对项目进行加密并签名。当您加载项目时，它还会透明地验证和解密您的项目。

## 配置保存行为
<a name="save-behavior"></a>

您可以使用 `AttributeEncryptor` 和 `DynamoDBMapper` 来添加或替换具有仅已签名（或已加密和签名）的属性的表项目。对于这些任务，我们建议您将其配置为使用 `PUT` 保存行为，如以下示例所示。否则，您可能无法解密您的数据。

```
DynamoDBMapperConfig mapperConfig = DynamoDBMapperConfig.builder().withSaveBehavior(SaveBehavior.PUT).build();
DynamoDBMapper mapper = new DynamoDBMapper(ddb, mapperConfig, new AttributeEncryptor(encryptor));
```

如果您使用默认保存行为（仅更新在表项目中建模的属性），则未建模的属性将不会包含在签名中，且不会由表写入更改。因此，在以后读取所有的属性时，签名将无法验证，因为它不包括未建模的属性。

您也可以使用 `CLOBBER` 保存行为。该行为与 `PUT` 保存行为相同，只不过它将禁用乐观锁并覆盖表中的项目。

为防止签名错误，如果 `AttributeEncryptor` 与未配置 `CLOBBER` 或 `PUT` 保存行为的 `DynamoDBMapper` 一起使用，则 DynamoDB 加密客户端会抛出运行时系统异常。

要查看示例中使用的此代码，请参阅[使用发电机 DBMapper](java-examples.md#java-example-dynamodb-mapper)和中`aws-dynamodb-encryption-java`存储库中的 [AwsKmsEncryptedObject GitHub.java](https://github.com/aws/aws-dynamodb-encryption-java/blob/master/examples/src/main/java/com/amazonaws/examples/AwsKmsEncryptedObject.java) 示例。

## Java 中的属性操作
<a name="attribute-actions-java"></a>

[属性操作](DDBEC-legacy-concepts.md#legacy-attribute-actions)确定加密并签名的属性值、仅签名的属性值以及忽略的属性值。用于指定属性操作的方法取决于您使用的是`DynamoDBMapper`和`AttributeEncryptor`还是较低级别的 [Dynam DBEncryptor](https://aws.github.io/aws-dynamodb-encryption-java/com/amazonaws/services/dynamodbv2/datamodeling/encryption/DynamoDBEncryptor.html) o。

**重要**  
使用属性操作对表项进行加密后，在数据模型中添加或删除属性可能会导致签名验证错误，从而使您无法解密数据。有关详细说明，请参阅[更改数据模型](data-model.md)。

### Dynamo 的属性动作 DBMapper
<a name="attribute-action-java-mapper"></a>

当您使用 `DynamoDBMapper` 和 `AttributeEncryptor` 时，使用注释指定属性操作。DynamoDB 加密客户端使用[标准 DynamoDB 属性注释](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBMapper.Annotations.html)，该注释可定义属性类型以确定如何保护属性。默认情况下，除主键以外的所有属性均加密并签名，主键已签名但未加密。

**注意**  
不要使用 [@Dynamo Attribut DBVersion e 注解](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBMapper.OptimisticLocking.html)对属性的值进行加密，尽管你可以（也应该）对它们进行签名。否则，使用其值的情况将产生意外后果。

```
// Attributes are encrypted and signed
@DynamoDBAttribute(attributeName="Description")

// Partition keys are signed but not encrypted
@DynamoDBHashKey(attributeName="Title")

// Sort keys are signed but not encrypted
@DynamoDBRangeKey(attributeName="Author")
```

要指定例外情况，请使用在适用于 Java 的 DynamoDB 加密客户端中定义的加密注释。如果您在类级别指定这些注释，它们将成为该类的默认值。

```
// Sign only
@DoNotEncrypt

// Do nothing; not encrypted or signed
@DoNotTouch
```

例如，这些注释签署但未加密 `PublicationYear` 属性，而且未加密或签署 `ISBN` 属性值。

```
// Sign only (override the default)
@DoNotEncrypt
@DynamoDBAttribute(attributeName="PublicationYear")

// Do nothing (override the default)
@DoNotTouch
@DynamoDBAttribute(attributeName="ISBN")
```

### Dynamo 的属性动作 DBEncryptor
<a name="attribute-action-default"></a>

要在DBEncryptor直接使用 [Dynamo](https://aws.github.io/aws-dynamodb-encryption-java/com/amazonaws/services/dynamodbv2/datamodeling/encryption/DynamoDBEncryptor.html) 时指定属性操作，请创建一个`HashMap`对象，其中名称/值对表示属性名称和指定操作。

有效值适用于在 `EncryptionFlags` 枚举类型中定义的属性操作。您可以结合使用 `ENCRYPT` 和 `SIGN`，单独使用 `SIGN`，或同时忽略。但是，如果您单独使用 `ENCRYPT`，则 DynamoDB 加密客户端会抛出错误。您无法加密未签名的属性。

```
ENCRYPT
SIGN
```

**警告**  
请勿加密主键属性。它们必须保留为明文，以便 DynamoDB 查找项目而无需运行全表扫描。

如果您在加密上下文中指定一个主键，然后为主键属性的属性操作指定 `ENCRYPT`，则 DynamoDB 加密客户端会抛出异常。

例如，以下 Java 代码创建了一个`actions` HashMap 对`record`项目中的所有属性进行加密和签名。例外是分区键和排序键属性（这些属性已签名但未加密）以及 `test` 属性（该属性未签名或未加密）。

```
final EnumSet<EncryptionFlags> signOnly = EnumSet.of(EncryptionFlags.SIGN);
final EnumSet<EncryptionFlags> encryptAndSign = EnumSet.of(EncryptionFlags.ENCRYPT, EncryptionFlags.SIGN);
final Map<String, Set<EncryptionFlags>> actions = new HashMap<>();

for (final String attributeName : record.keySet()) {
  switch (attributeName) {
    case partitionKeyName: // no break; falls through to next case
    case sortKeyName:
      // Partition and sort keys must not be encrypted, but should be signed
      actions.put(attributeName, signOnly);
      break;
    case "test":
      // Don't encrypt or sign
      break;
    default:
      // Encrypt and sign everything else
      actions.put(attributeName, encryptAndSign);
      break;
  }
}
```

然后，当您调用 `DynamoDBEncryptor` 的 [encryptRecord](https://aws.github.io/aws-dynamodb-encryption-java/com/amazonaws/services/dynamodbv2/datamodeling/encryption/DynamoDBEncryptor.html#encryptRecord-java.util.Map-java.util.Map-com.amazonaws.services.dynamodbv2.datamodeling.encryption.EncryptionContext-) 方法时，将映射指定为 `attributeFlags` 参数的值。例如，这个对 `encryptRecord` 的调用使用 `actions` 映射。

```
// Encrypt the plaintext record
final Map<String, AttributeValue> encrypted_record = encryptor.encryptRecord(record, actions, encryptionContext);
```

## 覆盖表名称
<a name="override-table-name"></a>

在 DynamoDB 加密客户端中，DynamoDB 表的名称是传递到加密和解密方法的 [DynamoDB 加密上下文](concepts.md#encryption-context)的元素。对表项目进行加密或签名时，DynamoDB 加密上下文（包括表名称）以加密方式绑定到加密文字。如果传递给解密方法的 DynamoDB 加密上下文与传递给加密方法的 DynamoDB 加密上下文不匹配，则解密操作将失败。

有时，表的名称会发生变化，例如备份表或执行[point-in-time 恢复](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/PointInTimeRecovery.html)时。解密或验证这些项目的签名时，必须传递用于对项目进行加密和签名的相同 DynamoDB 加密上下文，包括原始表名称。不需要当前表名称。

使用 `DynamoDBEncryptor` 时，您将手动汇编 DynamoDB 加密上下文。但是，如果使用 `DynamoDBMapper`，`AttributeEncryptor` 会为您创建 DynamoDB 加密上下文，包括当前表名称。要告知 `AttributeEncryptor` 使用其他表名称创建加密上下文，请使用 `EncryptionContextOverrideOperator`。

例如，以下代码创建加密材料提供程序 (CMP) 和 `DynamoDBEncryptor` 的实例。然后，它调用 `DynamoDBEncryptor` 的 `setEncryptionContextOverrideOperator` 方法。它使用 `overrideEncryptionContextTableName` 运算符，该运算符将覆盖一个表名称。通过这种方式配置它后，`AttributeEncryptor` 会创建一个 DynamoDB 加密上下文，其中包含 `newTableName` 以代替 `oldTableName`。有关完整的示例，请参阅 [EncryptionContextOverridesWithDynamoDBMapper.java。](https://github.com/aws/aws-dynamodb-encryption-java/blob/master/examples/src/main/java/com/amazonaws/examples/EncryptionContextOverridesWithDynamoDBMapper.java)

```
final DirectKmsMaterialProvider cmp = new DirectKmsMaterialProvider(kms, keyArn);
final DynamoDBEncryptor encryptor = DynamoDBEncryptor.getInstance(cmp);

encryptor.setEncryptionContextOverrideOperator(EncryptionContextOperators.overrideEncryptionContextTableName(
                oldTableName, newTableName));
```

当您调用 `DynamoDBMapper` 的加载方法（该方法解密并验证项目）时，您指定原始表名称。

```
mapper.load(itemClass, DynamoDBMapperConfig.builder()
                .withTableNameOverride(DynamoDBMapperConfig.TableNameOverride.withTableNameReplacement(oldTableName))
                .build());
```

您还可以使用 `overrideEncryptionContextTableNameUsingMap` 运算符，该运算符将覆盖多个表名称。

表名称覆盖运算符通常在解密数据和验证签名时使用。但是，您可以使用它们在加密和签名时将 DynamoDB 加密上下文中的表名称设置为其他值。

如果使用 `DynamoDBEncryptor`，请不要使用表名称覆盖运算符。而是使用原始表名称创建一个加密上下文，并将其提交给解密方法。

# 适用于 Java 的 DynamoDB 加密客户端的示例代码
<a name="java-examples"></a>

**注意**  
我们的客户端加密库已[重命名为 AWS 数据库加密 SDK](DDBEC-rename.md)。以下主题提供有关适用于 Java 的 DynamoDB 加密客户端版本 1.*x*—2.*x* 以及适用于 Python 的 DynamoDB 加密客户端版本 1.*x*—3.*x* 的信息。有关更多信息，请参阅[适用于 DynamoDB 的AWS 数据库加密 SDK 版本支持](legacy-dynamodb-encryption-client.md#legacy-support)。

以下示例为您演示如何使用适用于 Java 的 DynamoDB 加密客户端来保护应用程序中的 DynamoDB 表项目。你可以在上[aws-dynamodb-encryption-java](https://github.com/aws/aws-dynamodb-encryption-java/)存储库的示例目录中找到更多[示例](https://github.com/aws/aws-dynamodb-encryption-java/tree/master/examples)（并贡献自己的示例） GitHub。

**Topics**
+ [使用发电机 DBEncryptor](#java-example-ddb-encryptor)
+ [使用发电机 DBMapper](#java-example-dynamodb-mapper)

## 使用发电机 DBEncryptor
<a name="java-example-ddb-encryptor"></a>

此示例说明如何将较低级别的 [Dynamo DBEncryptor](https://aws.github.io/aws-dynamodb-encryption-java/com/amazonaws/services/dynamodbv2/datamodeling/encryption/DynamoDBEncryptor.html) 与 Di [rect KMS](direct-kms-provider.md) 提供程序配合使用。直接 KMS 提供商在您指定的 [AWS KMS key](https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#master_keys)in AWS Key Management Service (AWS KMS) 下生成并保护其加密材料。

您可以将任何兼容的[加密材料提供程序](DDBEC-legacy-concepts.md#concept-material-provider) (CMP) 与一起使用`DynamoDBEncryptor`，也可以将直接 KMS 提供程序与`DynamoDBMapper`和[AttributeEncryptor](java-using.md#attribute-encryptor)一起使用。

**查看完整的代码示例**：[AwsKmsEncryptedItem.java](https://github.com/aws/aws-dynamodb-encryption-java/blob/master/examples/src/main/java/com/amazonaws/examples/AwsKmsEncryptedItem.java)

步骤 1：创建 Direct KMS 提供程序  
创建指定区域的 AWS KMS 客户端实例。然后，使用客户端实例借助您的首选 AWS KMS key创建 Direct KMS 提供程序的实例。  
此示例使用 Amazon 资源名称 (ARN) 来标识 AWS KMS key，但您可以使用[任何有效的密钥](https://docs.aws.amazon.com/kms/latest/developerguide/viewing-keys.html#find-cmk-id-arn)标识符。  

```
final String keyArn = "arn:aws:kms:us-west-2:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab";
final String region = "us-west-2";
      
final AWSKMS kms = AWSKMSClientBuilder.standard().withRegion(region).build();
final DirectKmsMaterialProvider cmp = new DirectKmsMaterialProvider(kms, keyArn);
```

步骤 2：创建项目  
此示例定义了`record` HashMap 表示示例表项的。  

```
final String partitionKeyName = "partition_attribute";
final String sortKeyName = "sort_attribute";

final Map<String, AttributeValue> record = new HashMap<>();
record.put(partitionKeyName, new AttributeValue().withS("value1"));
record.put(sortKeyName, new AttributeValue().withN("55"));
record.put("example", new AttributeValue().withS("data"));
record.put("numbers", new AttributeValue().withN("99"));
record.put("binary", new AttributeValue().withB(ByteBuffer.wrap(new byte[]{0x00, 0x01, 0x02})));
record.put("test", new AttributeValue().withS("test-value"));
```

步骤 3：创建发电机 DBEncryptor  
使用 Direct KMS 提供程序创建 `DynamoDBEncryptor` 的实例。  

```
final DynamoDBEncryptor encryptor = DynamoDBEncryptor.getInstance(cmp);
```

步骤 4：创建 DynamoDB 加密上下文  
[DynamoDB 加密上下文](concepts.md#encryption-context)包含有关表结构以及其如何加密和签名的信息。如果使用的是 `DynamoDBMapper`，则 `AttributeEncryptor` 会为您创建加密上下文。  

```
final String tableName = "testTable";

final EncryptionContext encryptionContext = new EncryptionContext.Builder()
    .withTableName(tableName)
    .withHashKeyName(partitionKeyName)
    .withRangeKeyName(sortKeyName)
    .build();
```

步骤 5：创建属性操作对象  
[属性操作](DDBEC-legacy-concepts.md#legacy-attribute-actions)确定已加密并签名的项目属性、仅签名的属性以及未加密或签名的属性。  
在 Java 中，要指定属性操作，需要创建属性名称和`EncryptionFlags`值对。 HashMap   
例如，以下 Java 代码创建了一个`actions` HashMap 对`record`项目中的所有属性进行加密和签名，但分区键和排序密钥属性（已签名但未加密）以及未签名或加密的`test`属性除外。  

```
final EnumSet<EncryptionFlags> signOnly = EnumSet.of(EncryptionFlags.SIGN);
final EnumSet<EncryptionFlags> encryptAndSign = EnumSet.of(EncryptionFlags.ENCRYPT, EncryptionFlags.SIGN);
final Map<String, Set<EncryptionFlags>> actions = new HashMap<>();

for (final String attributeName : record.keySet()) {
  switch (attributeName) {
    case partitionKeyName: // fall through to the next case
    case sortKeyName:
      // Partition and sort keys must not be encrypted, but should be signed
      actions.put(attributeName, signOnly);
      break;
    case "test":
      // Neither encrypted nor signed
      break;
    default:
      // Encrypt and sign all other attributes
      actions.put(attributeName, encryptAndSign);
      break;
  }
}
```

步骤 6：加密并签名项目  
要加密并签名项目，请对 `encryptRecord` 的实例调用 `DynamoDBEncryptor` 方法。指定表项目 (`record`)、属性操作 (`actions`) 和加密上下文 (`encryptionContext`)。  

```
final Map<String, AttributeValue> encrypted_record = encryptor.encryptRecord(record, actions, encryptionContext);
```

步骤 7：将项目放入 DynamoDB 表中  
最后，将已加密且签名的项目放入 DynamoDB 表中。  

```
final AmazonDynamoDB ddb = AmazonDynamoDBClientBuilder.defaultClient();
ddb.putItem(tableName, encrypted_record);
```

## 使用发电机 DBMapper
<a name="java-example-dynamodb-mapper"></a>

以下示例为您演示如何结合使用 DynamoDB Mapper 帮助程序类与 [Direct KMS 提供程序](direct-kms-provider.md)。Direct KMS 提供程序借助您指定的 AWS Key Management Service （AWS KMS）中的 [AWS KMS key](https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#master_keys) 生成并保护其加密材料。

您可以结合使用任何兼容的[加密材料提供程序](DDBEC-legacy-concepts.md#concept-material-provider) (CMP) 与 `DynamoDBMapper`，也可以结合使用 Direct KMS 提供程序与低级别 `DynamoDBEncryptor`。

**查看完整的代码示例**：[AwsKmsEncryptedObject.java](https://github.com/aws/aws-dynamodb-encryption-java/blob/master/examples/src/main/java/com/amazonaws/examples/AwsKmsEncryptedObject.java)

步骤 1：创建 Direct KMS 提供程序  
创建指定区域的 AWS KMS 客户端实例。然后，使用客户端实例借助您的首选 AWS KMS key创建 Direct KMS 提供程序的实例。  
此示例使用 Amazon 资源名称 (ARN) 来标识 AWS KMS key，但您可以使用[任何有效的密钥](https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#key-id)标识符。  

```
final String keyArn = "arn:aws:kms:us-west-2:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab";
final String region = "us-west-2";
      
final AWSKMS kms = AWSKMSClientBuilder.standard().withRegion(region).build();
final DirectKmsMaterialProvider cmp = new DirectKmsMaterialProvider(kms, keyArn);
```

第 2 步：创建 DynamoDB 加密器和 Dynamo DBMapper  
使用您在上一步中创建的 Direct KMS 提供程序创建 [DynamoDB Encryptor](java-using.md#attribute-encryptor) 的实例。您需要实例化低级别 DynamoDB Encryptor 才能使用 DynamoDB Mapper。  
接着，创建 DynamoDB 数据库的实例和映射器配置，然后使用它们创建 DynamoDB Mapper 的实例。  
当使用 `DynamoDBMapper` 添加或编辑已签名（或已加密并签名）项目时，将其配置为[使用保存行为](java-using.md#save-behavior)（如包含所有属性的 `PUT`），如以下示例所示。否则，您可能无法解密您的数据。

```
final DynamoDBEncryptor encryptor = DynamoDBEncryptor.getInstance(cmp)
final AmazonDynamoDB ddb = AmazonDynamoDBClientBuilder.standard().withRegion(region).build();

DynamoDBMapperConfig mapperConfig = DynamoDBMapperConfig.builder().withSaveBehavior(SaveBehavior.PUT).build();
DynamoDBMapper mapper = new DynamoDBMapper(ddb, mapperConfig, new AttributeEncryptor(encryptor));
```

步骤 3：定义您的 DynamoDB 表  
接下来，定义您的 DynamoDB 表。使用注释指定[属性操作](java-using.md#attribute-actions-java)。此示例将创建一个 DynamoDB 表、`ExampleTable`，以及一个表示表项目的 `DataPoJo` 类。  
在此示例表中，将为主键属性签名，但不进行加密。这适用于使用 `@DynamoDBHashKey` 进行注释的 `partition_attribute` 以及使用 `@DynamoDBRangeKey` 进行注释的 `sort_attribute`。  
将为使用 `@DynamoDBAttribute` 进行注释的属性（如 `some numbers`）加密并签名。使用 `@DoNotEncrypt`（仅签名）或 DynamoDB 加密客户端定义的 `@DoNotTouch`（不进行加密或签名）加密注释的属性则例外。例如，由于 `leave me` 属性具有 `@DoNotTouch` 注释，因此不会为其加密或签名。  

```
@DynamoDBTable(tableName = "ExampleTable")
public static final class DataPoJo {
  private String partitionAttribute;
  private int sortAttribute;
  private String example;
  private long someNumbers;
  private byte[] someBinary;
  private String leaveMe;

  @DynamoDBHashKey(attributeName = "partition_attribute")
  public String getPartitionAttribute() {
    return partitionAttribute;
  }

  public void setPartitionAttribute(String partitionAttribute) {
    this.partitionAttribute = partitionAttribute;
  }

  @DynamoDBRangeKey(attributeName = "sort_attribute")
  public int getSortAttribute() {
    return sortAttribute;
  }

  public void setSortAttribute(int sortAttribute) {
    this.sortAttribute = sortAttribute;
  }

  @DynamoDBAttribute(attributeName = "example")
  public String getExample() {
    return example;
  }

  public void setExample(String example) {
    this.example = example;
  }

  @DynamoDBAttribute(attributeName = "some numbers")
  public long getSomeNumbers() {
    return someNumbers;
  }

  public void setSomeNumbers(long someNumbers) {
    this.someNumbers = someNumbers;
  }

  @DynamoDBAttribute(attributeName = "and some binary")
  public byte[] getSomeBinary() {
    return someBinary;
  }

  public void setSomeBinary(byte[] someBinary) {
    this.someBinary = someBinary;
  }

  @DynamoDBAttribute(attributeName = "leave me")
  @DoNotTouch
  public String getLeaveMe() {
    return leaveMe;
  }

  public void setLeaveMe(String leaveMe) {
    this.leaveMe = leaveMe;
  }

  @Override
  public String toString() {
    return "DataPoJo [partitionAttribute=" + partitionAttribute + ", sortAttribute="
        + sortAttribute + ", example=" + example + ", someNumbers=" + someNumbers
        + ", someBinary=" + Arrays.toString(someBinary) + ", leaveMe=" + leaveMe + "]";
  }
}
```

步骤 4：加密并保存表项目  
现在，当您创建一个表项目并使用 DynamoDB Mapper 保存它时，会在将此项目添加到表之前自动对其进行加密和签名。  
此示例定义一个名为 `record` 的表项目。在将此表项目保存到表中之前，将基于 `DataPoJo` 类中的注释为其属性加密和签名。在此示例中，将为 `PartitionAttribute`、`SortAttribute` 和 `LeaveMe` 之外的所有属性加密和签名。仅为 `PartitionAttribute` 和 `SortAttributes` 进行签名。不会为 `LeaveMe` 属性加密或签名。  
要为 `record` 项目加密并签名，然后将其添加到 `ExampleTable`，请调用 `DynamoDBMapper` 类的 `save` 方法。由于您的 DynamoDB Mapper 配置为使用 `PUT` 保存行为，因此项目将替换具有相同主键的任何项目，而不是更新这些项目。这将确保签名匹配，并且您可以在从表中获取项目时为其解密。  

```
DataPoJo record = new DataPoJo();
record.setPartitionAttribute("is this");
record.setSortAttribute(55);
record.setExample("data");
record.setSomeNumbers(99);
record.setSomeBinary(new byte[]{0x00, 0x01, 0x02});
record.setLeaveMe("alone");

mapper.save(record);
```

# 适用于 Python 的 DynamoDB 加密客户端
<a name="python"></a>

**注意**  
我们的客户端加密库已[重命名为 AWS 数据库加密 SDK](DDBEC-rename.md)。以下主题提供有关适用于 Java 的 DynamoDB 加密客户端版本 1.*x*—2.*x* 以及适用于 Python 的 DynamoDB 加密客户端版本 1.*x*—3.*x* 的信息。有关更多信息，请参阅[适用于 DynamoDB 的AWS 数据库加密 SDK 版本支持](legacy-dynamodb-encryption-client.md#legacy-support)。

本主题介绍了如何安装和使用适用于 Python 的 DynamoDB 加密客户端。您可以在上的[aws-dynamodb-encryption-python](https://github.com/aws/aws-dynamodb-encryption-python/)存储库中找到代码 GitHub，包括完整且经过测试的[示例代码](https://github.com/aws/aws-dynamodb-encryption-python/tree/master/examples)，以帮助您入门。

**注意**  
版本 1. *x*。 *x* 和 2。 *x*。 适用于 Python 的 DynamoDB 加密客户端的 *x* 已于 2022 [end-of-support 年](what-is-database-encryption-sdk.md#support) 7 月开始分阶段生效。请尽快升级到更新的版本。

**Topics**
+ [先决条件](#python-prerequisites)
+ [安装](#python-installation)
+ [使用适用于 Python 的 DynamoDB 加密客户端](python-using.md)
+ [Python 示例](python-examples.md)

## 先决条件
<a name="python-prerequisites"></a>

在安装适用于 Python 的 Amazon DynamoDB Encryption Client 之前，请确保满足以下先决条件。

**支持的 Python 版本**  
对于 Python 版本 3.3.0 及更高版本，亚马逊 DynamoDB 加密客户端需要 Python 3.8 或更高版本。要下载 Python，请参阅 [Python 下载](https://www.python.org/downloads/)。  
适用于 Python 的 Amazon DynamoDB Encryption Client 的早期版本支持 Python 2.7 和 Python 3.4 及更高版本，但我们建议您使用 DynamoDB 加密客户端的最新版本。

**适用于 Python 的 pip 安装工具**  
Python 3.6 及更高版本包括 **pip**，但您可能需要对其进行升级。有关升级或安装 pip 的更多信息，请参阅 **pip** 文档中的[安装](https://pip.pypa.io/en/latest/installation/)。

## 安装
<a name="python-installation"></a>

可以使用 **pip** 安装适用于 Python 的 Amazon DynamoDB Encryption Client，如以下示例中所示。

**安装最新版本**  

```
pip install dynamodb-encryption-sdk
```

有关使用 **pip** 安装和升级程序包的详细信息，请参阅[安装程序包](https://packaging.python.org/tutorials/installing-packages/)。

DynamoDB 加密客户端要求在所有平台上使用[加密库](https://cryptography.io/en/latest/)。所有 **pip** 版本在 Windows 上安装和构建**加密**库。**pip** 8.1 和更高版本在 Linux 上安装和构建**加密**库。如果使用早期版本的 **pip** 并且 Linux 环境没有构建**加密**库所需的工具，则需要安装这些工具。有关更多信息，请参阅[在 Linux 上构建加密](https://cryptography.io/en/latest/installation/#building-cryptography-on-linux)。

您可以从存储库中获取 DynamoDB 加密客户端的最新[aws-dynamodb-encryption-python](https://github.com/aws/aws-dynamodb-encryption-python/)开发版本。 GitHub

安装 DynamoDB 加密客户端后，先从在本指南中查找示例 Python 代码。

# 使用适用于 Python 的 DynamoDB 加密客户端
<a name="python-using"></a>

**注意**  
我们的客户端加密库已[重命名为 AWS 数据库加密 SDK](DDBEC-rename.md)。以下主题提供有关适用于 Java 的 DynamoDB 加密客户端版本 1.*x*—2.*x* 以及适用于 Python 的 DynamoDB 加密客户端版本 1.*x*—3.*x* 的信息。有关更多信息，请参阅[适用于 DynamoDB 的AWS 数据库加密 SDK 版本支持](legacy-dynamodb-encryption-client.md#legacy-support)。

本主题介绍了适用于 Python 的 DynamoDB 加密客户端的可能在其他编程语言实施中找不到的一些功能。这些功能旨在更轻松地以最安全的方式使用 DynamoDB 加密客户端。除非您有不寻常的使用案例，否则我们建议您使用这些功能。

[有关使用 DynamoDB 加密客户端进行编程的详细信息，请参阅本指南中的 [Python](python-examples.md) 示例、存储库 GitHub中的 aws-dynamodb-encryption-python示例以及 DynamoDB 加密客户端的 [Python](https://aws-dynamodb-encryption-python.readthedocs.io/en/latest/) 文档。](https://github.com/aws/aws-dynamodb-encryption-python/tree/master/examples)

**Topics**
+ [客户端帮助程序类](#python-helpers)
+ [TableInfo 班级](#table-info)
+ [Python 中的属性操作](#python-attribute-actions)

## 客户端帮助程序类
<a name="python-helpers"></a>

适用于 Python 的 DynamoDB 加密客户端包括多个对 DynamoDB 的 Boto 3 类进行镜像的客户端帮助程序类。这些帮助程序类旨在更轻松地向您的现有 DynamoDB 应用程序添加加密和签名并且避免最常见问题，如下所示：
+ 通过向对象添加主密钥的覆盖操作，或者在您的[AttributeActions](#python-attribute-actions)`AttributeActions`对象明确要求客户端加密主密钥时抛出异常，防止您对项目中的主密钥进行加密。如果您的 `AttributeActions` 对象中的默认操作为 `DO_NOTHING`，则客户端帮助程序类会对主键使用该操作。否则，它们使用 `SIGN_ONLY`。
+ 创建[TableInfo 对象](#python-helpers)并根据对 Dynamo [DB 的调用填充 DynamoDB 加密](concepts.md#encryption-context)上下文。这有助于确保您的 DynamoDB 加密上下文准确且客户端可以标识主键。
+ 支持方法（如 `put_item` 和 `get_item`），这些方法在您在 DynamoDB 表中写入或读取时会以透明方式加密和解密表项目。仅不支持 `update_item` 方法。

您可以使用客户端帮助程序类而不是直接与较低级别的[项目加密程序](DDBEC-legacy-concepts.md#item-encryptor)交互。除非您需要在项目加密程序中设置高级选项，否则使用这些类。

客户端帮助程序类包括：
+ [EncryptedTable](https://aws-dynamodb-encryption-python.readthedocs.io/en/latest/lib/encrypted/table.html#module-dynamodb_encryption_sdk.encrypted.table)适用于使用 DynamoDB 中的[表](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb.html#table)资源一次处理一张表的应用程序。
+ [EncryptedResource](https://aws-dynamodb-encryption-python.readthedocs.io/en/latest/lib/encrypted/resource.html)适用于使用 DynamoDB 中的[服务资源](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb.html#service-resource)类进行批处理的应用程序。
+ [EncryptedClient](https://aws-dynamodb-encryption-python.readthedocs.io/en/latest/lib/encrypted/client.html)适用于在 DynamoDB 中使用[较低级别客户端](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb.html#client)的应用程序。

要使用客户端帮助程序类，调用者必须具有在目标表上调用 Dynam [DescribeTable](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_DescribeTable.html)oDB 操作的权限。

## TableInfo 班级
<a name="table-info"></a>

该[TableInfo](https://aws-dynamodb-encryption-python.readthedocs.io/en/latest/lib/tools/structures.html#dynamodb_encryption_sdk.structures.TableInfo)类是一个代表一个 DynamoDB 表的辅助类，其中包含用于其主键和二级索引的字段。它有助于您获取有关表的准确的实时信息。

如果您使用的是[客户端帮助程序类](#python-helpers)，它会为您创建并使用 `TableInfo` 对象。否则，您可以明确创建一个。有关示例，请参阅[使用项目加密程序](python-examples.md#python-example-item-encryptor)。

当您在`TableInfo`对象上调用该`refresh_indexed_attributes`方法时，它会通过调用 DynamoDB [DescribeTable](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_DescribeTable.html)操作来填充该对象的属性值。查询表要比硬编码索引名称更加可靠。`TableInfo` 类还包括 `encryption_context_values` 属性，该属性提供了 [DynamoDB 加密上下文](concepts.md#encryption-context)所需的值。

要使用该`refresh_indexed_attributes`方法，调用者必须具有在目标表上调用 Dynam [DescribeTable](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_DescribeTable.html)oDB 操作的权限。

## Python 中的属性操作
<a name="python-attribute-actions"></a>

[属性操作](DDBEC-legacy-concepts.md#legacy-attribute-actions)告知项目加密程序将对项目的每个属性执行哪些操作。要在 Python 中指定属性操作，请创建具有默认操作和针对特定属性的任何例外的 `AttributeActions` 对象。有效值将在 `CryptoAction` 枚举类型中定义。

**重要**  
使用属性操作对表项进行加密后，在数据模型中添加或删除属性可能会导致签名验证错误，从而使您无法解密数据。有关详细说明，请参阅[更改数据模型](data-model.md)。

```
DO_NOTHING = 0
SIGN_ONLY = 1
ENCRYPT_AND_SIGN = 2
```

例如，此 `AttributeActions` 对象建立 `ENCRYPT_AND_SIGN` 作为所有属性的默认值，并且指定 `ISBN` 和 `PublicationYear` 属性的例外。

```
actions = AttributeActions(
    default_action=CryptoAction.ENCRYPT_AND_SIGN,
    attribute_actions={
        'ISBN': CryptoAction.DO_NOTHING,
        'PublicationYear': CryptoAction.SIGN_ONLY
    }
)
```

如果您使用的是[客户端帮助程序类](#python-helpers)，则无需指定主键属性的属性操作。该客户端帮助程序类阻止您加密主键。

如果您未使用客户端帮助程序类且默认操作为 `ENCRYPT_AND_SIGN`，则必须为主键指定操作。对主键建议的操作为 `SIGN_ONLY`。要轻松实现此操作，请使用 `set_index_keys` 方法，该方法对主键使用 SIGN\$1ONLY，或者使用 DO\$1NOTHING，这是默认操作。

**警告**  
请勿加密主键属性。它们必须保留为明文，以便 DynamoDB 查找项目而无需运行全表扫描。

```
actions = AttributeActions(
    default_action=CryptoAction.ENCRYPT_AND_SIGN,
)
actions.set_index_keys(*table_info.protected_index_keys())
```

# 适用于 Python 的 DynamoDB 加密客户端的示例代码
<a name="python-examples"></a>

**注意**  
我们的客户端加密库已[重命名为 AWS 数据库加密 SDK](DDBEC-rename.md)。以下主题提供有关适用于 Java 的 DynamoDB 加密客户端版本 1.*x*—2.*x* 以及适用于 Python 的 DynamoDB 加密客户端版本 1.*x*—3.*x* 的信息。有关更多信息，请参阅[适用于 DynamoDB 的AWS 数据库加密 SDK 版本支持](legacy-dynamodb-encryption-client.md#legacy-support)。

以下示例为您演示如何使用适用于 Python 的 DynamoDB 加密客户端来保护应用程序中的 DynamoDB 数据。你可以在上[aws-dynamodb-encryption-python](https://github.com/aws/aws-dynamodb-encryption-python/)存储库的示例目录中找到更多[示例](https://github.com/aws/aws-dynamodb-encryption-python/tree/master/examples)（并贡献自己的示例） GitHub。

**Topics**
+ [使用 EncryptedTable 客户端帮助器类](#python-example-table)
+ [使用项目加密程序](#python-example-item-encryptor)

## 使用 EncryptedTable 客户端帮助器类
<a name="python-example-table"></a>

以下示例为您演示如何结合使用 [Direct KMS 提供程序](direct-kms-provider.md)和此`EncryptedTable`[客户端帮助程序类](python-using.md#python-helpers)。此示例使用相同的[加密材料提供程序](DDBEC-legacy-concepts.md#concept-material-provider)，如[使用项目加密程序](#python-example-item-encryptor)示例所示。但是，它使用的是 `EncryptedTable` 类，而不是与低级别[项目加密程序](DDBEC-legacy-concepts.md#item-encryptor)直接交互。

通过比较这些示例，您可以看到客户端帮助程序类为您执行的工作。这包括创建 [DynamoDB 加密上下文](concepts.md#encryption-context)和确保始终为主键属性签名，但绝不加密。要创建加密上下文并发现主密钥，客户端帮助程序类会调用 DynamoDB 操作[DescribeTable](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_DescribeTable.html)。要运行此代码，您必须具有调用此操作的权限。

**请参阅完整的代码示例**：[aws\$1kms\$1encrypted\$1table.py](https://github.com/aws/aws-dynamodb-encryption-python/blob/master/examples/src/dynamodb_encryption_sdk_examples/aws_kms_encrypted_table.py)

步骤 1：创建表  
首先使用表名称创建标准 DynamoDB 表的实例。  

```
table_name='test-table'
table = boto3.resource('dynamodb').Table(table_name)
```

步骤 2：创建加密材料提供程序  
创建您选择的[加密材料提供程序](crypto-materials-providers.md) (CMP) 的实例。  
此示例使用 [Direct KMS 提供程序](direct-kms-provider.md)，但您可以使用任何兼容的 CMP。要创建 Direct KMS 提供程序，请指定 [AWS KMS key](https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#master_keys)。此示例使用的 Amazon 资源名称 (ARN) AWS KMS key，但您可以使用任何有效的密钥标识符。  

```
kms_key_id='arn:aws:kms:us-west-2:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab'
kms_cmp = AwsKmsCryptographicMaterialsProvider(key_id=kms_key_id)
```

步骤 3：创建属性操作对象  
[属性操作](DDBEC-legacy-concepts.md#legacy-attribute-actions)告知项目加密程序将对项目的每个属性执行哪些操作。此示例中的 `AttributeActions` 对象加密并签名所有项目，除 `test` 属性以外，后者已被忽略。  
请勿在使用客户端帮助程序类时为主键属性指定属性操作。`EncryptedTable` 类会签名但绝不加密主键属性。  

```
actions = AttributeActions(
    default_action=CryptoAction.ENCRYPT_AND_SIGN,
    attribute_actions={'test': CryptoAction.DO_NOTHING}
)
```

步骤 4：创建加密表  
使用标准表、Direct KMS 提供程序和属性操作创建加密表。此步骤将完成配置。  

```
encrypted_table = EncryptedTable(
    table=table,
    materials_provider=kms_cmp,
    attribute_actions=actions
)
```

步骤 5：将明文项目放入表中  
在对 `encrypted_table` 调用 `put_item` 方法时，您的表项目会以透明方式加密、签名并添加到您的 DynamoDB 表。  
首先，定义表项目。  

```
plaintext_item = {
    'partition_attribute': 'value1',
    'sort_attribute': 55
    'example': 'data',
    'numbers': 99,
    'binary': Binary(b'\x00\x01\x02'),
    'test': 'test-value'
}
```
然后，请项目放入表中。  

```
encrypted_table.put_item(Item=plaintext_item)
```

要从采用加密形式的 DynamoDB 表中获取该项目，请对 `table` 对象调用 `get_item` 方法。要获取已解密的项目，请对 `get_item` 对象调用 `encrypted_table` 方法。

## 使用项目加密程序
<a name="python-example-item-encryptor"></a>

此示例向您展示在加密表项目时如何直接与 DynamoDB 加密客户端中的[项目加密程序](DDBEC-legacy-concepts.md#item-encryptor)交互，而不是使用与项目加密程序交互的[客户端帮助程序类](python-using.md#python-helpers)。

使用此方法时，将手动创建 DynamoDB 加密上下文和配置对象（`CryptoConfig`）。此外，您还会在加密一个调用中的项目并将它们放置在您在单独调用中的 DynamoDB 表中。这允许您自定义 `put_item` 调用并使用 DynamoDB 加密客户端来加密并签名绝不发送 DynamoDB 的结构化数据。

此示例使用 [Direct KMS 提供程序](direct-kms-provider.md)，但您可以使用任何兼容的 CMP。

**请参阅完整的代码示例**：[aws\$1kms\$1encrypted\$1item.py](https://github.com/aws/aws-dynamodb-encryption-python/blob/master/examples/src/dynamodb_encryption_sdk_examples/aws_kms_encrypted_item.py)

步骤 1：创建表  
首先使用表名称创建标准 DynamoDB 表资源的实例。  

```
table_name='test-table'
table = boto3.resource('dynamodb').Table(table_name)
```

步骤 2：创建加密材料提供程序  
创建您选择的[加密材料提供程序](crypto-materials-providers.md) (CMP) 的实例。  
此示例使用 [Direct KMS 提供程序](direct-kms-provider.md)，但您可以使用任何兼容的 CMP。要创建 Direct KMS 提供程序，请指定 [AWS KMS key](https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#master_keys)。此示例使用的 Amazon 资源名称 (ARN) AWS KMS key，但您可以使用任何有效的密钥标识符。  

```
kms_key_id='arn:aws:kms:us-west-2:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab'
kms_cmp = AwsKmsCryptographicMaterialsProvider(key_id=kms_key_id)
```

第 3 步：使用 TableInfo 辅助类  
要从 DynamoDB 获取有关表的信息，请创建帮助类的实例。[TableInfo](python-using.md#python-helpers)当您直接使用项目加密程序时，需要创建一个 `TableInfo` 实例并调用其方法：[客户端帮助程序类](python-using.md#python-helpers)可为您执行此操作。  
的`refresh_indexed_attributes`方法`TableInfo`使用 [DescribeTable](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_DescribeTable.html)DynamoDB 操作来获取有关表的实时、准确的信息。这包括其主键及其本地和全局二级索引。调用方需要具有调用 `DescribeTable` 的权限。  

```
table_info = TableInfo(name=table_name)
table_info.refresh_indexed_attributes(table.meta.client)
```

步骤 4：创建 DynamoDB 加密上下文  
[DynamoDB 加密上下文](concepts.md#encryption-context)包含有关表结构以及其如何加密和签名的信息。此示例明确创建 DynamoDB 密上下文，因为它与项目加密程序交互。[客户端帮助程序类](python-using.md#python-helpers)为您创建 DynamoDB 加密上下文。  
要获取分区键和排序键，可以使用[TableInfo](python-using.md#python-helpers)辅助类的属性。  

```
index_key = {
    'partition_attribute': 'value1',
    'sort_attribute': 55
}

encryption_context = EncryptionContext(
    table_name=table_name,
    partition_key_name=table_info.primary_index.partition,
    sort_key_name=table_info.primary_index.sort,
    attributes=dict_to_ddb(index_key)
)
```

步骤 5：创建属性操作对象  
[属性操作](DDBEC-legacy-concepts.md#legacy-attribute-actions)告知项目加密程序将对项目的每个属性执行哪些操作。此示例中的 `AttributeActions` 对象加密并签名所有项目，除已签名但未加密的主键属性和已被忽略的 `test` 属性以外。  
当您与项目加密程序直接交互且您的默认操作为 `ENCRYPT_AND_SIGN` 时，您必须为主键指定一个替代操作。您可以使用 `set_index_keys` 方法，该方法对主键使用 `SIGN_ONLY`；如果是默认操作，也可以使用 `DO_NOTHING`。  
为了指定主键，此示例使用[TableInfo](python-using.md#python-helpers)对象中的索引键，该索引键通过调用 DynamoDB 来填充。此方法要比硬编码主键名称更加安全。  

```
actions = AttributeActions(
    default_action=CryptoAction.ENCRYPT_AND_SIGN,
    attribute_actions={'test': CryptoAction.DO_NOTHING}
)
actions.set_index_keys(*table_info.protected_index_keys())
```

步骤 6：创建项目的配置  
要配置 DynamoDB 加密客户端，请使用您刚才在表项目的配置中[CryptoConfig](https://aws-dynamodb-encryption-python.readthedocs.io/en/latest/lib/encrypted/config.html)创建的对象。客户端帮助程序类 CryptoConfig 为您创建。  

```
crypto_config = CryptoConfig(
    materials_provider=kms_cmp,
    encryption_context=encryption_context,
    attribute_actions=actions
)
```

步骤 7：加密项目  
此步将加密并签名项目，但不会将项目放入 DynamoDB 表中。  
当您使用客户端帮助程序类时，您的项目会以透明方式加密并签名，然后在您调用帮助程序类的 `put_item` 方法时添加到您的 DynamoDB 表。当您直接使用项目加密程序时，encrypt 和 put 操作是相互独立的。  
首先，创建一个明文项目。  

```
plaintext_item = {
    'partition_attribute': 'value1',
    'sort_key': 55,
    'example': 'data',
    'numbers': 99,
    'binary': Binary(b'\x00\x01\x02'),
    'test': 'test-value'
}
```
然后，对该项目进行加密和签名。`encrypt_python_item` 方法需要 `CryptoConfig` 配置对象。  

```
encrypted_item = encrypt_python_item(plaintext_item, crypto_config)
```

步骤 8：将项目放入表中  
此步会将已加密且签名的项目放入 DynamoDB 表中。  

```
table.put_item(Item=encrypted_item)
```

要查看加密项目，请对原始 `get_item` 对象调用 `table` 方法，而不是对 `encrypted_table` 对象。它会从 DynamoDB 表获取该项目，无需验证和解密它。

```
encrypted_item = table.get_item(Key=partition_key)['Item']
```

下图展示了一个已加密且签名的示例表项目的一部分。

加密属性值为二进制数据。主键属性 (`partition_attribute` 和 `sort_attribute`) 和 `test` 属性的名称和值保持明文形式。输出还显示包含签名 (`*amzn-ddb-map-sig*`) 的属性和[材料描述属性](DDBEC-legacy-concepts.md#legacy-material-description) (`*amzn-ddb-map-desc*`)。

![\[已加密且签名的项目的摘要\]](http://docs.aws.amazon.com/zh_cn/database-encryption-sdk/latest/devguide/images/encrypted-item-closeup.png)


# 更改数据模型
<a name="data-model"></a>

**注意**  
我们的客户端加密库已[重命名为 AWS 数据库加密 SDK](DDBEC-rename.md)。以下主题提供有关适用于 Java 的 DynamoDB 加密客户端版本 1.*x*—2.*x* 以及适用于 Python 的 DynamoDB 加密客户端版本 1.*x*—3.*x* 的信息。有关更多信息，请参阅[适用于 DynamoDB 的AWS 数据库加密 SDK 版本支持](legacy-dynamodb-encryption-client.md#legacy-support)。

每次加密或解密项目时，您需要提供[属性操作](DDBEC-legacy-concepts.md#legacy-attribute-actions)，这些操作告诉 DynamoDB 加密客户端要加密并签名的属性、要签名（但不加密）的属性以及要忽略的属性。属性操作不会保存在加密的项目中，并且 DynamoDB 加密客户端不会自动更新您的属性操作。

**重要**  
DynamoDB 加密客户端不支持对现有的未加密 DynamoDB 表数据进行加密。

每当您更改数据模型时（也即，在表项目中添加或删除属性时），都有可能出错。如果您指定的属性操作未考虑到该项目中的所有属性，则该项目可能不会按您希望的方式进行加密和签名。更重要的是，如果您在解密项目时提供的属性操作与在加密项目时提供的属性操作不同，则签名验证可能会失败。

例如，如果用于加密项目的属性操作告知其签署 `test` 属性，则项目中的签名将包含 `test` 属性。但是，如果用于解密项目的属性操作未考虑到 `test` 属性，则验证会失败，因为客户端将尝试验证与包含 `test` 属性的签名。

当多个应用程序读取和写入相同的 DynamoDB 项目时，这是一个特别的问题，因为 DynamoDB 加密客户端必须为所有应用程序中的项目计算相同的签名。对于任何分布式应用程序来说，这也是一个问题，因为属性操作的更改必须传播到所有主机。即使您的 DynamoDB 表是由一个主机在一个过程中访问的，但如果项目变得更加复杂，则建立最佳实践过程也将有助于防止错误。

为避免签名验证错误阻止您读取表项目，请使用以下指南。
+ [添加属性](#add-attribute) — 如果新的属性更改了属性操作，请在将新属性包括在项目中之前完全部署属性操作更改。
+ [移除属性](#remove-attribute) — 如果您停止在项目中使用属性，请不要更改属性操作。
+ 更改操作 — 使用属性操作配置对表项目进行加密后，如果不重新加密表中的每个项目，就无法安全地更改默认操作或现有属性的操作。

签名验证错误可能很难解决，因此最好的方法是防止它们发生。

**Topics**
+ [添加属性](#add-attribute)
+ [删除属性](#remove-attribute)

## 添加属性
<a name="add-attribute"></a>

在向表项目添加新属性时，可能需要更改属性操作。为了防止签名验证错误，我们建议您分两步实施此更改。在开始第二阶段之前，请验证第一阶段是否已完成。

1. 在读取或写入表的所有应用程序中更改属性操作。部署这些更改并确认更新已传播到所有目标主机。

1. 将值写入表项目中的新属性。

这种两阶段方法可确保所有应用程序和主机具有相同的属性操作，并且在遇到新属性之前将计算相同的签名。即使该属性的操作为*不执行任何操作*（不加密或签名），这也很重要，因为某些加密程序的默认设置是加密和签名。

以下示例显示此过程中第一阶段的代码。它们添加了一个新的项目属性 `link`，该属性存储指向另一个表项目的链接。由于此链接必须保持为纯文本格式，因此该示例向其分配仅签名操作。完全部署此更改，然后验证所有应用程序和主机都具有新的属性操作之后，可以开始在表项目中使用 `link` 属性。

------
#### [ Java DynamoDB Mapper ]

当使用 `DynamoDB Mapper` 和 `AttributeEncryptor` 时，默认情况下，除主键以外的所有属性均加密并签名，而主键已签名但未加密。要指定仅签名操作，请使用 `@DoNotEncrypt` 注释。

本示例将 `@DoNotEncrypt` 注释用于新的 `link` 属性。

```
@DynamoDBTable(tableName = "ExampleTable")
public static final class DataPoJo {
  private String partitionAttribute;
  private int sortAttribute;
  private String link;

  @DynamoDBHashKey(attributeName = "partition_attribute")
  public String getPartitionAttribute() {
    return partitionAttribute;
  }
    
  public void setPartitionAttribute(String partitionAttribute) {
    this.partitionAttribute = partitionAttribute;
  }

  @DynamoDBRangeKey(attributeName = "sort_attribute")
  public int getSortAttribute() {
    return sortAttribute;
  }

  public void setSortAttribute(int sortAttribute) {
    this.sortAttribute = sortAttribute;
  }

  @DynamoDBAttribute(attributeName = "link")
  @DoNotEncrypt
  public String getLink() {
    return link;
  }

  public void setLink(String link) {
    this.link = link;
  }

  @Override
  public String toString() {
    return "DataPoJo [partitionAttribute=" + partitionAttribute + ",
        sortAttribute=" + sortAttribute + ",
        link=" + link + "]";
  }
}
```

------
#### [ Java DynamoDB encryptor ]

 在较低级别的 DynamoDB 加密程序中，必须为每个属性设置操作。本示例使用一个开关语句，其中默认值为 `encryptAndSign`，并为分区键、排序键和新的 `link` 属性指定了例外。在此示例中，如果在使用链接属性代码之前未完全部署它，则链接属性将由某些应用程序加密和签名，而仅由其他应用程序签名。

```
for (final String attributeName : record.keySet()) {
    switch (attributeName) {
        case partitionKeyName:
            // fall through to the next case
        case sortKeyName:
            // partition and sort keys must be signed, but not encrypted
            actions.put(attributeName, signOnly);
            break;
        case "link":
            // only signed
            actions.put(attributeName, signOnly);
            break;
        default:
            // Encrypt and sign all other attributes
            actions.put(attributeName, encryptAndSign);
            break;
    }
}
```

------
#### [ Python ]

在适用于 Python 的 DynamoDB 加密客户端中，您可以为所有属性指定默认操作，然后指定例外。

如果您使用的是 Python [客户端帮助程序类](python-using.md#python-helpers)，则无需指定主键属性的属性操作。该客户端帮助程序类阻止您加密主键。但是，如果不使用客户端帮助程序类，则必须在分区键和排序键上设置 SIGN\$1ONLY 操作。如果您不小心加密了分区键或排序键，那么在没有全表扫描的情况下将无法恢复数据。

本示例为新的 `link` 属性指定一个例外，该例外将获取 `SIGN_ONLY` 操作。

```
actions = AttributeActions(
    default_action=CryptoAction.ENCRYPT_AND_SIGN,
    attribute_actions={
      'example': CryptoAction.DO_NOTHING,  
      'link': CryptoAction.SIGN_ONLY
    }
)
```

------

## 删除属性
<a name="remove-attribute"></a>

如果您在使用 DynamoDB 加密客户端加密的项目中不再需要某个属性，则可以停止使用该属性。但是，请勿删除或更改该属性的操作。如果这样做，然后遇到具有该属性的项目，则为该项目计算的签名将与原始签名不匹配，并且签名验证将失败。

尽管您可能很想从代码中删除该属性的所有痕迹，但请添加一条注释，指出不再使用该项目，而不是删除它。即使您进行全表扫描以删除该属性的所有实例，具有该属性的加密项目也可能会缓存或在配置中的某个地方处于正在进行状态。

# 排查 DynamoDB 加密客户端应用程序中的问题
<a name="troubleshooting"></a>

**注意**  
我们的客户端加密库已[重命名为 AWS 数据库加密 SDK](DDBEC-rename.md)。以下主题提供有关适用于 Java 的 DynamoDB 加密客户端版本 1.*x*—2.*x* 以及适用于 Python 的 DynamoDB 加密客户端版本 1.*x*—3.*x* 的信息。有关更多信息，请参阅[适用于 DynamoDB 的AWS 数据库加密 SDK 版本支持](legacy-dynamodb-encryption-client.md#legacy-support)。

本部分介绍了您在使用 DynamoDB 加密客户端时可能遇到的问题并提供了解决这些问题的建议。

要提供有关 DynamoDB 加密客户端的反馈，请在或存储库中提交问题。[aws-dynamodb-encryption-java[aws-dynamodb-encryption-python](https://github.com/aws/aws-dynamodb-encryption-python/)](https://github.com/aws/aws-dynamodb-encryption-java/) GitHub 

要提供对本文档的反馈，请使用任何页面上的反馈链接。

**Topics**
+ [拒绝访问](#kms-permissions)
+ [签名验证失败](#change-data-model)
+ [旧版本全局表存在的问题](#fix-global-tables)
+ [最新提供程序表现不佳](#mrp-ttl-delay)

## 拒绝访问
<a name="kms-permissions"></a>

**问题**：拒绝您的应用程序访问其所需的资源。

**建议**：了解所需权限并将权限添加到您的应用程序所运行的安全环境。

**详细信息**

要运行使用 DynamoDB 加密客户端库的应用程序，调用方必须具有使用其组件的权限。否则，将会拒绝他们访问必要元素。
+ DynamoDB 加密客户端不需要 Amazon Web Services（AWS）账户，也不依赖任何 AWS 服务。但是，如果您的应用程序使用 AWS，[则](https://aws.amazon.com/premiumsupport/knowledge-center/create-and-activate-aws-account/)需要[有权使用该账户的 AWS 账户和用户](https://docs.aws.amazon.com/IAM/latest/UserGuide/getting-started_create-admin-group.html)。
+ DynamoDB 加密客户端不需要 Amazon DynamoDB。但是，如果使用客户端的应用程序创建 DynamoDB 表、将项目放入表中或从表中获取项目，则调用方必须具有在您的 AWS 账户账户中使用所需 DynamoDB 操作的权限。有关详细信息，请参阅《Amazon DynamoDB 开发人员指南》**中的[访问控制主题](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/access-control-overview.html)。
+ 如果您的应用程序使用适用于 Python 的 DynamoDB 加密[客户端中的客户端帮助程序类](python-using.md#python-helpers)，则调用者必须具有调用 DynamoDB 操作的权限。[DescribeTable](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_DescribeTable.html)
+ DynamoDB 加密客户端不 AWS Key Management Service 需要 ()。AWS KMS但是，如果您的应用程序使用 Di [rect KMS 材料提供程序](direct-kms-provider.md)，或者它使用[的是最新提供程序](most-recent-provider.md)和正在使用的提供程序存储区 AWS KMS，则调用方必须拥有使用 AWS KMS [GenerateDataKey](https://docs.aws.amazon.com/kms/latest/APIReference/API_GenerateDataKey.html)和[解密操作](https://docs.aws.amazon.com/kms/latest/APIReference/API_Decrypt.html)的权限。

## 签名验证失败
<a name="change-data-model"></a>

**问题**：由于签名验证失败，无法解密某个项目。该项目也可能未按您希望的进行加密和签名。

**建议**：确保您提供的属性操作考虑到该项目中的所有属性。当解密某个项目时，请确保提供与用于加密该项目的操作匹配的属性操作。

**详细信息**

您提供的[属性操作](DDBEC-legacy-concepts.md#legacy-attribute-actions)告诉 DynamoDB 加密客户端要加密并签名的属性、要签名（但不加密）的属性以及要忽略的属性。

如果您指定的属性操作未考虑到该项目中的所有属性，则该项目可能不会按您希望的方式进行加密和签名。如果您在解密项目时提供的属性操作与在加密项目时提供的属性操作不同，则签名验证可能会失败。这是分布式应用程序中的特定问题，在分布式应用程序中，新属性操作可能不会传播到所有主机。

签名验证错误很难解决。为了帮助防止此类错误，请在更改数据模型时采取额外的预防措施。有关更多信息，请参阅 [更改数据模型](data-model.md)。

## 旧版本全局表存在的问题
<a name="fix-global-tables"></a>

**问题**：由于签名验证失败，旧版本的 Amazon DynamoDB 全局表中的项目无法解密。

**建议**：设置属性操作，使得保留的复制字段不会被加密或签名。

**详细信息**

您可以将 DynamoDB 加密客户端与 [DynamoDB 全局表](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GlobalTables.html)结合使用。我们建议您使用带有[多区域 KMS 密钥](https://docs.aws.amazon.com/kms/latest/developerguide/multi-region-keys-overview.html)的全局表，并将 KMS 密钥复制到复制全局表的所有 AWS 区域 位置。

从全局表[版本 2019.11.21](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/globaltables.V2.html) 开始，您无需任何特殊配置即可将全局表与 DynamoDB 加密客户端结合使用。但是，如果您使用全局表[版本 2017.11.29](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/globaltables.V1.html)，则必须确保所保留的复制字段不会被加密或签名。

如果您使用全局表版本 2017.11.29，则必须将以下属性的属性操作设置为 [Java](java-using.md#attribute-actions-java) 中的 `DO_NOTHING` 或 [Python](python-using.md#python-attribute-actions) 中的 `@DoNotTouch`。
+ `aws:rep:deleting`
+ `aws:rep:updatetime`
+ `aws:rep:updateregion`

如果您使用任何其他版本的全局表，则无需执行任何操作。

## 最新提供程序表现不佳
<a name="mrp-ttl-delay"></a>

**问题**：您的应用程序响应速度较差，尤其是在更新到较新版本的 DynamoDB 加密客户端之后。

**建议**：调整 time-to-live值和缓存大小。

**详细信息**

最新提供程序旨在通过允许有限地重用加密材料来提高使用 DynamoDB 加密客户端的应用程序的性能。为应用程序配置最新提供程序时，您必须在提高性能与缓存和重用所产生的安全问题之间取得平衡。

在较新版本的 DynamoDB 加密客户端中， time-to-live(TTL) 值决定了缓存的加密材料提供程序 CMPs () 的使用时长。TTL 还决定最新提供程序检查新版本的 CMP 的频率。

如果您的 TTL 过长，则应用程序可能会违反您的业务规则或安全标准。如果 TTL 过短，则频繁调用提供程序存储可能会导致您的提供程序存储限制来自您的应用程序和共享您的服务账户的其他应用程序的请求。要解决此问题，请将 TTL 和缓存大小调整为符合延迟和可用性目标并且符合安全标准的值。有关详细信息，请参阅[设置一个 time-to-live值](most-recent-provider.md#most-recent-provider-ttl)。