

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

# 使用适用于 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 的详细信息。