

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

# 使用適用於 Java 的 DynamoDB 加密用戶端
<a name="java-using"></a>

**注意**  
我們的用戶端加密程式庫已[重新命名為 AWS 資料庫加密 SDK](DDBEC-rename.md)。下列主題提供有關適用於 Java 的 DynamoDB 加密用戶端 1.*x*-2.*x* 版和適用於 Python 的 DynamoDB 加密用戶端 1.*x*-3.*x* 版的資訊。如需詳細資訊，請參閱[AWS 資料庫加密 SDK for DynamoDB 版本支援](legacy-dynamodb-encryption-client.md#legacy-support)。

本主題說明在 Java 中可能無法在其他程式設計語言實作中找到的 DynamoDB 加密用戶端的一些功能。

如需使用 DynamoDB 加密用戶端進行程式設計的詳細資訊，請參閱 [Java 範例](java-examples.md)、GitHub `aws-dynamodb-encryption-java repository`上 中[的範例](https://github.com/aws/aws-dynamodb-encryption-java/tree/master/examples)，以及 DynamoDB 加密用戶端的 [Javadoc](https://aws.github.io/aws-dynamodb-encryption-java/)。



**Topics**
+ [項目加密程式](#attribute-encryptor)
+ [設定儲存行為](#save-behavior)
+ [Java 中的屬性動作](#attribute-actions-java)
+ [覆寫表格名稱](#override-table-name)

## 項目加密程式：AttributeEncryptor 和 DynamoDBEncryptor
<a name="attribute-encryptor"></a>

Java 中的 DynamoDB 加密用戶端有兩個[項目加密程式](DDBEC-legacy-concepts.md#item-encryptor)：較低層級的 [DynamoDBEncryptor](https://aws.github.io/aws-dynamodb-encryption-java/com/amazonaws/services/dynamodbv2/datamodeling/encryption/DynamoDBEncryptor.html) 和 [AttributeEncryptor](#attribute-encryptor)。

`AttributeEncryptor` 是一種協助程式類別，可協助您在 DynamoDB 加密用戶端的 中使用 [DynamoDBMapper](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBMapper.Methods.html) 適用於 Java 的 AWS SDK 與 。 `DynamoDB Encryptor` DynamoDB 當您搭配 `DynamoDBMapper` 使用 `AttributeEncryptor` 時，它會在您保存項目時，透明地加密和簽署您的項目。當您載入項目時，它也會透明地驗證和解密您的項目。

## 設定儲存行為
<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`或 的儲存行為`DynamoDBMapper`的 搭配使用，則 DynamoDB Encryption Client 會擲回執行期例外狀況`PUT`。

若要查看範例中使用的此程式碼，請參閱 [使用 DynamoDBMapper](java-examples.md#java-example-dynamodb-mapper)和 GitHub 中`aws-dynamodb-encryption-java`儲存庫中的 [AwsKmsEncryptedObject.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`，還是較低層層級的 [DynamoDBEncryptor](https://aws.github.io/aws-dynamodb-encryption-java/com/amazonaws/services/dynamodbv2/datamodeling/encryption/DynamoDBEncryptor.html)。

**重要**  
使用屬性動作加密表格項目後，從資料模型新增或移除屬性可能會導致簽章驗證錯誤，讓您無法解密資料。如需更詳細的說明，請參閱[變更您的資料模型](data-model.md)。

### DynamoDBMapper 的屬性動作
<a name="attribute-action-java-mapper"></a>

當您使用 `DynamoDBMapper` 和 `AttributeEncryptor` 時，您可使用註釋來指定屬性動作。DynamoDB 加密用戶端使用[標準 DynamoDB 屬性註釋](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBMapper.Annotations.html)來定義屬性類型，以判斷如何保護屬性。除了主要索引鍵 (簽署但不加密) 以外，所有屬性都預設會進行加密和簽署。

**注意**  
雖然您可以 (而且應該) 簽署屬性值，但請勿使用 [@DynamoDBVersionAttribute 註釋](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")
```

若要指定例外狀況，請使用 DynamoDB Encryption Client for Java 中定義的加密註釋。如果您在類別層級指定例外狀況，這些例外狀況就會成為類別的預設值。

```
// 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")
```

### DynamoDBEncryptor 的屬性動作
<a name="attribute-action-default"></a>

若要在您直接使用 [DynamoDBEncryptor](https://aws.github.io/aws-dynamodb-encryption-java/com/amazonaws/services/dynamodbv2/datamodeling/encryption/DynamoDBEncryptor.html) 時指定屬性動作，請建立 `HashMap` 物件，其中的名稱值組代表屬性名稱和指定的動作。

屬性動作的有效值會定義於 `EncryptionFlags` 列舉類型中。您可以同時使用 `ENCRYPT` 與 `SIGN`、單獨使用 `SIGN`，或省略兩者。不過，如果您`ENCRYPT`單獨使用 ，DynamoDB Encryption Client 會擲回錯誤。您無法加密您未簽署的屬性。

```
ENCRYPT
SIGN
```

**警告**  
請勿加密主索引鍵的屬性。它們必須保持純文字，以便 DynamoDB 可以在不執行完整資料表掃描的情況下找到項目。

如果您在加密內容中指定主金鑰，然後在任一主金鑰屬性的屬性動作`ENCRYPT`中指定 ，則 DynamoDB 加密用戶端會擲回例外狀況。

例如，下列 Java 程式碼會建立 `actions` HashMap，該 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;
  }
}
```

然後，當您呼叫 的 [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-) 方法時`DynamoDBEncryptor`，請將映射指定為 `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 加密內容不相符，解密操作會失敗。

有時候，表格的名稱會發生變更，例如當您備份表格或執行[時間點復原時](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`，請勿使用表格名稱覆寫運算子。請改為使用原始表格名稱建立加密內容，並將其提交至解密方法。