

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

# 使用适用于 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`，请不要使用表名称覆盖运算符。而是使用原始表名称创建一个加密上下文，并将其提交给解密方法。