

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

# AWS 适用于 DynamoDB 的数据库加密 SDK
<a name="dynamodb-encryption-client"></a>


****  

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

[适用于 DynamoDB 的 AWS 数据库加密软件开发工具包是一个软件库，可让您在 Amazon DynamoDB 设计中加入客户端加密。](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/)适用于 DynamoDB 的 AWS 数据库加密 SDK 提供属性级加密，使您能够指定要加密哪些项目以及要在签名中包含哪些项目，以确保数据的真实性。加密传输中敏感数据和静态敏感数据有助于确保您的明文数据不会提供给任何第三方，包括 AWS。

**注意**  
 AWS 数据库加密 SDK 不支持 PartiQL。

在 DynamoDB 中，[表](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.CoreComponents.html#HowItWorks.CoreComponents.TablesItemsAttributes)是项目的集合。每个*项目* 都是*属性* 的集合。每个属性都有各自的名称和值。适用于 DynamoDB 的 AWS 数据库加密 SDK 对属性的值进行加密。然后，它将通过属性计算签名。您可以指定哪些属性值要加密，哪些属性值要包含在[加密操作](concepts.md#crypt-actions)的签名中。

本章中的主题概述了适用于 DynamoDB 的 AWS 数据库加密 SDK，包括哪些字段已加密、客户端安装和配置指南以及可帮助您入门的 Java 示例。

**Topics**
+ [客户端加密和服务器端加密](client-server-side.md)
+ [哪些域已被加密和签名？](DDB-encrypted-and-signed.md)
+ [DynamoDB 中的可搜索加密](ddb-searchable-encryption.md)
+ [更新您的数据模型](ddb-update-data-model.md)
+ [AWS 适用于 DynamoDB 的数据库加密 SDK 可用编程语言](ddb-programming-languages.md)
+ [旧版 DynamoDB 加密客户端](legacy-dynamodb-encryption-client.md)

# 客户端加密和服务器端加密
<a name="client-server-side"></a>


****  

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

适用于 DynamoDB 的 AWS 数据库加密 SDK *支持客户端*加密，即在将表数据发送到数据库之前对其进行加密。但是，DynamoDB 提供服务器端*静态加密*功能，该功能会在您将表保存到磁盘时以透明方式进行加密并在您访问表时进行解密。

您选择的工具取决于数据的敏感性和应用程序的安全性要求。您可以同时使用适用于 DynamoDB 的 AWS 数据库加密 SDK 和静态加密。当您将已加密且签名的项目发送到 DynamoDB 时，DynamoDB 不会识别受保护的项目。它仅检测带有二进制属性值的典型表项目。

**服务器端静态加密**

DynamoDB 支持[静态加密](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/EncryptionAtRest.html)，这是一项*服务器端加密*功能，利用此功能，DynamoDB 可以在将表保存到磁盘时以透明方式进行加密并且在您访问表时进行解密。

当您使用 AWS SDK 与 DynamoDB 交互时，默认情况下，您的数据在通过 HTTPS 连接传输时会进行加密，在 DynamoDB 终端节点进行解密，然后重新加密，然后再存储在 DynamoDB 中。
+ **默认加密。**DynamoDB 在写入所有表时，以透明方式对其进行加密和解密。没有启用或禁用静态加密的选项。
+ **DynamoDB 创建和管理加密密钥。**每个表的唯一键受 [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）处于不加密状态。默认情况下，DynamoDB 在 DynamoDB 服务账户中使用 [AWS 拥有的密钥](https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#aws-owned-cmk)，但您可以在账户中选择一个 [AWS 托管式密钥](https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#aws-managed-cmk) 或[客户托管密钥](https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#customer-cmk)来保护您的部分或全部表。
+ **所有表数据均已在磁盘上加密。**当加密表保存到磁盘时，DynamoDB 会加密所有表数据，包括[主键](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.CoreComponents.html#HowItWorks.CoreComponents.PrimaryKey)以及本地和全局[二级索引](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.CoreComponents.html#HowItWorks.CoreComponents.SecondaryIndexes)。如果表具有排序键，则标记范围边界的一些排序键将以明文形式存储在表元数据中。
+ **与表相关的对象也被加密。**只要将 [DynamoDB 流](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Streams.html)、[全局表](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GlobalTables.html)和[备份](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/BackupRestore.html)写入到持久性媒体，静态加密就会保护它们。
+ **您的项目在您进行访问时解密。**当您访问表时，DynamoDB 会解密包含目标项目的表的一部分并向您返回明文项目。

**AWS 适用于 DynamoDB 的数据库加密 SDK**

客户端加密为您的数据提供 end-to-end保护，无论是传输中的数据还是静态数据，从 DynamoDB 的源数据到 DynamoDB 中的存储。您的纯文本数据永远不会泄露给任何第三方，包括。 AWS您可以将适用于 DynamoDB 的 AWS 数据库加密软件开发工具包与新的 DynamoDB 表配合使用，也可以将现有的 Amazon DynamoDB 表迁移到最新版本的 DynamoDB 数据库加密软件开发工具包。 AWS 
+ **您的传输中数据和静态数据均受保护。**它永远不会暴露给任何第三方，包括 AWS。
+ **您可以为表项目签名。**您可以定向适用于 DynamoDB 的 AWS 数据库加密 SDK 以计算表项目的全部或部分的签名，包括主键属性。此签名允许您整体检测项目的未经授权的更改，包括添加或删除属性，或者交换属性值。
+ **您可以通过[选择密钥环](keyrings.md)的方式确定如何保护您的数据**。您的密钥环决定了哪些包装密钥保护您的数据密钥并最终保护您的数据。使用最安全且对您的任务实用的包装密钥。
+ **适用于 DynamoDB 的 AWS 数据库加密 SDK 不会加密整个表。**您可以选择在项目中加密哪些属性。适用于 DynamoDB 的 AWS 数据库加密 SDK 不会加密整个项目。它不会加密属性名称或主键（分区键和排序键）属性的名称或值。

**AWS Encryption SDK**

如果您要加密存储在 DynamoDB 中的数据，我们建议使用适用于 DynamoDB 的数据库加密 SD AWS K。

[AWS Encryption SDK](https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/) 是一个客户端加密库，可帮助您加密和解密通用数据。尽管它可以保护任何类型的数据，但它不适用于结构化数据，如数据库记录。与适用于 DynamoDB 的 AWS 数据库加密 SDK 不同，它无法提供项目级别的完整性检查，也没有识别属性或阻止加密 AWS Encryption SDK 主密钥的逻辑。

如果您使用 AWS Encryption SDK 来加密表中的任何元素，请记住它与适用于 DynamoDB 的 AWS 数据库加密 SDK 不兼容。您无法使用一个库进行加密而使用另一个库进行解密。

# 哪些域已被加密和签名？
<a name="DDB-encrypted-and-signed"></a>


****  

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

DynamoDB AWS 数据库加密软件开发工具包是一个专为亚马逊 DynamoDB 应用程序设计的客户端加密库。Amazon DynamoDB 将数据存储在[表](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.CoreComponents.html#HowItWorks.CoreComponents.TablesItemsAttributes)中，表是项目的集合。每个*项目* 都是*属性* 的集合。每个属性都有各自的名称和值。适用于 DynamoDB 的 AWS 数据库加密 SDK 对属性的值进行加密。然后，它将通过属性计算签名。您可以指定哪些属性值要加密，哪些属性值要包含在签名中。

加密可保护属性值的机密性。签名提供了所有已签名属性及其相互关系的完整性，并提供了身份验证。它使您能够整体检测项目的未经授权的更改（包括添加或删除属性），或者用一个加密值替换另一个加密至。

在加密项目中，某些数据保持明文形式，包括表名称、所有属性名称、未加密的属性值、主键（分区键和排序键）属性的名称和值以及属性类型。请勿在这些域中存储敏感数据。

有关适用于 DynamoDB 的 AWS 数据库加密 SDK 的工作原理的更多信息，请参阅。[AWS 数据库加密 SDK 的工作原理](how-it-works.md)

**注意**  
[适用于 DynamoDB 的 AWS 数据库加密 SDK 主题中所有提及*属性操作*的内容均指加密操作。](concepts.md#crypt-actions)

**Topics**
+ [加密属性值](#encrypt-attribute-values)
+ [签署项目](#sign-the-item)

## 加密属性值
<a name="encrypt-attribute-values"></a>

适用于 DynamoDB 的 AWS 数据库加密 SDK 对您指定的属性的值（但不加密属性名称或类型）进行加密。要确定加密的属性值，请使用[属性操作](concepts.md#crypt-actions)。

例如，此项目包含 `example` 和 `test` 属性。

```
'example': 'data',
'test': 'test-value',
...
```

如果您加密了 `example` 属性，但未加密 `test` 属性，结果将类似于以下内容。加密的 `example` 属性值是二进制数据，而不是字符串。

```
'example': Binary(b"'b\x933\x9a+s\xf1\xd6a\xc5\xd5\x1aZ\xed\xd6\xce\xe9X\xf0T\xcb\x9fY\x9f\xf3\xc9C\x83\r\xbb\\"),
'test': 'test-value'
...
```

每个项目的主键属性（分区键和排序键）必须保持明文形式，因为 DynamoDB 使用它们在表中查找项目。应该对它们进行签名而不是加密。

适用于 DynamoDB 的 AWS 数据库加密 SDK 可为您识别主键属性，并确保其值已签名，但未加密。此外，如果您标识了主键，然后尝试对其进行加密，客户端将引发异常。

客户端将[材料描述](concepts.md#material-description)存储在添加到项目的新属性（`aws_dbe_head`）中。材料描述说明了项目是如何加密和签名的。客户端使用此信息来验证和解密项目。存储材料描述的字段没有加密。

## 签署项目
<a name="sign-the-item"></a>

[加密指定属性值后，适用于 DynamoDB 的 AWS 数据库加密 SDK 会计算基于哈希的消息身份验证码 HMACs () 和[数字](concepts.md#digital-sigs)签名，而不是材料描述[、加密上下文以及属性操作中标记、](concepts.md#encryption-context)或的每个字段`ENCRYPT_AND_SIGN`的规范化。`SIGN_ONLY``SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`](concepts.md#crypt-actions)默认情况下，ECDSA 签名处于启用状态，但不是必需的。客户端将 HMACs 和签名存储在添加到项目的新属性 (`aws_dbe_foot`) 中。

# DynamoDB 中的可搜索加密
<a name="ddb-searchable-encryption"></a>

要配置 Amazon DynamoDB 表以进行可搜索的加密，必须使用 [AWS KMS 分层密钥环](use-hierarchical-keyring.md)来生成、加密和解密用于保护项目的数据密钥。您还必须在表加密配置中包含 [`SearchConfig`](ddb-net-using.md#ddb-net-search-config)。

**注意**  
如果您使用适用于 DynamoDB 的 Java 客户端加密库，则必须使用适用于 DynamoDB 的 AWS 低级数据库加密 SDK API 来加密、签名、验证和解密您的表格项目。DynamoDB 增强版客户端和较低级别 `DynamoDBItemEncryptor` 不支持可搜索的加密。

**Topics**
+ [通过使用信标配置二级索引](#ddb-beacon-indexes)
+ [测试信标输出](#ddb-beacon-testing)

## 通过使用信标配置二级索引
<a name="ddb-beacon-indexes"></a>

[配置信标](configure-beacons.md)后，您必须先配置反映每个信标的二级索引，然后才能搜索加密的属性。

配置标准信标或复合信标时， AWS 数据库加密 SDK 会在信标名称中添加`aws_dbe_b_`前缀，以便服务器可以轻松识别信标。例如，如果您将复合信标命名为 `compoundBeacon`，则信标的完整名称实际上为 `aws_dbe_b_compoundBeacon`。如果您要配置包含标准信标或复合信标的[二级索引](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/SecondaryIndexes.html)，则必须在标识信标名称时包含 `aws_dbe_b_` 前缀。

**分区键和排序键**  
您将无法加密主键值。您的分区和排序密钥必须经过签名。您的主键值不能是标准或复合信标。  
除非您指定任何`SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`属性`SIGN_ONLY`，否则您的主键值必须是，分区和排序属性也必须是`SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`。  
您的主键值可以是已签名的信标。如果您为每个主键值配置了不同的签名信标，则必须指定属性名称以将主键值标识为已签名信标名称。但是， AWS 数据库加密 SDK 不会为已签名的信标添加`aws_dbe_b_`前缀。即使您为主键值配置了不同的签名信标，您也只需要在配置二级索引时为主键值指定属性名称。

**本地二级索引**  
[本地二级索引](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/LSI.html)的排序键可以是信标。  
如果您为排序键指定信标，类型必须为 String。如果您为排序键指定标准信标或复合信标，则必须在指定信标名称时包含 `aws_dbe_b_` 前缀。如果您指定签名信标，则请指定不包含任何前缀的信标名称。

**全局二级索引**  
[全局二级索引](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GSI.html)的分区键和排序键都可以是信标。  
如果您为分区键或排序键指定信标，则类型必须为 String。如果您为排序键指定标准信标或复合信标，则必须在指定信标名称时包含 `aws_dbe_b_` 前缀。如果您指定签名信标，则请指定不包含任何前缀的信标名称。

**属性投影**  
[投影](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GSI.html#GSI.Projections)是从表复制到二级索引的属性集。表的分区键和排序键始终投影到索引中；您可以投影其他属性以支持应用程序的查询要求。DynamoDB 为属性投影提供三种不同的选项：`KEYS_ONLY`、`INCLUDE` 和 `ALL`。  
如果使用 INCLUDE 属性投影在信标上进行搜索，则您必须指定构造信标所用的所有属性的名称以及包含 `aws_dbe_b_` 前缀的信标名称。例如，如果通过 `field1`、`field2` 和 `field3` 配置了复合信标 `compoundBeacon`，则必须在投影中指定 `aws_dbe_b_compoundBeacon`、`field1`、`field2` 和 `field3`。  
全局二级索引只能使用投影中显式指定的属性，但本地二级索引可以使用任何属性。

## 测试信标输出
<a name="ddb-beacon-testing"></a>

如果您[配置了复合信标](configure-beacons.md#config-compound-beacons)或使用[虚拟字段](configure-beacons.md#create-virtual-field)构造了信标，我们建议您在填充 DynamoDB 表之前验证这些信标是否产生了预期的输出。

 AWS 数据库加密 SDK 提供的`DynamoDbEncryptionTransforms`服务可帮助您对虚拟场和复合信标输出进行故障排除。

### 测试虚拟字段
<a name="ddb-beacon-testing-virtual-field"></a>

以下代码段创建测试项目，使用 D [ynamoDB 表加密](ddb-java-using.md#ddb-config-encrypt)配置定义`DynamoDbEncryptionTransforms`服务，并演示如何`ResolveAttributes`使用来验证虚拟字段是否产生预期的输出。

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

**查看完整的代码示例**：[VirtualBeaconSearchableEncryptionExample.java](https://github.com/aws/aws-database-encryption-sdk-dynamodb//blob/main/Examples/runtimes/java/DynamoDbEncryption/src/main/java/software/amazon/cryptography/examples/searchableencryption/VirtualBeaconSearchableEncryptionExample.java) 

```
// Create test items
final PutItemRequest itemWithHasTestResultPutRequest = PutItemRequest.builder()
    .tableName(ddbTableName)
    .item(itemWithHasTestResult)
    .build();

final PutItemResponse itemWithHasTestResultPutResponse = ddb.putItem(itemWithHasTestResultPutRequest);

final PutItemRequest itemWithNoHasTestResultPutRequest = PutItemRequest.builder()
    .tableName(ddbTableName)
    .item(itemWithNoHasTestResult)
    .build();
    
final PutItemResponse itemWithNoHasTestResultPutResponse = ddb.putItem(itemWithNoHasTestResultPutRequest);    

// Define the DynamoDbEncryptionTransforms service
final DynamoDbEncryptionTransforms trans = DynamoDbEncryptionTransforms.builder()
    .DynamoDbTablesEncryptionConfig(encryptionConfig).build();

// Verify configuration
final ResolveAttributesInput resolveInput = ResolveAttributesInput.builder()
    .TableName(ddbTableName)
    .Item(itemWithHasTestResult)
    .Version(1)
    .build();
final ResolveAttributesOutput resolveOutput = trans.ResolveAttributes(resolveInput);

// Verify that VirtualFields has the expected value
Map<String, String> vf = new HashMap<>();
vf.put("stateAndHasTestResult", "CAt");
assert resolveOutput.VirtualFields().equals(vf);
```

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

**参见完整的代码示例**：[VirtualBeaconSearchableEncryptionExample.cs。](https://github.com/aws/aws-database-encryption-sdk-dynamodb/tree/main/Examples/runtimes/net/src/searchableencryption/VirtualBeaconSearchableEncryptionExample.cs)

```
 // Create item with hasTestResult=true
var itemWithHasTestResult = new Dictionary<String, AttributeValue>
{
    ["customer_id"] = new AttributeValue("ABC-123"),
    ["create_time"] = new AttributeValue { N = "1681495205" },
    ["state"] = new AttributeValue("CA"),
    ["hasTestResult"] = new AttributeValue { BOOL = true }
};

// Create item with hasTestResult=false
var itemWithNoHasTestResult = new Dictionary<String, AttributeValue>
{
    ["customer_id"] = new AttributeValue("DEF-456"),
    ["create_time"] = new AttributeValue { N = "1681495205" },
    ["state"] = new AttributeValue("CA"),
    ["hasTestResult"] = new AttributeValue { BOOL = false }
};

// Define the DynamoDbEncryptionTransforms service
var trans = new DynamoDbEncryptionTransforms(encryptionConfig);

// Verify configuration
var resolveInput = new ResolveAttributesInput
{
    TableName = ddbTableName,
    Item = itemWithHasTestResult,
    Version = 1
};
var resolveOutput = trans.ResolveAttributes(resolveInput);

// Verify that VirtualFields has the expected value
Debug.Assert(resolveOutput.VirtualFields.Count == 1);
Debug.Assert(resolveOutput.VirtualFields["stateAndHasTestResult"] == "CAt");
```

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

**参见完整的代码示例**：[virtual](https://github.com/aws/aws-database-encryption-sdk-dynamodb/blob/main/releases/rust/db_esdk/examples/searchableencryption/virtual_beacon_searchable_encryption.rs) \$1beacon\$1searchable\$1encryption.rs。

```
// Create item with hasTestResult=true
let item_with_has_test_result = HashMap::from([
    (
        "customer_id".to_string(),
        AttributeValue::S("ABC-123".to_string()),
    ),
    (
        "create_time".to_string(),
        AttributeValue::N("1681495205".to_string()),
    ),
    ("state".to_string(), AttributeValue::S("CA".to_string())),
    ("hasTestResult".to_string(), AttributeValue::Bool(true)),
]);

// Create item with hasTestResult=false
let item_with_no_has_test_result = HashMap::from([
    (
        "customer_id".to_string(),
        AttributeValue::S("DEF-456".to_string()),
    ),
    (
        "create_time".to_string(),
        AttributeValue::N("1681495205".to_string()),
    ),
    ("state".to_string(), AttributeValue::S("CA".to_string())),
    ("hasTestResult".to_string(), AttributeValue::Bool(false)),
]);

// Define the transform service
let trans = transform_client::Client::from_conf(encryption_config.clone())?;

// Verify the configuration 
let resolve_output = trans
    .resolve_attributes()
    .table_name(ddb_table_name)
    .item(item_with_has_test_result.clone())
    .version(1)
    .send()
    .await?;

// Verify that VirtualFields has the expected value
let virtual_fields = resolve_output.virtual_fields.unwrap();
assert_eq!(virtual_fields.len(), 1);
assert_eq!(virtual_fields["stateAndHasTestResult"], "CAt");
```

------

### 测试复合信标
<a name="ddb-beacon-testing-compound-beacon"></a>

以下代码段创建了一个测试项目，使用 D [ynamoDB 表加密](ddb-java-using.md#ddb-config-encrypt)配置定义`DynamoDbEncryptionTransforms`服务，并演示了如何`ResolveAttributes`使用来验证复合信标是否产生了预期的输出。

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

**查看完整的代码示例**：[CompoundBeaconSearchableEncryptionExample.java](https://github.com/aws/aws-database-encryption-sdk-dynamodb//blob/main/Examples/runtimes/java/DynamoDbEncryption/src/main/java/software/amazon/cryptography/examples/searchableencryption/CompoundBeaconSearchableEncryptionExample.java) 

```
// Create an item with both attributes used in the compound beacon.
final HashMap<String, AttributeValue> item = new HashMap<>();
item.put("work_id", AttributeValue.builder().s("9ce39272-8068-4efd-a211-cd162ad65d4c").build());
item.put("inspection_date", AttributeValue.builder().s("2023-06-13").build());
item.put("inspector_id_last4", AttributeValue.builder().s("5678").build());
item.put("unit", AttributeValue.builder().s("011899988199").build());
                            
// Define the DynamoDbEncryptionTransforms service
final DynamoDbEncryptionTransforms trans = DynamoDbEncryptionTransforms.builder()
    .DynamoDbTablesEncryptionConfig(encryptionConfig).build();

// Verify configuration 
final ResolveAttributesInput resolveInput = ResolveAttributesInput.builder()
    .TableName(ddbTableName)
    .Item(item)
    .Version(1)
    .build();

final ResolveAttributesOutput resolveOutput = trans.ResolveAttributes(resolveInput);
                            
// Verify that CompoundBeacons has the expected value   
Map<String, String> cbs = new HashMap<>();
cbs.put("last4UnitCompound", "L-5678.U-011899988199");
assert resolveOutput.CompoundBeacons().equals(cbs);
// Note : the compound beacon actually stored in the table is not "L-5678.U-011899988199"
// but rather something like "L-abc.U-123", as both parts are EncryptedParts
// and therefore the text is replaced by the associated beacon
```

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

**查看完整的代码示例**：[CompoundBeaconSearchableEncryptionExample.cs](https://github.com/aws/aws-database-encryption-sdk-dynamodb/tree/main/Examples/runtimes/net/src/searchableencryption/CompoundBeaconSearchableEncryptionExample.cs)

```
// Create an item with both attributes used in the compound beacon
var item = new Dictionary<String, AttributeValue>
{
    ["work_id"] = new AttributeValue("9ce39272-8068-4efd-a211-cd162ad65d4c"),
    ["inspection_date"] = new AttributeValue("2023-06-13"),
    ["inspector_id_last4"] = new AttributeValue("5678"),
    ["unit"] = new AttributeValue("011899988199")
};                           
                            
// Define the DynamoDbEncryptionTransforms service
var trans = new DynamoDbEncryptionTransforms(encryptionConfig);

// Verify configuration
var resolveInput = new ResolveAttributesInput
{
    TableName = ddbTableName,
    Item = item,
    Version = 1
};
var resolveOutput = trans.ResolveAttributes(resolveInput);                            
                            
// Verify that CompoundBeacons has the expected value 
Debug.Assert(resolveOutput.CompoundBeacons.Count == 1);
Debug.Assert(resolveOutput.CompoundBeacons["last4UnitCompound"] == "L-5678.U-011899988199");
// Note : the compound beacon actually stored in the table is not "L-5678.U-011899988199"
// but rather something like "L-abc.U-123", as both parts are EncryptedParts
// and therefore the text is replaced by the associated beacon
```

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

**查看完整的代码示例：compound\$1beacon\$1searchable\$1encr** y [pt](https://github.com/aws/aws-database-encryption-sdk-dynamodb/blob/main/releases/rust/db_esdk/examples/searchableencryption/compound_beacon_searchable_encryption.rs) ion.rs

```
// Create an item with both attributes used in the compound beacon
let item = HashMap::from([
    (
        "work_id".to_string(),
        AttributeValue::S("9ce39272-8068-4efd-a211-cd162ad65d4c".to_string()),
    ),
    (
        "inspection_date".to_string(),
        AttributeValue::S("2023-06-13".to_string()),
    ),
    (
        "inspector_id_last4".to_string(),
        AttributeValue::S("5678".to_string()),
    ),
    (
        "unit".to_string(),
        AttributeValue::S("011899988199".to_string()),
    ),
]);                           
                            
// Define the transforms service
let trans = transform_client::Client::from_conf(encryption_config.clone())?;

// Verify configuration
let resolve_output = trans
    .resolve_attributes()
    .table_name(ddb_table_name)
    .item(item.clone())
    .version(1)
    .send()
    .await?;                            
                            
// Verify that CompoundBeacons has the expected value 
let compound_beacons = resolve_output.compound_beacons.unwrap();
assert_eq!(compound_beacons.len(), 1);
assert_eq!(
    compound_beacons["last4UnitCompound"],
    "L-5678.U-011899988199"
);
// but rather something like "L-abc.U-123", as both parts are EncryptedParts
// and therefore the text is replaced by the associated beacon
```

------

# 更新您的数据模型
<a name="ddb-update-data-model"></a>


****  

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

[在为 DynamoDB 配置 AWS 数据库加密 SDK 时，您需要提供属性操作。](concepts.md#crypt-actions)在加密时，D AWS atabase Encryption SDK 使用属性操作来识别哪些属性需要加密和签名，哪些属性需要签名（但不加密），哪些要忽略。您还可以定义[允许的未签名属性](ddb-java-using.md#allowed-unauth)以明确告诉客户端哪些属性被排除在签名之外。解密时， AWS 数据库加密 SDK 使用您定义的允许的未签名属性来识别签名中未包含哪些属性。属性操作不会保存在加密项目中， AWS 数据库加密 SDK 也不会自动更新您的属性操作。

仔细选择属性操作。如有怀疑，请使用 **Encrypt and sign (加密和签名)**。使用 AWS 数据库加密 SDK 保护您的项目后，您无法将现有`ENCRYPT_AND_SIGN``SIGN_ONLY`、或`SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`属性更改为`DO_NOTHING`。但是，您可以安全地进行以下更改。
+ [添加新`ENCRYPT_AND_SIGN`的`SIGN_ONLY`、和`SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`属性](#ddb-add-auth-attribute)
+ [移除现有属性](#ddb-remove-attribute)
+ [将现有`ENCRYPT_AND_SIGN`属性更改为`SIGN_ONLY`或 `SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`](#ddb-encrypt-to-sign)
+ [将现有`SIGN_ONLY`或`SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`属性更改为 `ENCRYPT_AND_SIGN`](#ddb-sign-to-encrypt)
+ [添加新的 `DO_NOTHING` 属性](#ddb-add-unauth-attribute)
+ [将现有的 `SIGN_ONLY` 属性更改为 `SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`](#ddb-signOnly-to-signInclude)
+ [将现有的 `SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT` 属性更改为 `SIGN_ONLY`](#ddb-signInclude-to-signOnly)

**可搜索加密的注意事项**  
在您更新数据模型之前，请仔细考虑您的更新会如何影响您通过这些属性构造的任何[信标](beacons.md)。使用信标写入新记录后，您将无法更新信标的配置。您将无法更新与用于构造信标的属性相关联的属性操作。如果您移除现有属性及其关联信标，则将无法使用该信标来查询现有记录。您可以为添加到记录中的新字段创建新信标，但不能通过更新现有信标来包含新字段。

**`SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`属性的注意事项**  
默认情况下，分区和排序密钥是加密上下文中唯一包含的属性。您可以考虑定义其他字段，`SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`以便分[AWS KMS 层密钥环](use-hierarchical-keyring.md)的分支密钥 ID 提供者可以识别从加密上下文中解密需要哪个分支密钥。有关更多信息，请参阅[分支密钥 ID 供应商](use-hierarchical-keyring.md#branch-key-id-supplier)。如果您指定了任何`SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`属性，则分区和排序属性也必须是`SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`。

**注意**  
要使用`SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`加密操作，必须使用 AWS 数据库加密 SDK 的 3.3 或更高版本。在[更新要包含的数据模型之前，先将](#ddb-update-data-model)新版本部署给所有读者`SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`。

## 添加新`ENCRYPT_AND_SIGN`的`SIGN_ONLY`、和`SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`属性
<a name="ddb-add-auth-attribute"></a>

要添加新的`ENCRYPT_AND_SIGN``SIGN_ONLY`、或`SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`属性，请在属性操作中定义新属性。

您不能移除现有`DO_NOTHING`属性并将其作为`ENCRYPT_AND_SIGN``SIGN_ONLY`、或`SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`属性重新添加。

**使用带注释的数据类**  
如果您使用 `TableSchema` 定义了属性操作，则请将新的属性添加到带注释的数据类中。如果您没有为新属性指定属性操作注释，则默认情况下，客户端将对新属性进行加密和签名（除非该属性是主键的一部分）。如果您只想对新属性进行签名，则必须使用`@DynamoDBEncryptionSignOnly`或`@DynamoDBEncryptionSignAndIncludeInEncryptionContext`注释添加新属性。

**使用对象模型**  
如果您手动定义了属性操作，请将新属性添加到对象模型中的属性操作中，并指定`ENCRYPT_AND_SIGN``SIGN_ONLY`、或`SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`作为属性操作。

## 移除现有属性
<a name="ddb-remove-attribute"></a>

如果您决定不再需要某个属性，则可以停止向该属性写入数据，或者将其正式从属性操作中移除。当您停止向某个属性写入新数据时，该属性仍会显示在您的属性操作中。如果您将来需要重新开始使用该属性，则此操作可能会帮到您。正式从属性操作中移除属性并不能将其从数据集中移除。您的数据集仍将包含具有该属性的项目。

要正式移除现有`ENCRYPT_AND_SIGN``SIGN_ONLY``SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`、或`DO_NOTHING`属性，请更新您的属性操作。

如果您移除某个 `DO_NOTHING` 属性，不得将该属性从[允许的未签名属性](ddb-java-using.md#allowed-unauth)中移除。即使您不再向该属性写入新值，客户端仍需要知道该属性未签名，以读取包含该属性的现有项目。

**使用带注释的数据类**  
如果您使用 `TableSchema` 定义了属性操作，请将从带注释的数据类中移除属性。

**使用对象模型**  
如果您手动定义了属性操作，请从对象模型中的属性操作中移除属性。

## 将现有`ENCRYPT_AND_SIGN`属性更改为`SIGN_ONLY`或 `SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`
<a name="ddb-encrypt-to-sign"></a>

要将现有`ENCRYPT_AND_SIGN`属性更改为`SIGN_ONLY`或`SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`，必须更新属性操作。部署更新后，客户端将能够验证和解密写入属性的现有值，但却只能对写入该属性的新值进行签名。

**注意**  
在将现有`ENCRYPT_AND_SIGN`属性更改为`SIGN_ONLY`或之前，请仔细考虑您的安全要求`SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`。任何可以存储敏感数据的属性都应加密。

**使用带注释的数据类**  
如果您使用定义了属性操作`TableSchema`，请更新现有属性，以便在带`@DynamoDBEncryptionSignAndIncludeInEncryptionContext`注释的数据类中包含`@DynamoDBEncryptionSignOnly`或注释。

**使用对象模型**  
如果您手动定义了属性操作，请将与现有属性关联的属性操作从对象模型更新`ENCRYPT_AND_SIGN`为`SIGN_ONLY`或`SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`在对象模型中。

## 将现有`SIGN_ONLY`或`SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`属性更改为 `ENCRYPT_AND_SIGN`
<a name="ddb-sign-to-encrypt"></a>

要将现有`SIGN_ONLY`或`SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`属性更改为`ENCRYPT_AND_SIGN`，必须更新您的属性操作。部署更新后，客户端将能够验证写入属性的现有值，并且能够对写入该属性的新值进行加密和签名。

**使用带注释的数据类**  
如果您使用定义了属性操作`TableSchema`，请从现有属性中移除`@DynamoDBEncryptionSignOnly`或`@DynamoDBEncryptionSignAndIncludeInEncryptionContext`注释。

**使用对象模型**  
如果您手动定义了属性操作，请在对象模型`ENCRYPT_AND_SIGN`中将与该属性关联的属性操作从`SIGN_ONLY`或`SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`更新为。

## 添加新的 `DO_NOTHING` 属性
<a name="ddb-add-unauth-attribute"></a>

为了降低添加新 `DO_NOTHING` 属性时发生错误的风险，建议您在命名 `DO_NOTHING` 属性时指定一个不同的前缀，然后使用该前缀来定义[允许的未签名属性](ddb-java-using.md#allowed-unauth)。

您不能从带注释的数据类中移除现有`ENCRYPT_AND_SIGN``SIGN_ONLY`、或`SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`属性，然后再将该属性作为属性重新添加。`DO_NOTHING`您只能添加全新的 `DO_NOTHING` 属性。

添加新的 `DO_NOTHING` 属性的步骤取决于您是在列表中明确定义允许的未签名属性还是使用前缀对其进行定义。

**使用允许的未签名属性前缀**  
如果您使用 `TableSchema` 定义了属性操作，请使用 `@DynamoDBEncryptionDoNothing` 注释将新的 `DO_NOTHING` 属性添加到带注释的数据类中。如果您手动定义了属性操作，请更新您的属性操作，以包含新属性。请务必使用 `DO_NOTHING` 属性操作显式配置新属性。在新属性的名称中必须包含相同的独特前缀。

**使用允许的未签名属性列表**

1. 将新的 `DO_NOTHING` 属性添加到允许的未签名属性列表中，并部署更新的列表。

1. 部署**步骤 1** 的更改。

   在更改传播有需要读取此数据的所有主机之前，您无法继续执行**步骤 3**。

1. 将新的 `DO_NOTHING` 属性添加到您的属性操作中。

   1. 如果您使用 `TableSchema` 定义了属性操作，请使用 `@DynamoDBEncryptionDoNothing` 注释将新的 `DO_NOTHING` 属性添加到带注释的数据类中。

   1. 如果您手动定义了属性操作，请更新您的属性操作，以包含新属性。请务必使用 `DO_NOTHING` 属性操作显式配置新属性。

1. 部署**步骤 3** 的更改。

## 将现有的 `SIGN_ONLY` 属性更改为 `SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`
<a name="ddb-signOnly-to-signInclude"></a>

要将现有的 `SIGN_ONLY` 属性更改为 `SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`，您必须更新属性操作。部署更新后，客户端将能够验证写入属性的现有值，并将继续对写入该属性的新值进行签名。写入该属性的新值将包含在[加密上下文](concepts.md#encryption-context)中。

如果您指定了任何`SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`属性，则分区和排序属性也必须是`SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`。

**使用带注释的数据类**  
如果您使用定义了属性操作`TableSchema`，请将与该属性关联的属性操作从更新`@DynamoDBEncryptionSignOnly`为`@DynamoDBEncryptionSignAndIncludeInEncryptionContext`。

**使用对象模型**  
如果您手动定义了属性操作，请在对象模型中将与属性关联的属性操作从 `SIGN_ONLY` 更新为 `SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`。

## 将现有的 `SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT` 属性更改为 `SIGN_ONLY`
<a name="ddb-signInclude-to-signOnly"></a>

要将现有的 `SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT` 属性更改为 `SIGN_ONLY`，您必须更新属性操作。部署更新后，客户端将能够验证写入属性的现有值，并将继续对写入该属性的新值进行签名。写入该属性的新值将不会包含在[加密上下文](concepts.md#encryption-context)中。

在将现有`SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`属性更改为之前`SIGN_ONLY`，请仔细考虑您的更新会如何影响[分支密钥 ID 供应商](use-hierarchical-keyring.md#branch-key-id-supplier)的功能。

**使用带注释的数据类**  
如果您使用定义了属性操作`TableSchema`，请将与该属性关联的属性操作从更新`@DynamoDBEncryptionSignAndIncludeInEncryptionContext`为`@DynamoDBEncryptionSignOnly`。

**使用对象模型**  
如果您手动定义了属性操作，请在对象模型中将与属性关联的属性操作从 `SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT` 更新为 `SIGN_ONLY`。

# AWS 适用于 DynamoDB 的数据库加密 SDK 可用编程语言
<a name="ddb-programming-languages"></a>

适用于 DynamoDB 的 AWS 数据库加密 SDK 适用于以下编程语言。特定于语言的库各不相同，但生成的实现是可互操作的。您可以使用一种语言实施进行加密，并使用另一种语言实施进行解密。互操作性可能受到语言约束的限制。如果是这样，这些约束将在有关语言实施的主题中进行描述。

**Topics**
+ [Java](ddb-java.md)
+ [.NET](ddb-net.md)
+ [Rust](ddb-rust.md)

# Java
<a name="ddb-java"></a>


****  

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

本主题说明如何安装并使用适用于 DynamoDB 的 Java 客户端加密库的版本 3.*x*。有关使用适用于 DynamoDB 的 AWS 数据库加密 SDK 进行编程的详细信息，请参阅上的-dynamodb 存储库[中的 Java](https://github.com/aws/aws-database-encryption-sdk-dynamodb//tree/main/Examples/runtimes/java/DynamoDbEncryption/src/main/java/software/amazon/cryptography/examples) 示例。 aws-database-encryption-sdk GitHub

**注意**  
以下主题重点侧重于适用于 DynamoDB 的 Java 客户端加密库的版本 3.*x*。  
我们的客户端加密库已[重命名为 AWS 数据库加密 SDK](DDBEC-rename.md)。 AWS 数据库加密 SDK 继续支持[旧版 DynamoDB](legacy-dynamodb-encryption-client.md) 加密客户端版本。

**Topics**
+ [先决条件](#ddb-java-prerequisites)
+ [安装](#ddb-java-installation)
+ [使用 Java 客户端](ddb-java-using.md)
+ [Java 示例](ddb-java-examples.md)
+ [将版本 3.x 添加到现有表](ddb-java-config-existing-table.md)
+ [迁移到版本 3.x](ddb-java-migrate.md)

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

在安装适用于 DynamoDB 的 Java 客户端加密库的版本 3.*x* 之前，请确保满足以下先决条件。

**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)。

**AWS SDK for Java 2.x**  
适用于 DynamoDB 的 AWS 数据库加密 SDK 需要的 Dy [namoDB 增强型客户端模块](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/dynamodb-enhanced-client.html)。 AWS SDK for Java 2.x可以安装整个开发工具包或仅安装此模块。  
有关更新版本的信息 适用于 Java 的 AWS SDK，请参阅[从 1.x 版迁移到 2.x 版。 适用于 Java 的 AWS SDK](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/migration.html)  
可通过 Apache Maven 获得。 适用于 Java 的 AWS SDK 你可以声明整个模块的依赖关系 适用于 Java 的 AWS SDK，也可以只声明`dynamodb-enhanced`模块的依赖关系。  

**适用于 Java 的 AWS SDK 使用 Apache Maven 安装**
+ 要[导入整个 适用于 Java 的 AWS SDK](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/setup-project-maven.html#build-the-entire-sdk-into-your-project)以作为依赖项，请在 `pom.xml` 文件中对其进行声明。
+ 要仅为 适用于 Java 的 AWS SDK中的 Amazon DynamoDB 模块创建依赖项，请按照[指定特定模块](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/setup-project-maven.html#modules-dependencies)的说明进行操作。将 `groupId` 设置为 `software.amazon.awssdk`，并将 `artifactID` 设置为 `dynamodb-enhanced`。
**注意**  
如果您使用 AWS KMS 密钥环或 AWS KMS 分层密钥环，则还需要为模块创建依赖关系。 AWS KMS 将 `groupId` 设置为 `software.amazon.awssdk`，并将 `artifactID` 设置为 `kms`。

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

您可以按以下方式安装适用于 DynamoDB 的 Java 客户端加密库的版本 3.*x*。

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

```
<dependency>
  <groupId>software.amazon.cryptography</groupId>
  <artifactId>aws-database-encryption-sdk-dynamodb</artifactId>
  <version>version-number</version>
</dependency>
```

**使用 Gradle Kotlin**  
通过将以下内容添加到 Gradle 项目的*依赖项*部分，您可以使用 [Gradle](https://gradle.org/) 在适用于 Java 的 Amazon DynamoDB Encryption Client 上声明依赖项。  

```
implementation("software.amazon.cryptography:aws-database-encryption-sdk-dynamodb:version-number")
```

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

安装 SDK 后，请先查看本指南中的示例代码和上的 aws-database-encryption-sdk-dynamodb [存储库中的 Java 示例](https://github.com/aws/aws-database-encryption-sdk-dynamodb//tree/main/Examples/runtimes/java/DynamoDbEncryption/src/main/java/software/amazon/cryptography/examples)。 GitHub

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


****  

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

本主题介绍了适用于 DynamoDB 的 Java 客户端加密库的版本 3.*x* 中的的一些函数和帮助程序类。

有关使用适用于 DynamoDB 的 Java 客户端加密库进行编程的详细信息，请参阅 [J](java-examples.md) ava 示例、-dynamodb 存储库[中的 Java](https://github.com/aws/aws-database-encryption-sdk-dynamodb//tree/main/Examples/runtimes/java/DynamoDbEncryption/src/main/java/software/amazon/cryptography/examples) 示例。 aws-database-encryption-sdk GitHub

**Topics**
+ [项目加密程序](#ddb-item-encryptors)
+ [属性操作](#ddb-attribute-actions)
+ [加密配置](#ddb-config-encrypt)
+ [更新项目](#ddb-update-items)
+ [解密签名集](#ddb-java-signed-sets)

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

DynamoDB AWS 数据库加密 SDK 的核心是一个项目加密器。您可以使用适用于 DynamoDB 的 Java 客户端加密库的版本 3.*x*，以通过以下方式对您的 DynamoDB 表项目进行加密、签名、验证和解密。

**DynamoDB 增强版客户端**  
您可以使用 `DynamoDbEncryptionInterceptor` 配置 [DynamoDB 增强版客户端](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/dynamodb-enhanced-client.html)，以通过 DynamoDB `PutItem` 请求在客户端自动对项目进行加密和签名。使用 DynamoDB 增强型客户端，您可以使用[带注释的数据类](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/ddb-en-client-gs-tableschema.html#ddb-en-client-gs-tableschema-anno-bean)来定义属性操作。建议尽量使用 DynamoDB 增强型客户端。  
DynamoDB 增强版客户端不支持[可搜索的加密](searchable-encryption.md)。  
 AWS 数据库加密 SDK 不支持对[嵌套属性](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/ddb-en-client-adv-features-nested.html)进行标注。

**低级 DynamoDB API**  
您可以使用 `DynamoDbEncryptionInterceptor` 配置[低级 DynamoDB API](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Programming.LowLevelAPI.html)，以通过 DynamoDB `PutItem` 请求在客户端自动对项目进行加密和签名。  
您必须通过使用低级 DynamoDB API 来使用[可搜索加密](searchable-encryption.md)。

**较低级别的 `DynamoDbItemEncryptor`**  
较低级别的 `DynamoDbItemEncryptor` 无需调用 DynamoDB 即可直接对您的表项目进行加密、签名或解密和验证。它不会发出 DynamoDB `PutItem` 或 `GetItem` 请求。举例来说，您可以使用较低级别的 `DynamoDbItemEncryptor` 直接解密和验证已经检索到的 DynamoDB 项目。  
较低级别的 `DynamoDbItemEncryptor` 不支持[可搜索加密](searchable-encryption.md)。

## 适用于 DynamoDB 的 AWS 数据库加密 SDK 中的属性操作
<a name="ddb-attribute-actions"></a>

[属性操作](concepts.md#crypt-actions)决定哪些属性值经过加密和签名，哪些仅经过签名，哪些经过签名并包含在加密上下文中，哪些会被忽略。

**注意**  
要使用`SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`加密操作，必须使用 AWS 数据库加密 SDK 的 3.3 或更高版本。在[更新要包含的数据模型之前，先将](ddb-update-data-model.md)新版本部署给所有读者`SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`。

如果您使用低级 DynamoDB API 或较低级别的 `DynamoDbItemEncryptor`，则必须手动定义属性操作。如果您使用 DynamoDB 增强型客户端，则可以手动定义属性操作，也可以使用带注释的数据类来[生成一个 `TableSchema`](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/ddb-en-client-gs-tableschema.html)。为了简化配置过程，建议使用带注释的数据类。使用带注释的数据类时，您只需要对对象建模一次。

**注意**  
定义属性操作后，必须定义将哪些属性排除在签名之外。为了将来更方便添加新的未签名属性，建议您选择一个不同的前缀（例如“`:`”）来标识您的未签名属性。在定义 DynamoDB 架构和属性操作时，将此前缀包含在标记为 `DO_NOTHING` 的所有属性的属性名称中。

### 使用带注释的数据类
<a name="ddb-attribute-actions-annotated-data-class"></a>

使用[带注释的数据类](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/ddb-en-client-gs-tableschema.html#ddb-en-client-gs-tableschema-anno-bean)通过 DynamoDB 增强版客户端和 `DynamoDbEncryptionInterceptor` 指定您的属性操作。适用于 DynamoDB 的 AWS 数据库加密 SDK 使用[标准的 DynamoDB 属性注释](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/mapper/annotations/package-summary.html)，该注释可定义属性类型以确定如何保护属性。默认情况下，除主键以外的所有属性均加密并签名，主键已签名但未加密。

**注意**  
要使用`SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`加密操作，必须使用 AWS 数据库加密 SDK 的 3.3 或更高版本。在[更新要包含的数据模型之前，先将](ddb-update-data-model.md)新版本部署给所有读者`SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`。

有关 aws-database-encryption-sdk DynamoDB 增强型客户端注释的更多指导，请参阅上 GitHub 的-dynamodb 存储库中的 [SimpleClass.java](https://github.com/aws/aws-database-encryption-sdk-dynamodb//blob/main/Examples/runtimes/java/DynamoDbEncryption/src/main/java/software/amazon/cryptography/examples/enhanced/SimpleClass.java)。

默认情况下，主键属性已签名但未加密（`SIGN_ONLY`），而所有其他属性均经过加密和签名（`ENCRYPT_AND_SIGN`）。如果将任何属性定义为`SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`，则分区和排序属性也必须是`SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`。要指定例外情况，请使用在适用于 DynamoDB 的 Java 客户端加密库中定义的加密注释。例如，如果您只想对某个特定属性进行签名，请使用 `@DynamoDbEncryptionSignOnly` 注释。如果要对特定属性进行签名并将其包含在加密上下文中，请使用`@DynamoDbEncryptionSignAndIncludeInEncryptionContext`。如果对特定属性既不要签名也不要加密（`DO_NOTHING`），请使用 `@DynamoDbEncryptionDoNothing` 注释。

**注意**  
 AWS 数据库加密 SDK 不支持对[嵌套属性](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/ddb-en-client-adv-features-nested.html)进行标注。

以下示例显示了用于定义`ENCRYPT_AND_SIGN``SIGN_ONLY`、和`DO_NOTHING`属性操作的注释。有关显示用于定义的注释的示例`SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`，请参阅 [SimpleClass4.java](https://github.com/aws/aws-database-encryption-sdk-dynamodb//blob/main/Examples/runtimes/java/DynamoDbEncryption/src/main/java/software/amazon/cryptography/examples/enhanced/SimpleClass4.java)。

```
@DynamoDbBean
public class SimpleClass {

    private String partitionKey;
    private int sortKey;
    private String attribute1;
    private String attribute2;
    private String attribute3;

    @DynamoDbPartitionKey
    @DynamoDbAttribute(value = "partition_key")
    public String getPartitionKey() {
        return this.partitionKey;
    }

    public void setPartitionKey(String partitionKey) {
        this.partitionKey = partitionKey;
    }

    @DynamoDbSortKey
    @DynamoDbAttribute(value = "sort_key")
    public int getSortKey() {
        return this.sortKey;
    }

    public void setSortKey(int sortKey) {
        this.sortKey = sortKey;
    }

    public String getAttribute1() {
        return this.attribute1;
    }

    public void setAttribute1(String attribute1) {
        this.attribute1 = attribute1;
    }

    @DynamoDbEncryptionSignOnly
    public String getAttribute2() {
        return this.attribute2;
    }

    public void setAttribute2(String attribute2) {
        this.attribute2 = attribute2;
    }

    @DynamoDbEncryptionDoNothing
    public String getAttribute3() {
        return this.attribute3;
    }

    @DynamoDbAttribute(value = ":attribute3")
    public void setAttribute3(String attribute3) {
        this.attribute3 = attribute3;
    }
    
}
```

使用带注释的数据类创建 `TableSchema`，如下面的代码段所示。

```
final TableSchema<SimpleClass> tableSchema = TableSchema.fromBean(SimpleClass.class);
```

### 手动定义您的属性操作
<a name="ddb-attribute-actions-manual"></a>

要手动指定属性操作，请创建一个 `Map` 对象，在该对象中，名称/值对表示属性名称和指定的操作。

指定 `ENCRYPT_AND_SIGN` 以对属性进行加密和签名。指定 `SIGN_ONLY` 以对属性进行签名，但不进行加密。指定`SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`对属性进行签名并将其包含在加密上下文中。如果不对属性进行签名，也将无法对其进行加密。指定 `DO_NOTHING` 以忽略某个属性。

分区和排序属性必须为`SIGN_ONLY`或`SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`。如果将任何属性定义为`SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`，则分区和排序属性也必须是`SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`。

**注意**  
要使用`SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`加密操作，必须使用 AWS 数据库加密 SDK 的 3.3 或更高版本。在[更新要包含的数据模型之前，先将](ddb-update-data-model.md)新版本部署给所有读者`SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`。

```
final Map<String, CryptoAction> attributeActionsOnEncrypt = new HashMap<>();
// The partition attribute must be signed
attributeActionsOnEncrypt.put("partition_key", CryptoAction.SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT); 
// The sort attribute must be signed
attributeActionsOnEncrypt.put("sort_key", CryptoAction.SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT); 
attributeActionsOnEncrypt.put("attribute1", CryptoAction.ENCRYPT_AND_SIGN);
attributeActionsOnEncrypt.put("attribute2", CryptoAction.SIGN_ONLY);
attributeActionsOnEncrypt.put("attribute3", CryptoAction.SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT);
attributeActionsOnEncrypt.put(":attribute4", CryptoAction.DO_NOTHING);
```

## 适用于 DynamoDB 的 AWS 数据库加密 SDK 中的加密配置
<a name="ddb-config-encrypt"></a>

使用 AWS 数据库加密 SDK 时，必须为 DynamoDB 表显式定义加密配置。加密配置中所需的值取决于您是手动定义属性操作还是使用带注释的数据类来进行定义。

以下代码段使用 DynamoDB 增强版客户端、[https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/ddb-en-client-gs-tableschema.html](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/ddb-en-client-gs-tableschema.html) 以及不同前缀定义的允许的未签名属性来定义 DynamoDB 表加密配置。

```
final Map<String, DynamoDbEnhancedTableEncryptionConfig> tableConfigs = new HashMap<>();
tableConfigs.put(ddbTableName,
        DynamoDbEnhancedTableEncryptionConfig.builder()
            .logicalTableName(ddbTableName)
            .keyring(kmsKeyring)
            .allowedUnsignedAttributePrefix(unsignedAttrPrefix)
            .schemaOnEncrypt(tableSchema)
            // Optional: only required if you use beacons
            .search(SearchConfig.builder() 
                    .writeVersion(1) // MUST be 1
                    .versions(beaconVersions)
                    .build())         
            .build());
```

**逻辑表名**  
适用于您的 DynamoDB 表的逻辑表名称。  
为简化 DynamoDB 还原操作，逻辑表名称以加密方式绑定到表中存储的所有数据。强烈建议您在首次定义加密配置时将 DynamoDB 表名指定为逻辑表名。必须始终指定相同的逻辑表名。要成功解密，逻辑表名称必须与加密时所指定的名称相匹配。如果您的 DynamoDB 表名称在[从备份中恢复 DynamoDB 表](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Restore.Tutorial.html)后发生更改，则逻辑表名称可确保解密操作仍能识别该表。

**允许的未签名属性**  
在您的属性操作中标记为 `DO_NOTHING` 的属性。  
允许的未签名属性将告诉客户端哪些属性被排除在签名之外。客户端假设，所有的其他属性都包含在签名中。然后，在解密记录时，客户端会从您指定的允许的未签名属性中确定需要验证哪些属性以及需要忽略哪些属性。您将不能从允许的未签名属性中移除属性。  
您可以通过创建一个列出所有 `DO_NOTHING` 属性的数组来显式定义允许的未签名属性。您还可以在命名 `DO_NOTHING` 属性时指定不同的前缀，并使用前缀告诉客户端哪些属性未签名。强烈建议指定一个不同的前缀，因为它可以简化未来添加新的 `DO_NOTHING` 属性的过程。有关更多信息，请参阅 [更新您的数据模型](ddb-update-data-model.md)。  
如果您没有为所有 `DO_NOTHING` 属性指定前缀，可以配置一个 `allowedUnsignedAttributes` 数组，该数组将显式列出客户端在解密时遇到这些属性时应该取消签名的所有属性。您只有在绝对必要时，才应显式定义允许的未签名属性。

**搜索配置（可选）**  
`SearchConfig` 将定义[信标版本](using-beacons.md#beacon-version)。  
必须指定 `SearchConfig` 才能使用[可搜索的加密](searchable-encryption.md)或[签名信标](configure.md#signed-beacons)。

**算法套件（可选）**  
`algorithmSuiteId` 定义 AWS 数据库加密 SDK 使用哪种算法套件。  
除非您明确指定替代算法套件，否则 AWS 数据库加密 SDK 将使用[默认算法套件](supported-algorithms.md#recommended-algorithms)。默认算法套件将 AES-GCM 算法与密钥派生、[数字签名](concepts.md#digital-sigs)和[密钥承诺](concepts.md#key-commitment)结合使用。尽管默认算法套件可能适用于大多数应用程序，但您可以选择备用算法套件。例如，没有数字签名的算法套件可以满足某些信任模型的需求。有关 AWS 数据库加密 SDK 支持的算法套件的信息，请参阅[AWS 数据库加密 SDK 中支持的算法套件](supported-algorithms.md)。  
要选择[没有 ECDSA 数字签名的 AES-GCM 算法套件](supported-algorithms.md#other-algorithms)，请在表加密配置中加入以下片段。  

```
.algorithmSuiteId(
    DBEAlgorithmSuiteId.ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEY_SYMSIG_HMAC_SHA384)
```

## 使用 AWS 数据库加密 SDK 更新项目
<a name="ddb-update-items"></a>

UpdateItem对于已加密或签名的项目，[数据库加密 SDK 不支持 ddb:](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_UpdateItem.html)。 AWS 要更新加密或签名的项目，必须使用 [ddb: PutItem](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_PutItem.html)。如果将同一个主键指定为 `PutItem` 请求中现有的项目，则新项目将完全替代现有项目。更新项目后，您还可以使用 [CLOBBER](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/dynamodbv2/datamodeling/DynamoDBMapperConfig.SaveBehavior.html#CLOBBER) 在保存时清除和替换所有属性。

## 解密签名集
<a name="ddb-java-signed-sets"></a>

在 AWS 数据库加密 SDK 的 3.0.0 和 3.1.0 版本中，如果您[将集合类型](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.NamingRulesDataTypes.html#HowItWorks.DataTypes.SetTypes)属性定义为`SIGN_ONLY`，则该集的值将按照提供的顺序进行规范化。DynamoDB 不保留集合的顺序。因此，包含该集合的项目的签名验证可能会失败。如果集合值的返回顺序与提供给 AWS 数据库加密 SDK 的顺序不同，即使集合的属性包含相同的值，签名验证也会失败。

**注意**  
 AWS 数据库加密 SDK 3.1.1 及更高版本对所有集合类型属性的值进行规范化，因此读取值的顺序与写入 DynamoDB 的顺序相同。

如果签名验证失败，则解密操作将失败并返回以下错误消息。


|  | 
| --- |
| software.amazon.cryptography.dbencryptionsdk.struc StructuredEncryptionException: 没有匹配的收件人标签。 | 

如果您收到上述错误消息，并且认为要解密的项目包含使用版本 3.0.0 或 3.1.0 签名的集合，请查看-dy aws-database-encryption-sdk namodb-java 存储库的[DecryptWithPermute](https://github.com/aws/aws-database-encryption-sdk-dynamodb-java/tree/v3.1.1/DecryptWithPermute)目录，了解如何成功验证该集合 GitHub 的详细信息。

# Java 示例
<a name="ddb-java-examples"></a>


****  

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

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

以下示例演示了如何在未填充的全新 Amazon DynamoDB 表中配置适用于 DynamoDB 的 Java 客户端加密库。如果您想配置现有的 Amazon DynamoDB 表以进行客户端加密，请参阅 [将版本 3.x 添加到现有表](ddb-java-config-existing-table.md)。

**Topics**
+ [使用 DynamoDB 增强版客户端](#ddb-java-enhanced-client-example)
+ [使用低级 DynamoDB API](#ddb-java-lowlevel-API-example)
+ [使用较低的级别 DynamoDbItemEncryptor](#ddb-java-itemencryptor)

## 使用 DynamoDB 增强版客户端
<a name="ddb-java-enhanced-client-example"></a>

以下示例展示了如何作为 DynamoDB API 调用的一部分，结合使用 DynamoDB 增强型客户端和 `DynamoDbEncryptionInterceptor` 与 [AWS KMS 密钥环](use-kms-keyring.md)对 DynamoDB 表项目进行加密。

您可以在 DynamoDB 增强版客户端中使用任何支持的[密钥环](keyrings.md)，但我们建议尽可能使用其中 AWS KMS 一个密钥环。

**注意**  
DynamoDB 增强版客户端不支持[可搜索的加密](searchable-encryption.md)。将 `DynamoDbEncryptionInterceptor` 与低级 DynamoDB API 一起使用，以便使用可搜索加密。

**查看完整的代码示例**：[EnhancedPutGetExample.java](https://github.com/aws/aws-database-encryption-sdk-dynamodb//blob/main/Examples/runtimes/java/DynamoDbEncryption/src/main/java/software/amazon/cryptography/examples/enhanced/EnhancedPutGetExample.java)

**步骤 1：创建 AWS KMS 密钥环**  
以下示例使用`CreateAwsKmsMrkMultiKeyring`对称加密 KMS AWS KMS 密钥创建密钥环。`CreateAwsKmsMrkMultiKeyring` 方法可确保密钥环能够正确处理单区域密钥和多区域密钥。  

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

**步骤 2：根据带注释的数据类创建表架构**  
以下示例使用带注释的数据类创建 `TableSchema`。  
此示例假设带注释的数据类和属性操作是使用 [SimpleClass.java 定义的。](https://github.com/aws/aws-database-encryption-sdk-dynamodb//blob/main/Examples/runtimes/java/DynamoDbEncryption/src/main/java/software/amazon/cryptography/examples/enhanced/SimpleClass.java)有关为属性操作添加注释的更多指导，请参阅 [使用带注释的数据类](ddb-java-using.md#ddb-attribute-actions-annotated-data-class)。  
 AWS 数据库加密 SDK 不支持对[嵌套属性](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/ddb-en-client-adv-features-nested.html)进行标注。

```
final TableSchema<SimpleClass> schemaOnEncrypt = TableSchema.fromBean(SimpleClass.class);
```

**步骤 3：定义从签名中可以排除哪些属性**  
以下示例假设所有 `DO_NOTHING` 属性共享不同的前缀“`:`”，并使用该前缀定义允许的未签名属性。客户端假设任何带有“`:`”前缀的属性名称都被排除在签名之外。有关更多信息，请参阅 [Allowed unsigned attributes](ddb-java-using.md#allowed-unauth)。  

```
final String unsignedAttrPrefix = ":";
```

**步骤 4：创建加密配置**  
以下示例定义了一个 `tableConfigs` 映射，该映射表示 DynamoDB 表的加密配置。  
此示例将 DynamoDB 表名称指定为[逻辑表名称](ddb-java-using.md#logical-table-name)。强烈建议您在首次定义加密配置时将 DynamoDB 表名指定为逻辑表名。有关更多信息，请参阅 [适用于 DynamoDB 的 AWS 数据库加密 SDK 中的加密配置](ddb-java-using.md#ddb-config-encrypt)。  
要使用[可搜索的加密](searchable-encryption.md)或[签名信标](configure.md#signed-beacons)，您还必须在加密配置中包括 [`SearchConfig`](ddb-java-using.md#ddb-search-config)。

```
final Map<String, DynamoDbEnhancedTableEncryptionConfig> tableConfigs = new HashMap<>();
tableConfigs.put(ddbTableName,
    DynamoDbEnhancedTableEncryptionConfig.builder()
        .logicalTableName(ddbTableName)
        .keyring(kmsKeyring)
        .allowedUnsignedAttributePrefix(unsignedAttrPrefix)
        .schemaOnEncrypt(tableSchema)
        .build());
```

**步骤 5：创建 `DynamoDbEncryptionInterceptor`**  
以下示例使用**步骤 4** 中的 `tableConfigs` 中创建一个新的 `DynamoDbEncryptionInterceptor`。  

```
final DynamoDbEncryptionInterceptor interceptor =
    DynamoDbEnhancedClientEncryption.CreateDynamoDbEncryptionInterceptor(
        CreateDynamoDbEncryptionInterceptorInput.builder()
            .tableEncryptionConfigs(tableConfigs)
            .build()
    );
```

**第 6 步：创建新的 AWS SDK DynamoDB 客户端**  
**以下示例使用步骤 5 中的创建了一个新 AWS 的 SDK DynamoDB 客户端`interceptor`。**  

```
final DynamoDbClient ddb = DynamoDbClient.builder()
        .overrideConfiguration(
                ClientOverrideConfiguration.builder()
                       .addExecutionInterceptor(interceptor)
                       .build())
        .build();
```

**步骤 7：创建 DynamoDB 增强版客户端并创建表**  
以下示例使用**步骤 6** 中创建的 AWS SDK DynamoDB 客户端创建 DynamoDB 增强型客户端，并使用带注释的数据类创建表。  

```
final DynamoDbEnhancedClient enhancedClient = DynamoDbEnhancedClient.builder()
        .dynamoDbClient(ddb)
        .build();
final DynamoDbTable<SimpleClass> table = enhancedClient.table(ddbTableName, tableSchema);
```

**步骤 8：对表项目进行加密和签名**  
以下示例使用 DynamoDB 增强版客户端将项目放入 DynamoDB 表中。该项目在发送到 DynamoDB 之前将在客户端进行加密和签名。  

```
final SimpleClass item = new SimpleClass();
item.setPartitionKey("EnhancedPutGetExample");
item.setSortKey(0);
item.setAttribute1("encrypt and sign me!");
item.setAttribute2("sign me!");
item.setAttribute3("ignore me!");

table.putItem(item);
```

## 使用低级 DynamoDB API
<a name="ddb-java-lowlevel-API-example"></a>

以下示例演示如何使用带有 [AWS KMS 密钥环](use-kms-keyring.md)的低级 DynamoDB API，通过您的 DynamoDB `PutItem` 请求在客户端对项目自动进行加密和签名。

您可以使用任何支持的[密钥环](keyrings.md)，但我们建议尽可能使用其中一个 AWS KMS 密钥环。

**查看完整的代码示例**：[BasicPutGetExample.java](https://github.com/aws/aws-database-encryption-sdk-dynamodb//blob/main/Examples/runtimes/java/DynamoDbEncryption/src/main/java/software/amazon/cryptography/examples/BasicPutGetExample.java)

**步骤 1：创建 AWS KMS 密钥环**  
以下示例使用`CreateAwsKmsMrkMultiKeyring`对称加密 KMS AWS KMS 密钥创建密钥环。`CreateAwsKmsMrkMultiKeyring` 方法可确保密钥环能够正确处理单区域密钥和多区域密钥。  

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

**步骤 2：配置属性操作**  
以下示例定义了一个 `attributeActionsOnEncrypt` 映射，该映射表示表项目的示例[属性操作](concepts.md#crypt-actions)。  
以下示例未将任何属性定义为`SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`。如果您指定了任何`SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`属性，则分区和排序属性也必须是`SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`。

```
final Map<String, CryptoAction> attributeActionsOnEncrypt = new HashMap<>();
// The partition attribute must be SIGN_ONLY
attributeActionsOnEncrypt.put("partition_key", CryptoAction.SIGN_ONLY); 
// The sort attribute must be SIGN_ONLY
attributeActionsOnEncrypt.put("sort_key", CryptoAction.SIGN_ONLY); 
attributeActionsOnEncrypt.put("attribute1", CryptoAction.ENCRYPT_AND_SIGN);
attributeActionsOnEncrypt.put("attribute2", CryptoAction.SIGN_ONLY);
attributeActionsOnEncrypt.put(":attribute3", CryptoAction.DO_NOTHING);
```

**步骤 3：定义从签名中可以排除哪些属性**  
以下示例假设所有 `DO_NOTHING` 属性共享不同的前缀“`:`”，并使用该前缀定义允许的未签名属性。客户端假设任何带有“`:`”前缀的属性名称都被排除在签名之外。有关更多信息，请参阅 [Allowed unsigned attributes](ddb-java-using.md#allowed-unauth)。  

```
final String unsignedAttrPrefix = ":";
```

**步骤 4：定义 DynamoDB 表的加密配置**  
以下示例定义了一个 `tableConfigs` 映射，该映射表示此 DynamoDB 表的加密配置。  
此示例将 DynamoDB 表名称指定为[逻辑表名称](ddb-java-using.md#logical-table-name)。强烈建议您在首次定义加密配置时将 DynamoDB 表名指定为逻辑表名。有关更多信息，请参阅 [适用于 DynamoDB 的 AWS 数据库加密 SDK 中的加密配置](ddb-java-using.md#ddb-config-encrypt)。  
要使用[可搜索的加密](searchable-encryption.md)或[签名信标](configure.md#signed-beacons)，您还必须在加密配置中包括 [`SearchConfig`](ddb-java-using.md#ddb-search-config)。

```
final Map<String, DynamoDbTableEncryptionConfig> tableConfigs = new HashMap<>();
final DynamoDbTableEncryptionConfig config = DynamoDbTableEncryptionConfig.builder()
        .logicalTableName(ddbTableName)
        .partitionKeyName("partition_key")
        .sortKeyName("sort_key")
        .attributeActionsOnEncrypt(attributeActionsOnEncrypt)
        .keyring(kmsKeyring)
        .allowedUnsignedAttributePrefix(unsignedAttrPrefix)
        .build();
tableConfigs.put(ddbTableName, config);
```

**步骤 5：创建 `DynamoDbEncryptionInterceptor`**  
以下示例使用**步骤 4** 中的 `tableConfigs` 创建 `DynamoDbEncryptionInterceptor`。  

```
DynamoDbEncryptionInterceptor interceptor = DynamoDbEncryptionInterceptor.builder()
        .config(DynamoDbTablesEncryptionConfig.builder()
                .tableEncryptionConfigs(tableConfigs)
                .build())
        .build();
```

**第 6 步：创建新的 AWS SDK DynamoDB 客户端**  
**以下示例使用步骤 5 中的创建了一个新 AWS 的 SDK DynamoDB 客户端`interceptor`。**  

```
final DynamoDbClient ddb = DynamoDbClient.builder()
        .overrideConfiguration(
                ClientOverrideConfiguration.builder()
                       .addExecutionInterceptor(interceptor)
                       .build())
        .build();
```

**步骤 7：对 DynamoDB 表项目进行加密和签名**  
以下示例定义了一个 `item` 映射，该映射表示示例表项目并将该项目放入 DynamoDB 表中。该项目在发送到 DynamoDB 之前将在客户端进行加密和签名。  

```
final HashMap<String, AttributeValue> item = new HashMap<>();
item.put("partition_key", AttributeValue.builder().s("BasicPutGetExample").build());
item.put("sort_key", AttributeValue.builder().n("0").build());
item.put("attribute1", AttributeValue.builder().s("encrypt and sign me!").build());
item.put("attribute2", AttributeValue.builder().s("sign me!").build());
item.put(":attribute3", AttributeValue.builder().s("ignore me!").build());

final PutItemRequest putRequest = PutItemRequest.builder()
        .tableName(ddbTableName)
        .item(item)
        .build();

final PutItemResponse putResponse = ddb.putItem(putRequest);
```

## 使用较低的级别 DynamoDbItemEncryptor
<a name="ddb-java-itemencryptor"></a>

以下示例说明如何使用带有 [AWS KMS 密钥环](use-kms-keyring.md)的较低级别 `DynamoDbItemEncryptor` 来直接对表项目进行加密和签名。`DynamoDbItemEncryptor` 不会将项目放入 DynamoDB 表中。

您可以在 DynamoDB 增强版客户端中使用任何支持的[密钥环](keyrings.md)，但我们建议尽可能使用其中 AWS KMS 一个密钥环。

**注意**  
较低级别的 `DynamoDbItemEncryptor` 不支持[可搜索加密](searchable-encryption.md)。将 `DynamoDbEncryptionInterceptor` 与低级 DynamoDB API 一起使用，以便使用可搜索加密。

**查看完整的代码示例**：[ItemEncryptDecryptExample.java](https://github.com/aws/aws-database-encryption-sdk-dynamodb//blob/main/Examples/runtimes/java/DynamoDbEncryption/src/main/java/software/amazon/cryptography/examples/itemencryptor/ItemEncryptDecryptExample.java)

**步骤 1：创建 AWS KMS 密钥环**  
以下示例使用`CreateAwsKmsMrkMultiKeyring`对称加密 KMS AWS KMS 密钥创建密钥环。`CreateAwsKmsMrkMultiKeyring` 方法可确保密钥环能够正确处理单区域密钥和多区域密钥。  

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

**步骤 2：配置属性操作**  
以下示例定义了一个 `attributeActionsOnEncrypt` 映射，该映射表示表项目的示例[属性操作](concepts.md#crypt-actions)。  
以下示例未将任何属性定义为`SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`。如果您指定了任何`SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`属性，则分区和排序属性也必须是`SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`。

```
final Map<String, CryptoAction> attributeActionsOnEncrypt = new HashMap<>();
// The partition attribute must be SIGN_ONLY
attributeActionsOnEncrypt.put("partition_key", CryptoAction.SIGN_ONLY); 
// The sort attribute must be SIGN_ONLY
attributeActionsOnEncrypt.put("sort_key", CryptoAction.SIGN_ONLY); 
attributeActionsOnEncrypt.put("attribute1", CryptoAction.ENCRYPT_AND_SIGN);
attributeActionsOnEncrypt.put("attribute2", CryptoAction.SIGN_ONLY);
attributeActionsOnEncrypt.put(":attribute3", CryptoAction.DO_NOTHING);
```

**步骤 3：定义从签名中可以排除哪些属性**  
以下示例假设所有 `DO_NOTHING` 属性共享不同的前缀“`:`”，并使用该前缀定义允许的未签名属性。客户端假设任何带有“`:`”前缀的属性名称都被排除在签名之外。有关更多信息，请参阅 [Allowed unsigned attributes](ddb-java-using.md#allowed-unauth)。  

```
final String unsignedAttrPrefix = ":";
```

**步骤 4：定义 `DynamoDbItemEncryptor` 配置**  
以下示例定义 `DynamoDbItemEncryptor` 的配置。  
此示例将 DynamoDB 表名称指定为[逻辑表名称](ddb-java-using.md#logical-table-name)。强烈建议您在首次定义加密配置时将 DynamoDB 表名指定为逻辑表名。有关更多信息，请参阅 [适用于 DynamoDB 的 AWS 数据库加密 SDK 中的加密配置](ddb-java-using.md#ddb-config-encrypt)。  

```
final DynamoDbItemEncryptorConfig config = DynamoDbItemEncryptorConfig.builder()
        .logicalTableName(ddbTableName)
        .partitionKeyName("partition_key")
        .sortKeyName("sort_key")
        .attributeActionsOnEncrypt(attributeActionsOnEncrypt)
        .keyring(kmsKeyring)
        .allowedUnsignedAttributePrefix(unsignedAttrPrefix)
        .build();
```

**步骤 5：创建 `DynamoDbItemEncryptor`**  
以下示例使用**步骤 4** 中的 `config` 创建新的 `DynamoDbItemEncryptor`。  

```
final DynamoDbItemEncryptor itemEncryptor = DynamoDbItemEncryptor.builder()
        .DynamoDbItemEncryptorConfig(config)
        .build();
```

**步骤 6：直接对表项目进行加密和签名**  
以下示例使用 `DynamoDbItemEncryptor` 直接对项目进行加密和签名。`DynamoDbItemEncryptor` 不会将项目放入 DynamoDB 表中。  

```
final Map<String, AttributeValue> originalItem = new HashMap<>();
originalItem.put("partition_key", AttributeValue.builder().s("ItemEncryptDecryptExample").build());
originalItem.put("sort_key", AttributeValue.builder().n("0").build());
originalItem.put("attribute1", AttributeValue.builder().s("encrypt and sign me!").build());
originalItem.put("attribute2", AttributeValue.builder().s("sign me!").build());
originalItem.put(":attribute3", AttributeValue.builder().s("ignore me!").build());

final Map<String, AttributeValue> encryptedItem = itemEncryptor.EncryptItem(
        EncryptItemInput.builder()
                .plaintextItem(originalItem)
                .build()
).encryptedItem();
```

# 将现有 DynamoDB 表配置为使用适用于 DynamoDB AWS 的数据库加密 SDK
<a name="ddb-java-config-existing-table"></a>


****  

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

使用适用于 DynamoDB 的 Java 客户端加密库的 3.*x* 版本，您可以配置现有的 Amazon DynamoDB 表以进行客户端加密。本主题提供有关添加版本 3.*x* 到已填充的现有 DynamoDB 表要采取的三个步骤的指导。

**先决条件**  
适用于 DynamoDB 的 Java 客户端加密库中的版本 3.*x* 需要 AWS SDK for Java 2.x 中提供的 [DynamoDB 增强型客户端](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/dynamodb-enhanced-client.html)。如果您仍在使用 [Dynamo DBMapper](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBMapper.Methods.html)，则必须迁移 AWS SDK for Java 2.x 到才能使用 DynamoDB 增强型客户端。

 按照[从 适用于 Java 的 AWS SDK的版本 1.x 迁移到 2.x](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/migration.html) 的说明进行操作。

然后，按照说明[开始使用 DynamoDB 增强型客户端 API](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/ddb-en-client-getting-started.html)。

在将表配置为使用适用于 DynamoDB 的 Java 客户端加密库之前，您需要[使用带注释的数据类](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/ddb-en-client-gs-tableschema.html#ddb-en-client-gs-tableschema-anno-bean)生成 `TableSchema`，并且需要[创建增强型客户端](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/ddb-en-client-getting-started-dynamodbTable.html#ddb-en-client-getting-started-dynamodbTable-eclient)。

## 步骤 1：准备读取和写入加密项目
<a name="ddb-java-add-step1"></a>

完成以下步骤，为 AWS 数据库加密 SDK 客户端做好读取和写入加密项目的准备。部署以下更改后，您的客户端将继续读取和写入明文项目。它不会对写入表中的任何新项目进行加密或签名，但却能够在加密项目显示后立即对其进行解密。这些更改使得客户端为开始[加密新项目](#ddb-java-add-step2)做好准备。在继续执行下一步操作之前，必须将以下更改部署到每一个读取器。

**1. 定义您的[属性操作](concepts.md#crypt-actions)**  
更新带注释的数据类以包含属性操作，这些操作定义哪些属性值将被加密和签名，哪些将仅被签名，哪些将被忽略。  
有关 DynamoDB 增强型客户端注释的更多指导，请参阅上 GitHub的 aws-database-encryption-sdk-dynamodb 存储库中的 [SimpleClass.java](https://github.com/aws/aws-database-encryption-sdk-dynamodb//blob/main/Examples/runtimes/java/DynamoDbEncryption/src/main/java/software/amazon/cryptography/examples/enhanced/SimpleClass.java)。  
默认情况下，主键属性已签名但未加密（`SIGN_ONLY`），而所有其他属性均经过加密和签名（`ENCRYPT_AND_SIGN`）。要指定例外情况，请使用在适用于 DynamoDB 的 Java 客户端加密库中定义的加密注释。例如，如果您只想对某个特定属性进行签名，请使用 `@DynamoDbEncryptionSignOnly` 注释。如果要对特定属性进行签名并将其包含在加密上下文中，请使用`@DynamoDbEncryptionSignAndIncludeInEncryptionContext`注释。如果对特定属性既不要签名也不要加密（`DO_NOTHING`），请使用 `@DynamoDbEncryptionDoNothing` 注释。  
如果您指定了任何`SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`属性，则分区和排序属性也必须是`SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`。有关显示用于定义的注释的示例`SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`，请参阅 [SimpleClass4.java](https://github.com/aws/aws-database-encryption-sdk-dynamodb//blob/main/Examples/runtimes/java/DynamoDbEncryption/src/main/java/software/amazon/cryptography/examples/enhanced/SimpleClass4.java)。
有关注释的示例，请参阅 [使用带注释的数据类](ddb-java-using.md#ddb-attribute-actions-annotated-data-class)。

**2. 定义从签名中将可以排除哪些属性**  
以下示例假设所有 `DO_NOTHING` 属性共享不同的前缀“`:`”，并使用该前缀定义允许的未签名属性。客户端将假设任何带有“`:`”前缀的属性名称都被排除在签名之外。有关更多信息，请参阅 [Allowed unsigned attributes](ddb-java-using.md#allowed-unauth)。  

```
final String unsignedAttrPrefix = ":";
```

**3. 创建[密钥环](keyrings.md)**  
以下示例创建一个 [AWS KMS 密钥环](use-kms-keyring.md)。 AWS KMS 密钥环使用对称加密或非对称 RSA AWS KMS keys 来生成、加密和解密数据密钥。  
该示例使用 `CreateMrkMultiKeyring` 创建带有对称加密 KMS 密钥的 AWS KMS 密钥环。`CreateAwsKmsMrkMultiKeyring` 方法可确保密钥环能够正确处理单区域密钥和多区域密钥。  

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

**4. 定义 DynamoDB 表的加密配置 **  
以下示例定义了一个 `tableConfigs` 映射，该映射表示此 DynamoDB 表的加密配置。  
此示例将 DynamoDB 表名称指定为[逻辑表名称](ddb-java-using.md#logical-table-name)。强烈建议您在首次定义加密配置时将 DynamoDB 表名指定为逻辑表名。有关更多信息，请参阅 [适用于 DynamoDB 的 AWS 数据库加密 SDK 中的加密配置](ddb-java-using.md#ddb-config-encrypt)。  
必须指定 `FORCE_WRITE_PLAINTEXT_ALLOW_READ_PLAINTEXT` 作为明文替代。此策略继续读取和写入明文项目，读取加密项目，并使客户端做好准备以写入加密项目。  

```
final Map<String, DynamoDbTableEncryptionConfig> tableConfigs = new HashMap<>();
final DynamoDbTableEncryptionConfig config = DynamoDbTableEncryptionConfig.builder()
        .logicalTableName(ddbTableName)
        .partitionKeyName("partition_key")
        .sortKeyName("sort_key")
        .schemaOnEncrypt(tableSchema)
        .keyring(kmsKeyring)
        .allowedUnsignedAttributePrefix(unsignedAttrPrefix)
        .plaintextOverride(PlaintextOverride.FORCE_WRITE_PLAINTEXT_ALLOW_READ_PLAINTEXT)
        .build();
tableConfigs.put(ddbTableName, config);
```

**5. 创建 `DynamoDbEncryptionInterceptor`**  
以下示例使用**步骤 3** 中的 `tableConfigs` 创建 `DynamoDbEncryptionInterceptor`。  

```
DynamoDbEncryptionInterceptor interceptor = DynamoDbEncryptionInterceptor.builder()
        .config(DynamoDbTablesEncryptionConfig.builder()
                .tableEncryptionConfigs(tableConfigs)                
                .build())
        .build();
```

## 步骤 2：写入已加密和签名项目
<a name="ddb-java-add-step2"></a>

更新 `DynamoDbEncryptionInterceptor` 配置中的明文策略，以允许客户端写入已加密和签名的项目。部署好以下更改后，客户端将根据您在**步骤 1** 中配置的属性操作对新项目进行加密和签名。客户将能够读取明文项目以及已加密和签名的项目。

在继续执行[步骤 3](#ddb-java-add-step3) 之前，您必须对表格中所有现有的明文项目进行加密和签名。您无法运行单一指标或查询来快速加密您的现有明文项目。使用对您的系统最有意义的过程。例如，您可以使用异步过程，以缓慢扫描表，然后使用您定义的属性操作和加密配置重写项目。要识别表中的纯文本项目，我们建议您扫描所有不包含 AWS 数据库加密 SDK 在项目加密`aws_dbe_head`和签名时添加的和`aws_dbe_foot`属性的项目。

以下示例更新了**步骤 1** 中的表加密配置。您必须使用 `FORBID_WRITE_PLAINTEXT_ALLOW_READ_PLAINTEXT` 更新明文替代。该策略继续读取明文项目，但也会读取和写入加密项目。`DynamoDbEncryptionInterceptor`使用更新的内容创建一个新的`tableConfigs`。

```
final Map<String, DynamoDbTableEncryptionConfig> tableConfigs = new HashMap<>();
final DynamoDbTableEncryptionConfig config = DynamoDbTableEncryptionConfig.builder()
        .logicalTableName(ddbTableName)
        .partitionKeyName("partition_key")
        .sortKeyName("sort_key")
        .schemaOnEncrypt(tableSchema)
        .keyring(kmsKeyring)
        .allowedUnsignedAttributePrefix(unsignedAttrPrefix)
        .plaintextOverride(PlaintextOverride.FORBID_WRITE_PLAINTEXT_ALLOW_READ_PLAINTEXT)
        .build();
tableConfigs.put(ddbTableName, config);
```

## 步骤 3：仅读取已加密和签名项目
<a name="ddb-java-add-step3"></a>

在对所有项目进行加密和签名后，请更新 `DynamoDbEncryptionInterceptor` 配置中的明文替代，以便仅允许客户端读取和写入已加密和签名的项目。部署好以下更改后，客户端将根据您在**步骤 1** 中配置的属性操作对新项目进行加密和签名。客户只能够读取已加密和签名的项目。

以下示例更新了**步骤 2** 中的表加密配置。您可以使用 `FORBID_WRITE_PLAINTEXT_FORBID_READ_PLAINTEXT` 更新明文替代，也可以从配置中移除明文策略。默认情况下，客户端仅读取和写入已加密和签名的项目。`DynamoDbEncryptionInterceptor`使用更新的内容创建一个新的`tableConfigs`。

```
final Map<String, DynamoDbTableEncryptionConfig> tableConfigs = new HashMap<>();
final DynamoDbTableEncryptionConfig config = DynamoDbTableEncryptionConfig.builder()
        .logicalTableName(ddbTableName)
        .partitionKeyName("partition_key")
        .sortKeyName("sort_key")
        .schemaOnEncrypt(tableSchema)
        .keyring(kmsKeyring)
        .allowedUnsignedAttributePrefix(unsignedAttrPrefix)
        // Optional: you can also remove the plaintext policy from your configuration
        .plaintextOverride(PlaintextOverride.FORBID_WRITE_PLAINTEXT_FORBID_READ_PLAINTEXT)
        .build();
tableConfigs.put(ddbTableName, config);
```

# 迁移到适用于 DynamoDB 的 Java 客户端加密库的版本 3.x
<a name="ddb-java-migrate"></a>


****  

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

适用于 DynamoDB 的 Java 客户端加密库的版本 3.*x* 是对 2.*x* 代码库的重大改写。它包括许多更新，例如新的结构化数据格式、改进的多租户支持、无缝架构更改，以及可搜索的加密支持。本主题提供有关如何将代码迁移到版本 3.*x* 的指导。

## 从版本 1.x 迁移到 2.x
<a name="ddb-java-v1-to-v2"></a>

在迁移到版本 3.*x* 之前先迁移到版本 2.*x*。版本 2.*x* 已将最新提供程序的符号从 `MostRecentProvider` 更改为 `CachingMostRecentProvider`。如果您当前使用的是带有 `MostRecentProvider` 符号的适用于 DynamoDB 的 Java 客户端加密库的版本 1.*x*，必须将代码中的符号名称更新为 `CachingMostRecentProvider`。要了解更多信息，请参阅[最新提供程序的更新](most-recent-provider.md#mrp-versions)。

## 从版本 2.x 迁移到 3.x
<a name="ddb-java-v2-to-v3"></a>

以下步骤说明如何将您的代码从适用于 DynamoDB 的 Java 客户端加密库的版本 2.*x* 迁移到版本 3.*x*。

### 步骤 1：准备读取新格式的项目
<a name="ddb-java-migrate-step1"></a>

完成以下步骤，准备您的 AWS 数据库加密 SDK 客户端，以读取新格式的项目。部署以下更改后，您的客户端将继续以与版本 2.*x* 相同的行为方式运行。您的客户将继续读取和写入 2.*x* 格式中的项目，但是这些更改使客户端做好[读取新格式项目](#ddb-java-migrate-step2)的准备。

**将你的版本更新 适用于 Java 的 AWS SDK 到 2.x 版**  
适用于 DynamoDB 的 Java 客户端加密库的版本 3.*x* 需要 [DynamoDB 增强型客户端](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/dynamodb-enhanced-client.html)。DynamoDB 增强版客户端取代了之前版本[中使用的 DBMapper](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBMapper.Methods.html) Dynamo。要使用增强型客户端，您必须使用 AWS SDK for Java 2.x。  
按照[从 适用于 Java 的 AWS SDK的版本 1.x 迁移到 2.x](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/migration.html) 的说明进行操作。  
有关需要哪些 AWS SDK for Java 2.x 模块的更多信息，请参阅[先决条件](ddb-java.md#ddb-java-prerequisites)。

**配置您的客户端，以读取由旧版本加密的项目**  
以下过程概述了以下代码示例中所演示的步骤。  

1. 创建一个[密钥环](keyrings.md)。

   密钥环和[加密材料管理程序](concepts.md#crypt-materials-manager)将取代以前版本的适用于 DynamoDB 的 Java 客户端加密库中使用的加密材料提供程序。
**重要**  
您在创建密钥环时指定的包装密钥必须与版本 2.*x* 中用于加密材料提供程序的包装密钥相同。

1. 创建一个带注释的类的表架构。

   此步骤用于定义开始以新格式编写项目时将使用的属性操作。

   有关使用全新 DynamoDB 增强版客户端的指南，请参阅《适用于 Java 的 AWS SDK 开发人员指南》**中的[生成一个 `TableSchema`](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/ddb-en-client-gs-tableschema.html)。

   以下示例假设您已使用新的属性操作注释从版本 2.*x* 中更新您的带注释类。有关为属性操作添加注释的更多指导，请参阅 [使用带注释的数据类](ddb-java-using.md#ddb-attribute-actions-annotated-data-class)。
**注意**  
如果您指定了任何`SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`属性，则分区和排序属性也必须是`SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`。有关显示用于定义的注释的示例`SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`，请参阅 [SimpleClass4.java](https://github.com/aws/aws-database-encryption-sdk-dynamodb//blob/main/Examples/runtimes/java/DynamoDbEncryption/src/main/java/software/amazon/cryptography/examples/enhanced/SimpleClass4.java)。

1. 定义[从签名中可以排除哪些属性](ddb-java-using.md#allowed-unauth)。

1. 配置在 2.x 版本建模类中配置的属性操作的显式映射。

   此步骤定义用于以旧格式编写项目的属性操作。

1. 配置 `DynamoDBEncryptor` 您在适用于 DynamoDB 的 Java 客户端加密库的版本 2.*x* 中使用的 。

1. 配置遗留行为。

1. 创建 `DynamoDbEncryptionInterceptor`。

1. 创建一个新的 AWS SDK DynamoDB 客户端。

1. 创建 `DynamoDBEnhancedClient` 并使用您的建模类创建表。

   要了解 DynamoDB 增强版客户端的更多信息，请参阅[创建增强型客户端](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/ddb-en-client-getting-started-dynamodbTable.html#ddb-en-client-getting-started-dynamodbTable-eclient)。

```
public class MigrationExampleStep1 {

    public static void MigrationStep1(String kmsKeyId, String ddbTableName, int sortReadValue) {
        // 1. Create a Keyring.
        //    This example creates an AWS KMS Keyring that specifies the 
        //    same kmsKeyId previously used in the version 2.x configuration.
        //    It uses the 'CreateMrkMultiKeyring' method to create the 
        //    keyring, so that the keyring can correctly handle both single
        //    region and Multi-Region KMS Keys.
        //    Note that this example uses the AWS SDK for Java v2 KMS client.
        final MaterialProviders matProv = MaterialProviders.builder()
                .MaterialProvidersConfig(MaterialProvidersConfig.builder().build())
                .build();
        final CreateAwsKmsMrkMultiKeyringInput keyringInput = CreateAwsKmsMrkMultiKeyringInput.builder()
                .generator(kmsKeyId)
                .build();
        final IKeyring kmsKeyring = matProv.CreateAwsKmsMrkMultiKeyring(keyringInput);

        // 2. Create a Table Schema over your annotated class.
        //    For guidance on using the new attribute actions 
        //    annotations, see SimpleClass.java in the 
        //    aws-database-encryption-sdk-dynamodb GitHub repository. 
        //    All primary key attributes must be signed but not encrypted 
        //    and by default all non-primary key attributes 
        //    are encrypted and signed (ENCRYPT_AND_SIGN).
        //    If you want a particular non-primary key attribute to be signed but
        //    not encrypted, use the 'DynamoDbEncryptionSignOnly' annotation.
        //    If you want a particular attribute to be neither signed nor encrypted
        //    (DO_NOTHING), use the 'DynamoDbEncryptionDoNothing' annotation.
        final TableSchema<SimpleClass> schemaOnEncrypt = TableSchema.fromBean(SimpleClass.class);

        // 3. Define which attributes the client should expect to be excluded 
        //    from the signature when reading items.
        //    This value represents all unsigned attributes across the entire 
        //    dataset.
        final List<String> allowedUnsignedAttributes = Arrays.asList("attribute3");

        // 4. Configure an explicit map of the attribute actions configured 
        //    in your version 2.x modeled class.
        final Map<String, CryptoAction> legacyActions = new HashMap<>();
        legacyActions.put("partition_key", CryptoAction.SIGN_ONLY);
        legacyActions.put("sort_key", CryptoAction.SIGN_ONLY);
        legacyActions.put("attribute1", CryptoAction.ENCRYPT_AND_SIGN);
        legacyActions.put("attribute2", CryptoAction.SIGN_ONLY);
        legacyActions.put("attribute3", CryptoAction.DO_NOTHING);

        // 5. Configure the DynamoDBEncryptor that you used in version 2.x.
        final AWSKMS kmsClient = AWSKMSClientBuilder.defaultClient();
        final DirectKmsMaterialProvider cmp = new DirectKmsMaterialProvider(kmsClient, kmsKeyId);
        final DynamoDBEncryptor oldEncryptor = DynamoDBEncryptor.getInstance(cmp);

        // 6. Configure the legacy behavior.
        //    Input the DynamoDBEncryptor and attribute actions created in 
        //    the previous steps. For Legacy Policy, use 
        //    'FORCE_LEGACY_ENCRYPT_ALLOW_LEGACY_DECRYPT'. This policy continues to read 
        //    and write items using the old format, but will be able to read
        //    items written in the new format as soon as they appear.
        final LegacyOverride legacyOverride = LegacyOverride
                .builder()
                .encryptor(oldEncryptor)
                .policy(LegacyPolicy.FORCE_LEGACY_ENCRYPT_ALLOW_LEGACY_DECRYPT)
                .attributeActionsOnEncrypt(legacyActions)
                .build();

        // 7. Create a DynamoDbEncryptionInterceptor with the above configuration.
        final Map<String, DynamoDbEnhancedTableEncryptionConfig> tableConfigs = new HashMap<>();
        tableConfigs.put(ddbTableName,
                DynamoDbEnhancedTableEncryptionConfig.builder()
                        .logicalTableName(ddbTableName)
                        .keyring(kmsKeyring)
                        .allowedUnsignedAttributes(allowedUnsignedAttributes)
                        .schemaOnEncrypt(tableSchema)
                        .legacyOverride(legacyOverride)
                        .build());
        final DynamoDbEncryptionInterceptor interceptor =
                DynamoDbEnhancedClientEncryption.CreateDynamoDbEncryptionInterceptor(
                        CreateDynamoDbEncryptionInterceptorInput.builder()
                                .tableEncryptionConfigs(tableConfigs)
                                .build()
                );

        // 8. Create a new AWS SDK DynamoDb client using the 
        //    interceptor from Step 7.
        final DynamoDbClient ddb = DynamoDbClient.builder()
                .overrideConfiguration(
                        ClientOverrideConfiguration.builder()
                                .addExecutionInterceptor(interceptor)
                                .build())
                .build();

        // 9. Create the DynamoDbEnhancedClient using the AWS SDK DynamoDb client 
        //    created in Step 8, and create a table with your modeled class.
        final DynamoDbEnhancedClient enhancedClient = DynamoDbEnhancedClient.builder()
                .dynamoDbClient(ddb)
                .build();
        final DynamoDbTable<SimpleClass> table = enhancedClient.table(ddbTableName, tableSchema);
    }
}
```

### 步骤 2：用新格式编写项目
<a name="ddb-java-migrate-step2"></a>

将步骤 1 中的更改部署到所有读取器后，请完成以下步骤，将 AWS 数据库加密 SDK 客户端配置为以新格式写入项目。部署以下更改后，您的客户端将继续读取旧格式的项目，并且开始以新格式编写和读取项目。

以下过程概述了以下代码示例中所演示的步骤。

1. 继续配置密钥环、表架构、旧属性操作 `allowedUnsignedAttributes` 和 `DynamoDBEncryptor`，就像在[**步骤 1**](#ddb-java-migrate-step1) 中执行的操作一样。

1. 将遗留行为更新为仅使用新格式编写新项目。

1. 创建 `DynamoDbEncryptionInterceptor `

1. 创建一个新的 AWS SDK DynamoDB 客户端。

1. 创建 `DynamoDBEnhancedClient` 并使用您的建模类创建表。

   要了解 DynamoDB 增强版客户端的更多信息，请参阅[创建增强型客户端](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/ddb-en-client-getting-started-dynamodbTable.html#ddb-en-client-getting-started-dynamodbTable-eclient)。

```
public class MigrationExampleStep2 {

    public static void MigrationStep2(String kmsKeyId, String ddbTableName, int sortReadValue) {
        // 1. Continue to configure your keyring, table schema, legacy 
        //    attribute actions, allowedUnsignedAttributes, and 
        //    DynamoDBEncryptor as you did in Step 1.
        final MaterialProviders matProv = MaterialProviders.builder()
                .MaterialProvidersConfig(MaterialProvidersConfig.builder().build())
                .build();
        final CreateAwsKmsMrkMultiKeyringInput keyringInput = CreateAwsKmsMrkMultiKeyringInput.builder()
                .generator(kmsKeyId)
                .build();
        final IKeyring kmsKeyring = matProv.CreateAwsKmsMrkMultiKeyring(keyringInput);

        final TableSchema<SimpleClass> schemaOnEncrypt = TableSchema.fromBean(SimpleClass.class);

        final List<String> allowedUnsignedAttributes = Arrays.asList("attribute3");

        final Map<String, CryptoAction> legacyActions = new HashMap<>();
        legacyActions.put("partition_key", CryptoAction.SIGN_ONLY);
        legacyActions.put("sort_key", CryptoAction.SIGN_ONLY);
        legacyActions.put("attribute1", CryptoAction.ENCRYPT_AND_SIGN);
        legacyActions.put("attribute2", CryptoAction.SIGN_ONLY);
        legacyActions.put("attribute3", CryptoAction.DO_NOTHING);

        final AWSKMS kmsClient = AWSKMSClientBuilder.defaultClient();
        final DirectKmsMaterialProvider cmp = new DirectKmsMaterialProvider(kmsClient, kmsKeyId);
        final DynamoDBEncryptor oldEncryptor = DynamoDBEncryptor.getInstance(cmp);

        // 2. Update your legacy behavior to only write new items using the new
        //    format. 
        //    For Legacy Policy, use 'FORBID_LEGACY_ENCRYPT_ALLOW_LEGACY_DECRYPT'. This policy
        //    continues to read items in both formats, but will only write items
        //    using the new format.
        final LegacyOverride legacyOverride = LegacyOverride
                .builder()
                .encryptor(oldEncryptor)
                .policy(LegacyPolicy.FORBID_LEGACY_ENCRYPT_ALLOW_LEGACY_DECRYPT)
                .attributeActionsOnEncrypt(legacyActions)
                .build();

        // 3. Create a DynamoDbEncryptionInterceptor with the above configuration.
        final Map<String, DynamoDbEnhancedTableEncryptionConfig> tableConfigs = new HashMap<>();
        tableConfigs.put(ddbTableName,
                DynamoDbEnhancedTableEncryptionConfig.builder()
                        .logicalTableName(ddbTableName)
                        .keyring(kmsKeyring)
                        .allowedUnsignedAttributes(allowedUnsignedAttributes)
                        .schemaOnEncrypt(tableSchema)
                        .legacyOverride(legacyOverride)
                        .build());
        final DynamoDbEncryptionInterceptor interceptor =
                DynamoDbEnhancedClientEncryption.CreateDynamoDbEncryptionInterceptor(
                        CreateDynamoDbEncryptionInterceptorInput.builder()
                                .tableEncryptionConfigs(tableConfigs)
                                .build()
                );

        // 4. Create a new AWS SDK DynamoDb client using the 
        //    interceptor from Step 3.
        final DynamoDbClient ddb = DynamoDbClient.builder()
                .overrideConfiguration(
                        ClientOverrideConfiguration.builder()
                                .addExecutionInterceptor(interceptor)
                                .build())
                .build();

        // 5. Create the DynamoDbEnhancedClient using the AWS SDK DynamoDb Client created
        //    in Step 4, and create a table with your modeled class.
        final DynamoDbEnhancedClient enhancedClient = DynamoDbEnhancedClient.builder()
                .dynamoDbClient(ddb)
                .build();
        final DynamoDbTable<SimpleClass> table = enhancedClient.table(ddbTableName, tableSchema);
    }
}
```

部署步骤 2 的更改后，必须使用新格式重新加密表中的所有旧项目，然后才能继续执行[步骤 3](#ddb-java-migrate-step3)。您无法运行单一指标或查询来快速加密您的现有项目。使用对您的系统最有意义的过程。例如，您可以使用异步过程，以缓慢扫描表，然后使用您定义的新属性操作和加密配置重写项目。

### 步骤 3：只能以新格式读取和编写项目
<a name="ddb-java-migrate-step3"></a>

使用新格式重新加密表格中的所有项目后，您可以从配置中移除遗留行为。完成以下步骤以将客户端配置为仅以新格式读取和编写项目。

以下过程概述了以下代码示例中所演示的步骤。

1. 继续配置密钥环、表架构和 `allowedUnsignedAttributes`，就像在[**步骤 1**](#ddb-java-migrate-step1) 中执行的操作一样。从您的配置中移除旧属性操作和 `DynamoDBEncryptor`。

1. 创建 `DynamoDbEncryptionInterceptor`。

1. 创建一个新的 AWS SDK DynamoDB 客户端。

1. 创建 `DynamoDBEnhancedClient` 并使用您的建模类创建表。

   要了解 DynamoDB 增强版客户端的更多信息，请参阅[创建增强型客户端](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/ddb-en-client-getting-started-dynamodbTable.html#ddb-en-client-getting-started-dynamodbTable-eclient)。

```
public class MigrationExampleStep3 {

    public static void MigrationStep3(String kmsKeyId, String ddbTableName, int sortReadValue) {
        // 1. Continue to configure your keyring, table schema,
        //    and allowedUnsignedAttributes as you did in Step 1.
        //    Do not include the configurations for the DynamoDBEncryptor or 
        //    the legacy attribute actions.
        final MaterialProviders matProv = MaterialProviders.builder()
                .MaterialProvidersConfig(MaterialProvidersConfig.builder().build())
                .build();
        final CreateAwsKmsMrkMultiKeyringInput keyringInput = CreateAwsKmsMrkMultiKeyringInput.builder()
                .generator(kmsKeyId)
                .build();
        final IKeyring kmsKeyring = matProv.CreateAwsKmsMrkMultiKeyring(keyringInput);

        final TableSchema<SimpleClass> schemaOnEncrypt = TableSchema.fromBean(SimpleClass.class);

        final List<String> allowedUnsignedAttributes = Arrays.asList("attribute3");


        // 3. Create a DynamoDbEncryptionInterceptor with the above configuration.
        //    Do not configure any legacy behavior.
        final Map<String, DynamoDbEnhancedTableEncryptionConfig> tableConfigs = new HashMap<>();
        tableConfigs.put(ddbTableName,
                DynamoDbEnhancedTableEncryptionConfig.builder()
                        .logicalTableName(ddbTableName)
                        .keyring(kmsKeyring)
                        .allowedUnsignedAttributes(allowedUnsignedAttributes)
                        .schemaOnEncrypt(tableSchema)
                        .build());
        final DynamoDbEncryptionInterceptor interceptor =
                DynamoDbEnhancedClientEncryption.CreateDynamoDbEncryptionInterceptor(
                        CreateDynamoDbEncryptionInterceptorInput.builder()
                                .tableEncryptionConfigs(tableConfigs)
                                .build()
                );

        // 4. Create a new AWS SDK DynamoDb client using the 
        //    interceptor from Step 3.
        final DynamoDbClient ddb = DynamoDbClient.builder()
                .overrideConfiguration(
                        ClientOverrideConfiguration.builder()
                                .addExecutionInterceptor(interceptor)
                                .build())
                .build();

        // 5. Create the DynamoDbEnhancedClient using the AWS SDK Client 
        //    created in Step 4, and create a table with your modeled class.
        final DynamoDbEnhancedClient enhancedClient = DynamoDbEnhancedClient.builder()
                .dynamoDbClient(ddb)
                .build();
        final DynamoDbTable<SimpleClass> table = enhancedClient.table(ddbTableName, tableSchema);
    }
}
```

# .NET
<a name="ddb-net"></a>

本主题介绍如何安装和使用版本 3。 DynamoDB 的.NET 客户端加密库中的 *x*。有关使用适用于 DynamoDB 的 AWS 数据库加密 SDK 进行编程的详细信息，请参阅上-dynamodb 存储库[中的 aws-database-encryption-sdk .NET](https://github.com/aws/aws-database-encryption-sdk-dynamodb/tree/main/Examples/runtimes/net/src/) 示例。 GitHub

DynamoDB 的.NET 客户端加密库适用于使用 C\$1 和其他.NET 编程语言编写应用程序的开发人员。它在 Windows、macOS 和 Linux 上受支持。

适用于 DynamoDB 的 AWS 数据库加密 SDK 的所有[编程语言](ddb-programming-languages.md)实现均可互操作。但是，列表或地图数据类型 适用于 .NET 的 SDK 不支持空值。这意味着，如果您使用适用于 DynamoDB 的 Java 客户端加密库来编写包含列表或地图数据类型的空值的项目，则无法使用适用于 DynamoDB 的.NET 客户端加密库来解密和读取该项目。

**Topics**
+ [安装](#ddb-net-install)
+ [调试](#ddb-net-debugging)
+ [使用.NET 客户端](ddb-net-using.md)
+ [.NET 示](ddb-net-examples.md)
+ [将版本 3.x 添加到现有表](ddb-net-config-existing-table.md)

## 为 DynamoDB 安装.NET 客户端加密库
<a name="ddb-net-install"></a>

[DynamoDB 的.NET 客户端加密库以 AWS.cryptography 的形式提供。 DbEncryptionSDK。 DynamoDb](https://www.nuget.org/packages/AWS.Cryptography.DbEncryptionSDK.DynamoDb/)打包进去 NuGet。有关安装和构建库的详细信息，请参阅-dynamodb 存储库中的 [.NET README.md](https://github.com/aws/aws-database-encryption-sdk-dynamodb/blob/main/DynamoDbEncryption/runtimes/net/README.md) 文件。 aws-database-encryption-sdk即使您没有 AWS Key Management Service 使用 () 密钥，DynamoDB 适用于 .NET 的 SDK 的.NET 客户端加密库也需要。AWS KMS随 适用于 .NET 的 SDK NuGet 软件包一起安装。

版本 3。 DynamoDB 的.NET 客户端加密库中的 *x* 支持.NET 6.0 和.NET Framework net48 及更高版本。

## 使用.NET 调试
<a name="ddb-net-debugging"></a>

DynamoDB 的.NET 客户端加密库不会生成任何日志。DynamoDB 的.NET 客户端加密库中的异常会生成异常消息，但不会生成堆栈跟踪。

为了帮助您进行调试，请务必在 适用于 .NET 的 SDK中启用日志记录功能。中的日志和错误消息 适用于 .NET 的 SDK 可以帮助您区分在 DynamoDB 的.NET 客户端加密库中出现的 适用于 .NET 的 SDK 错误和 DynamoDB 的.NET 客户端加密库中出现的错误。有关 适用于 .NET 的 SDK 日志记录的帮助，请参阅[AWSLogging](https://docs.aws.amazon.com/sdk-for-net/latest/developer-guide/net-dg-config-other.html#config-setting-awslogging)《*适用于 .NET 的 AWS SDK 开发人员指南》*。（要查看该主题，请展开 **Open to view .NET Framework content** 部分。）

# 使用适用于 DynamoDB 的.NET 客户端加密库
<a name="ddb-net-using"></a>

本主题解释了版本 3 中的一些函数和辅助类。 DynamoDB 的.NET 客户端加密库中的 *x*。

有关使用适用于 DynamoDB 的.NET 客户端加密库进行编程的详细信息，请参阅上的-dynamodb 存储库中的 [ aws-database-encryption-sdk.NET](https://github.com/aws/aws-database-encryption-sdk-dynamodb/tree/main/Examples/runtimes/net/src/) 示例。 GitHub

**Topics**
+ [项目加密程序](#ddb-net-item-encryptors)
+ [属性操作](#ddb-net-attribute-actions)
+ [加密配置](#ddb-net-config-encrypt)
+ [更新项目](#ddb-net-update-items)

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

DynamoDB AWS 数据库加密 SDK 的核心是一个项目加密器。你可以使用版本 3。 DynamoDB 的.NET 客户端加密库中的 *x*，用于通过以下方式对您的 DynamoDB 表项目进行加密、签名、验证和解密。

**适用于 DynamoDB 的低级 AWS 数据库加密 SDK API**  
您可以使用[表加密配置](#ddb-net-config-encrypt)来构建 DynamoDB 客户端，该客户端会自动使用您的 DynamoDB 请求在客户端对项目进行加密和签名。`PutItem`您可以直接使用此客户端，也可以构造[文档模型](https://docs.aws.amazon.com/sdk-for-net/v3/developer-guide/dynamodb-intro.html#dynamodb-intro-apis-document)或[对象持久化模型](https://docs.aws.amazon.com/sdk-for-net/v3/developer-guide/dynamodb-intro.html#dynamodb-intro-apis-object-persistence)。  
[您必须使用适用于 DynamoDB API 的低级 AWS 数据库加密 SDK 才能使用可搜索的加密。](searchable-encryption.md)

**较低级别的 `DynamoDbItemEncryptor`**  
较低级别的 `DynamoDbItemEncryptor` 无需调用 DynamoDB 即可直接对您的表项目进行加密、签名或解密和验证。它不会发出 DynamoDB `PutItem` 或 `GetItem` 请求。举例来说，您可以使用较低级别的 `DynamoDbItemEncryptor` 直接解密和验证已经检索到的 DynamoDB 项目。如果您使用较低级别`DynamoDbItemEncryptor`，我们建议您使用[低级编程模型，该模型](https://docs.aws.amazon.com/sdk-for-net/v3/developer-guide/dynamodb-intro.html#dynamodb-intro-apis-low-level) 适用于 .NET 的 SDK 用于与 DynamoDB 通信。  
较低级别的 `DynamoDbItemEncryptor` 不支持[可搜索加密](searchable-encryption.md)。

## 适用于 DynamoDB 的 AWS 数据库加密 SDK 中的属性操作
<a name="ddb-net-attribute-actions"></a>

[属性操作](concepts.md#crypt-actions)决定哪些属性值经过加密和签名，哪些仅经过签名，哪些经过签名并包含在加密上下文中，哪些会被忽略。

要使用.NET 客户端指定属性操作，请使用对象模型手动定义属性操作。通过创建一个`Dictionary`对象来指定您的属性操作，其中名称-值对表示属性名称和指定操作。

指定 `ENCRYPT_AND_SIGN` 以对属性进行加密和签名。指定 `SIGN_ONLY` 以对属性进行签名，但不进行加密。指定`SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`对属性进行签名并将其包含在加密上下文中。如果不对属性进行签名，也将无法对其进行加密。指定 `DO_NOTHING` 以忽略某个属性。

分区和排序属性必须为`SIGN_ONLY`或`SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`。如果将任何属性定义为`SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`，则分区和排序属性也必须是`SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`。

**注意**  
定义属性操作后，必须定义将哪些属性排除在签名之外。为了将来更方便添加新的未签名属性，建议您选择一个不同的前缀（例如“`:`”）来标识您的未签名属性。在定义 DynamoDB 架构和属性操作时，将此前缀包含在标记为 `DO_NOTHING` 的所有属性的属性名称中。

以下对象模型演示了如何使用.NET 客户端指定`ENCRYPT_AND_SIGN``SIGN_ONLY``SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`、、和`DO_NOTHING`属性操作。此示例使用前缀 “`:`” 来标识`DO_NOTHING`属性。

**注意**  
要使用`SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`加密操作，必须使用 AWS 数据库加密 SDK 的 3.3 或更高版本。在[更新要包含的数据模型之前，先将](ddb-update-data-model.md)新版本部署给所有读者`SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`。

```
var attributeActionsOnEncrypt = new Dictionary<string, CryptoAction>
{
    ["partition_key"] = CryptoAction.SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT, // The partition attribute must be signed
    ["sort_key"] = CryptoAction.SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT, // The sort attribute must be signed
    ["attribute1"] = CryptoAction.ENCRYPT_AND_SIGN,
    ["attribute2"] = CryptoAction.SIGN_ONLY,
    ["attribute3"] = CryptoAction.SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT,
    [":attribute4"] = CryptoAction.DO_NOTHING
};
```

## 适用于 DynamoDB 的 AWS 数据库加密 SDK 中的加密配置
<a name="ddb-net-config-encrypt"></a>

使用 AWS 数据库加密 SDK 时，必须为 DynamoDB 表显式定义加密配置。加密配置中所需的值取决于您是手动定义属性操作还是使用带注释的数据类来进行定义。

以下代码段使用适用于 DynamoDB API 的 AWS 低级数据库加密 SDK 定义了 DynamoDB 表加密配置，并允许使用不同前缀定义的未签名属性。

```
Dictionary<String, DynamoDbTableEncryptionConfig> tableConfigs =
    new Dictionary<String, DynamoDbTableEncryptionConfig>();
DynamoDbTableEncryptionConfig config = new DynamoDbTableEncryptionConfig
{
    LogicalTableName = ddbTableName,
    PartitionKeyName = "partition_key",
    SortKeyName = "sort_key",
    AttributeActionsOnEncrypt = attributeActionsOnEncrypt,
    Keyring = kmsKeyring,
    AllowedUnsignedAttributePrefix = unsignAttrPrefix,
    // Optional: SearchConfig only required if you use beacons
    Search = new SearchConfig
    {
        WriteVersion = 1, // MUST be 1
        Versions = beaconVersions
    }    
};
tableConfigs.Add(ddbTableName, config);
```

**逻辑表名**  
适用于您的 DynamoDB 表的逻辑表名称。  
为简化 DynamoDB 还原操作，逻辑表名称以加密方式绑定到表中存储的所有数据。强烈建议您在首次定义加密配置时将 DynamoDB 表名指定为逻辑表名。必须始终指定相同的逻辑表名。要成功解密，逻辑表名称必须与加密时所指定的名称相匹配。如果您的 DynamoDB 表名称在[从备份中恢复 DynamoDB 表](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Restore.Tutorial.html)后发生更改，则逻辑表名称可确保解密操作仍能识别该表。

**允许的未签名属性**  
在您的属性操作中标记为 `DO_NOTHING` 的属性。  
允许的未签名属性将告诉客户端哪些属性被排除在签名之外。客户端假设，所有的其他属性都包含在签名中。然后，在解密记录时，客户端会从您指定的允许的未签名属性中确定需要验证哪些属性以及需要忽略哪些属性。您将不能从允许的未签名属性中移除属性。  
您可以通过创建一个列出所有 `DO_NOTHING` 属性的数组来显式定义允许的未签名属性。您还可以在命名 `DO_NOTHING` 属性时指定不同的前缀，并使用前缀告诉客户端哪些属性未签名。强烈建议指定一个不同的前缀，因为它可以简化未来添加新的 `DO_NOTHING` 属性的过程。有关更多信息，请参阅 [更新您的数据模型](ddb-update-data-model.md)。  
如果您没有为所有 `DO_NOTHING` 属性指定前缀，可以配置一个 `allowedUnsignedAttributes` 数组，该数组将显式列出客户端在解密时遇到这些属性时应该取消签名的所有属性。您只有在绝对必要时，才应显式定义允许的未签名属性。

**搜索配置（可选）**  
`SearchConfig` 将定义[信标版本](using-beacons.md#beacon-version)。  
必须指定 `SearchConfig` 才能使用[可搜索的加密](searchable-encryption.md)或[签名信标](configure.md#signed-beacons)。

**算法套件（可选）**  
`algorithmSuiteId` 定义 AWS 数据库加密 SDK 使用哪种算法套件。  
除非您明确指定替代算法套件，否则 AWS 数据库加密 SDK 将使用[默认算法套件](supported-algorithms.md#recommended-algorithms)。默认算法套件将 AES-GCM 算法与密钥派生、[数字签名](concepts.md#digital-sigs)和[密钥承诺](concepts.md#key-commitment)结合使用。尽管默认算法套件可能适用于大多数应用程序，但您可以选择备用算法套件。例如，没有数字签名的算法套件可以满足某些信任模型的需求。有关 AWS 数据库加密 SDK 支持的算法套件的信息，请参阅[AWS 数据库加密 SDK 中支持的算法套件](supported-algorithms.md)。  
要选择[没有 ECDSA 数字签名的 AES-GCM 算法套件](supported-algorithms.md#other-algorithms)，请在表加密配置中加入以下片段。  

```
AlgorithmSuiteId = DBEAlgorithmSuiteId.ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEY_SYMSIG_HMAC_SHA384
```

## 使用 AWS 数据库加密 SDK 更新项目
<a name="ddb-net-update-items"></a>

UpdateItem对于包含加密或签名属性的项目，[数据库加密 SDK 不支持 ddb:](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_UpdateItem.html)。 AWS 要更新加密或已签名的属性，必须使用 [ddb: PutItem](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_PutItem.html)。如果将同一个主键指定为 `PutItem` 请求中现有的项目，则新项目将完全替代现有项目。更新项目后，您还可以使用 [CLOBBER](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/dynamodbv2/datamodeling/DynamoDBMapperConfig.SaveBehavior.html#CLOBBER) 在保存时清除和替换所有属性。

# .NET 示
<a name="ddb-net-examples"></a>

以下示例向您展示如何使用适用于 DynamoDB 的.NET 客户端加密库来保护应用程序中的表项目。要查找更多示例（并贡献自己的示例），请参阅上的 aws-database-encryption-sdk-dy [namodb 存储库中的.NET 示例](https://github.com/aws/aws-database-encryption-sdk-dynamodb//tree/main/Examples/runtimes/net/src)。 GitHub

以下示例演示了如何在未填充的全新 Amazon DynamoDB 表中为 DynamoDB 配置.NET 客户端加密库。如果您想配置现有的 Amazon DynamoDB 表以进行客户端加密，请参阅 [将版本 3.x 添加到现有表](ddb-net-config-existing-table.md)。

**Topics**
+ [使用适用于 DynamoDB 的低级 AWS 数据库加密 SDK API](#ddb-net-lowlevel-API-example)
+ [使用较低的级别 `DynamoDbItemEncryptor`](#ddb-net-itemencryptor)

## 使用适用于 DynamoDB 的低级 AWS 数据库加密 SDK API
<a name="ddb-net-lowlevel-API-example"></a>

[以下示例说明如何使用适用于 DynamoDB 的低级 AWS 数据库加密 SDK API 和密钥环，通过AWS KMS 您的 DynamoDB 请求在客户端自动加密和签名项目。](use-kms-keyring.md) `PutItem`

您可以使用任何支持的[密钥环](keyrings.md)，但我们建议尽可能使用其中一个 AWS KMS 密钥环。

**查看完整的代码示例**：[BasicPutGetExample.cs](https://github.com/aws/aws-database-encryption-sdk-dynamodb/tree/main/Examples/runtimes/net/src/BasicPutGetExample.cs)

**步骤 1：创建 AWS KMS 密钥环**  
以下示例使用`CreateAwsKmsMrkMultiKeyring`对称加密 KMS AWS KMS 密钥创建密钥环。`CreateAwsKmsMrkMultiKeyring` 方法可确保密钥环能够正确处理单区域密钥和多区域密钥。  

```
var matProv = new MaterialProviders(new MaterialProvidersConfig());
var keyringInput = new CreateAwsKmsMrkMultiKeyringInput { Generator = kmsKeyId };
var kmsKeyring = matProv.CreateAwsKmsMrkMultiKeyring(keyringInput);
```

**步骤 2：配置属性操作**  
以下示例定义了一个`attributeActionsOnEncrypt`字典，该字典表示表格项目的示例[属性操作](concepts.md#crypt-actions)。  
以下示例未将任何属性定义为`SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`。如果您指定了任何`SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`属性，则分区和排序属性也必须是`SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`。

```
var attributeActionsOnEncrypt = new Dictionary<string, CryptoAction>
{
    ["partition_key"] = CryptoAction.SIGN_ONLY, // The partition attribute must be SIGN_ONLY
    ["sort_key"] = CryptoAction.SIGN_ONLY, // The sort attribute must be SIGN_ONLY
    ["attribute1"] = CryptoAction.ENCRYPT_AND_SIGN,
    ["attribute2"] = CryptoAction.SIGN_ONLY,
    [":attribute3"] = CryptoAction.DO_NOTHING
};
```

**步骤 3：定义从签名中可以排除哪些属性**  
以下示例假设所有 `DO_NOTHING` 属性共享不同的前缀“`:`”，并使用该前缀定义允许的未签名属性。客户端假设任何带有“`:`”前缀的属性名称都被排除在签名之外。有关更多信息，请参阅 [Allowed unsigned attributes](ddb-net-using.md#net-allowed-unauth)。  

```
const String unsignAttrPrefix = ":";
```

**步骤 4：定义 DynamoDB 表的加密配置**  
以下示例定义了一个 `tableConfigs` 映射，该映射表示此 DynamoDB 表的加密配置。  
此示例将 DynamoDB 表名称指定为[逻辑表名称](ddb-net-using.md#net-logical-table-name)。强烈建议您在首次定义加密配置时将 DynamoDB 表名指定为逻辑表名。有关更多信息，请参阅 [适用于 DynamoDB 的 AWS 数据库加密 SDK 中的加密配置](ddb-net-using.md#ddb-net-config-encrypt)。  
要使用[可搜索的加密](searchable-encryption.md)或[签名信标](configure.md#signed-beacons)，您还必须在加密配置中包括 [`SearchConfig`](ddb-java-using.md#ddb-search-config)。

```
Dictionary<String, DynamoDbTableEncryptionConfig> tableConfigs =
    new Dictionary<String, DynamoDbTableEncryptionConfig>();
DynamoDbTableEncryptionConfig config = new DynamoDbTableEncryptionConfig
{
    LogicalTableName = ddbTableName,
    PartitionKeyName = "partition_key",
    SortKeyName = "sort_key",
    AttributeActionsOnEncrypt = attributeActionsOnEncrypt,
    Keyring = kmsKeyring,
    AllowedUnsignedAttributePrefix = unsignAttrPrefix
};
tableConfigs.Add(ddbTableName, config);
```

**第 5 步：创建新的 AWS SDK DynamoDB 客户端**  
**以下示例使用步骤 4 中的创建了一个新 AWS 的 SDK DynamoDB 客户端`TableEncryptionConfigs`。**  

```
var ddb = new Client.DynamoDbClient(
    new DynamoDbTablesEncryptionConfig { TableEncryptionConfigs = tableConfigs });
```

**步骤 6：对 DynamoDB 表格项目进行加密和签名**  
以下示例定义了一个代表示例表项目的`item`字典，并将该项目放入 DynamoDB 表中。该项目在发送到 DynamoDB 之前将在客户端进行加密和签名。  

```
var item = new Dictionary<String, AttributeValue>
{
    ["partition_key"] = new AttributeValue("BasicPutGetExample"),
    ["sort_key"] = new AttributeValue { N = "0" },
    ["attribute1"] = new AttributeValue("encrypt and sign me!"),
    ["attribute2"] = new AttributeValue("sign me!"),
    [":attribute3"] = new AttributeValue("ignore me!")
};

PutItemRequest putRequest = new PutItemRequest
{
    TableName = ddbTableName,
    Item = item
};

PutItemResponse putResponse = await ddb.PutItemAsync(putRequest);
```

## 使用较低的级别 `DynamoDbItemEncryptor`
<a name="ddb-net-itemencryptor"></a>

以下示例说明如何使用带有 [AWS KMS 密钥环](use-kms-keyring.md)的较低级别 `DynamoDbItemEncryptor` 来直接对表项目进行加密和签名。`DynamoDbItemEncryptor` 不会将项目放入 DynamoDB 表中。

您可以在 DynamoDB 增强版客户端中使用任何支持的[密钥环](keyrings.md)，但我们建议尽可能使用其中 AWS KMS 一个密钥环。

**注意**  
较低级别的 `DynamoDbItemEncryptor` 不支持[可搜索加密](searchable-encryption.md)。使用适用于 DynamoDB 的低级 AWS 数据库加密 SDK API 来使用可搜索的加密。

**查看完整的代码示例**：[ItemEncryptDecryptExample.cs](https://github.com/aws/aws-database-encryption-sdk-dynamodb/tree/main/Examples/runtimes/net/src/itemencryptor/ItemEncryptDecryptExample.cs)

**步骤 1：创建 AWS KMS 密钥环**  
以下示例使用`CreateAwsKmsMrkMultiKeyring`对称加密 KMS AWS KMS 密钥创建密钥环。`CreateAwsKmsMrkMultiKeyring` 方法可确保密钥环能够正确处理单区域密钥和多区域密钥。  

```
var matProv = new MaterialProviders(new MaterialProvidersConfig());
var keyringInput = new CreateAwsKmsMrkMultiKeyringInput { Generator = kmsKeyId };
var kmsKeyring = matProv.CreateAwsKmsMrkMultiKeyring(keyringInput);
```

**步骤 2：配置属性操作**  
以下示例定义了一个`attributeActionsOnEncrypt`字典，该字典表示表格项目的示例[属性操作](concepts.md#crypt-actions)。  
以下示例未将任何属性定义为`SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`。如果您指定了任何`SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`属性，则分区和排序属性也必须是`SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`。

```
var attributeActionsOnEncrypt = new Dictionary<String, CryptoAction>
{
    ["partition_key"] = CryptoAction.SIGN_ONLY, // The partition attribute must be SIGN_ONLY
    ["sort_key"] = CryptoAction.SIGN_ONLY, // The sort attribute must be SIGN_ONLY
    ["attribute1"] = CryptoAction.ENCRYPT_AND_SIGN,
    ["attribute2"] = CryptoAction.SIGN_ONLY,
    [":attribute3"] = CryptoAction.DO_NOTHING
};
```

**步骤 3：定义从签名中可以排除哪些属性**  
以下示例假设所有 `DO_NOTHING` 属性共享不同的前缀“`:`”，并使用该前缀定义允许的未签名属性。客户端假设任何带有“`:`”前缀的属性名称都被排除在签名之外。有关更多信息，请参阅 [Allowed unsigned attributes](ddb-net-using.md#net-allowed-unauth)。  

```
String unsignAttrPrefix = ":";
```

**步骤 4：定义 `DynamoDbItemEncryptor` 配置**  
以下示例定义 `DynamoDbItemEncryptor` 的配置。  
此示例将 DynamoDB 表名称指定为[逻辑表名称](ddb-net-using.md#net-logical-table-name)。强烈建议您在首次定义加密配置时将 DynamoDB 表名指定为逻辑表名。有关更多信息，请参阅 [适用于 DynamoDB 的 AWS 数据库加密 SDK 中的加密配置](ddb-net-using.md#ddb-net-config-encrypt)。  

```
var config = new DynamoDbItemEncryptorConfig
{
    LogicalTableName = ddbTableName,
    PartitionKeyName = "partition_key",
    SortKeyName = "sort_key",
    AttributeActionsOnEncrypt = attributeActionsOnEncrypt,
    Keyring = kmsKeyring,
    AllowedUnsignedAttributePrefix = unsignAttrPrefix
};
```

**步骤 5：创建 `DynamoDbItemEncryptor`**  
以下示例使用**步骤 4** 中的 `config` 创建新的 `DynamoDbItemEncryptor`。  

```
var itemEncryptor = new DynamoDbItemEncryptor(config);
```

**步骤 6：直接对表项目进行加密和签名**  
以下示例使用 `DynamoDbItemEncryptor` 直接对项目进行加密和签名。`DynamoDbItemEncryptor` 不会将项目放入 DynamoDB 表中。  

```
var originalItem = new Dictionary<String, AttributeValue>
{
    ["partition_key"] = new AttributeValue("ItemEncryptDecryptExample"),
    ["sort_key"] = new AttributeValue { N = "0" },
    ["attribute1"] = new AttributeValue("encrypt and sign me!"),
    ["attribute2"] = new AttributeValue("sign me!"),
    [":attribute3"] = new AttributeValue("ignore me!")
};

var encryptedItem = itemEncryptor.EncryptItem(
    new EncryptItemInput { PlaintextItem = originalItem }
).EncryptedItem;
```

# 将现有 DynamoDB 表配置为使用适用于 DynamoDB AWS 的数据库加密 SDK
<a name="ddb-net-config-existing-table"></a>

使用版本 3。 *x* 在 DynamoDB 的.NET 客户端加密库中，您可以将现有的 Amazon DynamoDB 表配置为用于客户端加密。本主题提供有关添加版本 3.*x* 到已填充的现有 DynamoDB 表要采取的三个步骤的指导。

## 步骤 1：准备读取和写入加密项目
<a name="ddb-net-add-step1"></a>

完成以下步骤，为 AWS 数据库加密 SDK 客户端做好读取和写入加密项目的准备。部署以下更改后，您的客户端将继续读取和写入明文项目。它不会对写入表中的任何新项目进行加密或签名，但却能够在加密项目显示后立即对其进行解密。这些更改使得客户端为开始[加密新项目](#ddb-net-add-step2)做好准备。在继续执行下一步操作之前，必须将以下更改部署到每一个读取器。

**1. 定义您的[属性操作](concepts.md#crypt-actions)**  
创建对象模型以定义哪些属性值将进行加密和签名，哪些仅进行签名，哪些将被忽略。  
默认情况下，主键属性已签名但未加密（`SIGN_ONLY`），而所有其他属性均经过加密和签名（`ENCRYPT_AND_SIGN`）。  
指定 `ENCRYPT_AND_SIGN` 以对属性进行加密和签名。指定 `SIGN_ONLY` 以对属性进行签名，但不进行加密。指定`SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`要签名并归因并将其包含在加密上下文中。如果不对属性进行签名，也将无法对其进行加密。指定 `DO_NOTHING` 以忽略某个属性。有关更多信息，请参阅 [适用于 DynamoDB 的 AWS 数据库加密 SDK 中的属性操作](ddb-net-using.md#ddb-net-attribute-actions)。  
如果您指定了任何`SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`属性，则分区和排序属性也必须是`SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`。

```
var attributeActionsOnEncrypt = new Dictionary<string, CryptoAction>
{
    ["partition_key"] = CryptoAction.SIGN_ONLY, // The partition attribute must be SIGN_ONLY
    ["sort_key"] = CryptoAction.SIGN_ONLY, // The sort attribute must be SIGN_ONLY
    ["attribute1"] = CryptoAction.ENCRYPT_AND_SIGN,
    ["attribute2"] = CryptoAction.SIGN_ONLY,
    [":attribute3"] = CryptoAction.DO_NOTHING
};
```

**2. 定义从签名中将可以排除哪些属性**  
以下示例假设所有 `DO_NOTHING` 属性共享不同的前缀“`:`”，并使用该前缀定义允许的未签名属性。客户端将假设任何带有“`:`”前缀的属性名称都被排除在签名之外。有关更多信息，请参阅 [Allowed unsigned attributes](ddb-net-using.md#net-allowed-unauth)。  

```
const String unsignAttrPrefix = ":";
```

**3. 创建[密钥环](keyrings.md)**  
以下示例创建一个 [AWS KMS 密钥环](use-kms-keyring.md)。 AWS KMS 密钥环使用对称加密或非对称 RSA AWS KMS keys 来生成、加密和解密数据密钥。  
该示例使用 `CreateMrkMultiKeyring` 创建带有对称加密 KMS 密钥的 AWS KMS 密钥环。`CreateAwsKmsMrkMultiKeyring` 方法可确保密钥环能够正确处理单区域密钥和多区域密钥。  

```
var matProv = new MaterialProviders(new MaterialProvidersConfig());
var keyringInput = new CreateAwsKmsMrkMultiKeyringInput { Generator = kmsKeyId };
var kmsKeyring = matProv.CreateAwsKmsMrkMultiKeyring(keyringInput);
```

**4. 定义 DynamoDB 表的加密配置 **  
以下示例定义了一个 `tableConfigs` 映射，该映射表示此 DynamoDB 表的加密配置。  
此示例将 DynamoDB 表名称指定为[逻辑表名称](ddb-net-using.md#net-logical-table-name)。强烈建议您在首次定义加密配置时将 DynamoDB 表名指定为逻辑表名。  
必须指定 `FORCE_WRITE_PLAINTEXT_ALLOW_READ_PLAINTEXT` 作为明文替代。此策略继续读取和写入明文项目，读取加密项目，并使客户端做好准备以写入加密项目。  
有关表加密配置中包含的值的更多信息，请参阅[适用于 DynamoDB 的 AWS 数据库加密 SDK 中的加密配置](ddb-java-using.md#ddb-config-encrypt)。  

```
Dictionary<String, DynamoDbTableEncryptionConfig> tableConfigs =
    new Dictionary<String, DynamoDbTableEncryptionConfig>();
DynamoDbTableEncryptionConfig config = new DynamoDbTableEncryptionConfig
{
    LogicalTableName = ddbTableName,
    PartitionKeyName = "partition_key",
    SortKeyName = "sort_key",
    AttributeActionsOnEncrypt = attributeActionsOnEncrypt,
    Keyring = kmsKeyring,
    AllowedUnsignedAttributePrefix = unsignAttrPrefix,
    PlaintextOverride = FORCE_WRITE_PLAINTEXT_ALLOW_READ_PLAINTEXT
};
tableConfigs.Add(ddbTableName, config);
```

**5. 创建新的 AWS SDK DynamoDB 客户端**  
**以下示例使用步骤 4 中的创建了一个新 AWS 的 SDK DynamoDB 客户端`TableEncryptionConfigs`。**  

```
var ddb = new Client.DynamoDbClient(
    new DynamoDbTablesEncryptionConfig { TableEncryptionConfigs = tableConfigs });
```

## 步骤 2：写入已加密和签名项目
<a name="ddb-net-add-step2"></a>

更新表加密配置中的明文策略，以允许客户端写入加密和签名的项目。部署好以下更改后，客户端将根据您在**步骤 1** 中配置的属性操作对新项目进行加密和签名。客户将能够读取明文项目以及已加密和签名的项目。

在继续执行[步骤 3](#ddb-net-add-step3) 之前，您必须对表格中所有现有的明文项目进行加密和签名。您无法运行单一指标或查询来快速加密您的现有明文项目。使用对您的系统最有意义的过程。例如，您可以使用异步过程，以缓慢扫描表，然后使用您定义的属性操作和加密配置重写项目。要识别表中的纯文本项目，我们建议您扫描所有不包含 AWS 数据库加密 SDK 在项目加密`aws_dbe_head`和签名时添加的和`aws_dbe_foot`属性的项目。

以下示例更新了**步骤 1** 中的表加密配置。您必须使用 `FORBID_WRITE_PLAINTEXT_ALLOW_READ_PLAINTEXT` 更新明文替代。该策略继续读取明文项目，但也会读取和写入加密项目。使用更新后的 AWS DynamoDB 客户端创建一个新的 SDK DynamoDB 客户端。`TableEncryptionConfigs`

```
Dictionary<String, DynamoDbTableEncryptionConfig> tableConfigs =
    new Dictionary<String, DynamoDbTableEncryptionConfig>();
DynamoDbTableEncryptionConfig config = new DynamoDbTableEncryptionConfig
{
    LogicalTableName = ddbTableName,
    PartitionKeyName = "partition_key",
    SortKeyName = "sort_key",
    AttributeActionsOnEncrypt = attributeActionsOnEncrypt,
    Keyring = kmsKeyring,
    AllowedUnsignedAttributePrefix = unsignAttrPrefix,
    PlaintextOverride = FORBID_WRITE_PLAINTEXT_ALLOW_READ_PLAINTEXT
};
tableConfigs.Add(ddbTableName, config);
```

## 步骤 3：仅读取已加密和签名项目
<a name="ddb-net-add-step3"></a>

对所有项目进行加密和签名后，请更新表加密配置中的明文替代，使其仅允许客户端读取和写入加密和签名的项目。部署好以下更改后，客户端将根据您在**步骤 1** 中配置的属性操作对新项目进行加密和签名。客户只能够读取已加密和签名的项目。

以下示例更新了**步骤 2** 中的表加密配置。您可以使用 `FORBID_WRITE_PLAINTEXT_FORBID_READ_PLAINTEXT` 更新明文替代，也可以从配置中移除明文策略。默认情况下，客户端仅读取和写入已加密和签名的项目。使用更新后的 AWS DynamoDB 客户端创建一个新的 SDK DynamoDB 客户端。`TableEncryptionConfigs`

```
Dictionary<String, DynamoDbTableEncryptionConfig> tableConfigs =
    new Dictionary<String, DynamoDbTableEncryptionConfig>();
DynamoDbTableEncryptionConfig config = new DynamoDbTableEncryptionConfig
{
    LogicalTableName = ddbTableName,
    PartitionKeyName = "partition_key",
    SortKeyName = "sort_key",
    AttributeActionsOnEncrypt = attributeActionsOnEncrypt,
    Keyring = kmsKeyring,
    AllowedUnsignedAttributePrefix = unsignAttrPrefix,
    // Optional: you can also remove the plaintext policy from your configuration
    PlaintextOverride = FORBID_WRITE_PLAINTEXT_FORBID_READ_PLAINTEXT
};
tableConfigs.Add(ddbTableName, config);
```

# Rust
<a name="ddb-rust"></a>

本主题介绍如何安装和使用版本 1。 适用于 DynamoDB 的 Rust 客户端加密库中的 *x*。有关使用适用于 DynamoDB 的 AWS 数据库加密 SDK 进行编程的详细信息，请参阅上的-dynamodb 存储库[中的 aws-database-encryption-sdk Rust](https://github.com/aws/aws-database-encryption-sdk-dynamodb/blob/main/releases/rust/db_esdk/examples/) 示例。 GitHub

适用于 DynamoDB 的 AWS 数据库加密 SDK 的所有编程语言实现均可互操作。

**Topics**
+ [先决条件](#ddb-rust-prerequisites)
+ [安装](#ddb-rust-install)
+ [使用 Rust 客户端](ddb-rust-using.md)

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

在安装适用于 DynamoDB 的 Rust 客户端加密库之前，请确保满足以下先决条件。

**安装 Rust 和 Cargo**  
使用 [r](https://rustup.rs/) ustup 安装当前稳定版本的 [Rust](https://www.rust-lang.org/)。  
有关下载和安装 rustup 的更多信息，请参阅《货运手册》中的[安装程序](https://doc.rust-lang.org/cargo/getting-started/installation.html)。

## 安装
<a name="ddb-rust-install"></a>

适用于 DynamoDB 的 Rust 客户端加密库在 Crates.io 上以箱子形式[aws-db-esdk](https://crates.io/crates/aws-db-esdk)提供。有关安装和构建库的详细信息，请参阅-dynamodb 存储库中的 [README.md](https://github.com/aws/aws-database-encryption-sdk-dynamodb/) 文件。 aws-database-encryption-sdk GitHub 

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

**安装最新版本**  
在您的项目目录中运行以下 Cargo 命令：  

```
cargo add aws-db-esdk
```
或者在你的 Cargo.toml 中添加以下一行：  

```
aws-db-esdk = "<version>"
```

# 使用 DynamoDB 的 Rust 客户端加密库
<a name="ddb-rust-using"></a>

本主题解释了版本 1 中的一些函数和辅助类。 适用于 DynamoDB 的 Rust 客户端加密库中的 *x*。

有关使用适用于 DynamoDB 的 Rust 客户端加密库进行编程的详细信息，请参阅上的-dynamodb 存储库[中的 aws-database-encryption-sdk Rust](https://github.com/aws/aws-database-encryption-sdk-dynamodb/blob/main/releases/rust/db_esdk/examples/) 示例。 GitHub

**Topics**
+ [项目加密程序](#ddb-rust-item-encryptors)
+ [属性操作](#ddb-rust-attribute-actions)
+ [加密配置](#ddb-rust-config-encrypt)
+ [更新项目](#ddb-rust-update-items)

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

DynamoDB AWS 数据库加密 SDK 的核心是一个项目加密器。你可以使用版本 1。 DynamoDB 的 Rust 客户端加密库中的 *x*，用于通过以下方式对您的 DynamoDB 表项目进行加密、签名、验证和解密。

**适用于 DynamoDB 的低级 AWS 数据库加密 SDK API**  
您可以使用[表加密配置](#ddb-rust-config-encrypt)来构建 DynamoDB 客户端，该客户端会自动使用您的 DynamoDB 请求在客户端对项目进行加密和签名。`PutItem`  
[您必须使用适用于 DynamoDB API 的低级 AWS 数据库加密 SDK 才能使用可搜索的加密。](searchable-encryption.md)  
有关演示如何使用适用于 DynamoDB API 的低级 AWS 数据库加密 SDK 的示例，[请参阅](https://github.com/aws/aws-database-encryption-sdk-dynamodb/blob/main/releases/rust/db_esdk/examples/basic_get_put_example.rs)上的-dynamodb 存储库中的 basic\$1get\$1put\$1example.rs。 aws-database-encryption-sdk GitHub

**较低级别的 `DynamoDbItemEncryptor`**  
较低级别的 `DynamoDbItemEncryptor` 无需调用 DynamoDB 即可直接对您的表项目进行加密、签名或解密和验证。它不会发出 DynamoDB `PutItem` 或 `GetItem` 请求。举例来说，您可以使用较低级别的 `DynamoDbItemEncryptor` 直接解密和验证已经检索到的 DynamoDB 项目。  
较低级别的 `DynamoDbItemEncryptor` 不支持[可搜索加密](searchable-encryption.md)。  
有关演示如何使用较低级别`DynamoDbItemEncryptor`的示例，请参阅上的-dynamodb [存储库中的 item\$1encrypt\$1decryp](https://github.com/aws/aws-database-encryption-sdk-dynamodb/blob/main/releases/rust/db_esdk/examples/itemencryptor/item_encrypt_decrypt.rs) t.rs。 aws-database-encryption-sdk GitHub

## 适用于 DynamoDB 的 AWS 数据库加密 SDK 中的属性操作
<a name="ddb-rust-attribute-actions"></a>

[属性操作](concepts.md#crypt-actions)决定哪些属性值经过加密和签名，哪些仅经过签名，哪些经过签名并包含在加密上下文中，哪些会被忽略。

要使用 Rust 客户端指定属性操作，请使用对象模型手动定义属性操作。通过创建一个`HashMap`对象来指定您的属性操作，其中名称-值对表示属性名称和指定操作。

指定 `ENCRYPT_AND_SIGN` 以对属性进行加密和签名。指定 `SIGN_ONLY` 以对属性进行签名，但不进行加密。指定`SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`对属性进行签名并将其包含在加密上下文中。如果不对属性进行签名，也将无法对其进行加密。指定 `DO_NOTHING` 以忽略某个属性。

分区和排序属性必须为`SIGN_ONLY`或`SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`。如果将任何属性定义为`SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`，则分区和排序属性也必须是`SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`。

**注意**  
定义属性操作后，必须定义将哪些属性排除在签名之外。为了将来更方便添加新的未签名属性，建议您选择一个不同的前缀（例如“`:`”）来标识您的未签名属性。在定义 DynamoDB 架构和属性操作时，将此前缀包含在标记为 `DO_NOTHING` 的所有属性的属性名称中。

以下对象模型演示了如何使用 Rust 客户端指定`ENCRYPT_AND_SIGN``SIGN_ONLY``SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`、、和`DO_NOTHING`属性操作。此示例使用前缀 “`:`” 来标识`DO_NOTHING`属性。

```
let attribute_actions_on_encrypt = HashMap::from([
    ("partition_key".to_string(), CryptoAction::SignOnly),
    ("sort_key".to_string(), CryptoAction::SignOnly),
    ("attribute1".to_string(), CryptoAction::EncryptAndSign),
    ("attribute2".to_string(), CryptoAction::SignOnly),
    (":attribute3".to_string(), CryptoAction::DoNothing),
]);
```

## 适用于 DynamoDB 的 AWS 数据库加密 SDK 中的加密配置
<a name="ddb-rust-config-encrypt"></a>

使用 AWS 数据库加密 SDK 时，必须为 DynamoDB 表显式定义加密配置。加密配置中所需的值取决于您是手动定义属性操作还是使用带注释的数据类来进行定义。

以下代码段使用适用于 DynamoDB API 的 AWS 低级数据库加密 SDK 定义了 DynamoDB 表加密配置，并允许使用由不同前缀定义的未签名属性。

```
let table_config = DynamoDbTableEncryptionConfig::builder()
    .logical_table_name(ddb_table_name)
    .partition_key_name("partition_key")
    .sort_key_name("sort_key")
    .attribute_actions_on_encrypt(attribute_actions_on_encrypt)
    .keyring(kms_keyring)
    .allowed_unsigned_attribute_prefix(UNSIGNED_ATTR_PREFIX)
    // Specifying an algorithm suite is optional
    .algorithm_suite_id(
        DbeAlgorithmSuiteId::AlgAes256GcmHkdfSha512CommitKeyEcdsaP384SymsigHmacSha384,
    )
    .build()?;

let table_configs = DynamoDbTablesEncryptionConfig::builder()
    .table_encryption_configs(HashMap::from([(ddb_table_name.to_string(), table_config)]))
    .build()?;
```

**逻辑表名**  
适用于您的 DynamoDB 表的逻辑表名称。  
为简化 DynamoDB 还原操作，逻辑表名称以加密方式绑定到表中存储的所有数据。强烈建议您在首次定义加密配置时将 DynamoDB 表名指定为逻辑表名。必须始终指定相同的逻辑表名。要成功解密，逻辑表名称必须与加密时所指定的名称相匹配。如果您的 DynamoDB 表名称在[从备份中恢复 DynamoDB 表](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Restore.Tutorial.html)后发生更改，则逻辑表名称可确保解密操作仍能识别该表。

**允许的未签名属性**  
在您的属性操作中标记为 `DO_NOTHING` 的属性。  
允许的未签名属性将告诉客户端哪些属性被排除在签名之外。客户端假设，所有的其他属性都包含在签名中。然后，在解密记录时，客户端会从您指定的允许的未签名属性中确定需要验证哪些属性以及需要忽略哪些属性。您将不能从允许的未签名属性中移除属性。  
您可以通过创建一个列出所有 `DO_NOTHING` 属性的数组来显式定义允许的未签名属性。您还可以在命名 `DO_NOTHING` 属性时指定不同的前缀，并使用前缀告诉客户端哪些属性未签名。强烈建议指定一个不同的前缀，因为它可以简化未来添加新的 `DO_NOTHING` 属性的过程。有关更多信息，请参阅 [更新您的数据模型](ddb-update-data-model.md)。  
如果您没有为所有 `DO_NOTHING` 属性指定前缀，可以配置一个 `allowedUnsignedAttributes` 数组，该数组将显式列出客户端在解密时遇到这些属性时应该取消签名的所有属性。您只有在绝对必要时，才应显式定义允许的未签名属性。

**搜索配置（可选）**  
`SearchConfig` 将定义[信标版本](using-beacons.md#beacon-version)。  
必须指定 `SearchConfig` 才能使用[可搜索的加密](searchable-encryption.md)或[签名信标](configure.md#signed-beacons)。

**算法套件（可选）**  
`algorithmSuiteId` 定义 AWS 数据库加密 SDK 使用哪种算法套件。  
除非您明确指定替代算法套件，否则 AWS 数据库加密 SDK 将使用[默认算法套件](supported-algorithms.md#recommended-algorithms)。默认算法套件将 AES-GCM 算法与密钥派生、[数字签名](concepts.md#digital-sigs)和[密钥承诺](concepts.md#key-commitment)结合使用。尽管默认算法套件可能适用于大多数应用程序，但您可以选择备用算法套件。例如，没有数字签名的算法套件可以满足某些信任模型的需求。有关 AWS 数据库加密 SDK 支持的算法套件的信息，请参阅[AWS 数据库加密 SDK 中支持的算法套件](supported-algorithms.md)。  
要选择[没有 ECDSA 数字签名的 AES-GCM 算法套件](supported-algorithms.md#other-algorithms)，请在表加密配置中加入以下片段。  

```
.algorithm_suite_id(
    DbeAlgorithmSuiteId::AlgAes256GcmHkdfSha512CommitKeyEcdsaP384SymsigHmacSha384,
)
```

## 使用 AWS 数据库加密 SDK 更新项目
<a name="ddb-rust-update-items"></a>

UpdateItem对于包含加密或签名属性的项目，[数据库加密 SDK 不支持 ddb:](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_UpdateItem.html)。 AWS 要更新加密或已签名的属性，必须使用 [ddb: PutItem](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_PutItem.html)。如果将同一个主键指定为 `PutItem` 请求中现有的项目，则新项目将完全替代现有项目。

# 旧版 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)。