

# AWS Database Encryption SDK for DynamoDB
<a name="dynamodb-encryption-client"></a>


****  

|  | 
| --- |
| Our client-side encryption library was renamed to the AWS Database Encryption SDK. This developer guide still provides information on the [DynamoDB Encryption Client](legacy-dynamodb-encryption-client.md). | 

The AWS Database Encryption SDK for DynamoDB is a software library that enables you to include client-side encryption in your [Amazon DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/) design. The AWS Database Encryption SDK for DynamoDB provides attribute-level encryption and enables you to specify which items to encrypt and which items to include in the signatures that ensure the authenticity of your data. Encrypting your sensitive data in transit and at rest helps ensure that your plaintext data isn’t available to any third party, including AWS.

**Note**  
The AWS Database Encryption SDK does not support PartiQL.

In DynamoDB, a [table](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.CoreComponents.html#HowItWorks.CoreComponents.TablesItemsAttributes) is a collection of items. Each *item* is a collection of *attributes*. Each attribute has a name and a value. The AWS Database Encryption SDK for DynamoDB encrypts the values of attributes. Then, it calculates a signature over the attributes. You specify which attribute values to encrypt and which to include in the signature in the [cryptographic actions](concepts.md#crypt-actions).

The topics in this chapter provide an overview of the AWS Database Encryption SDK for DynamoDB, including which fields are encrypted, guidance on client installation and configuration, and Java examples to help you get started.

**Topics**
+ [Client-side and server-side encryption](client-server-side.md)
+ [Which fields are encrypted and signed?](DDB-encrypted-and-signed.md)
+ [Searchable encryption in DynamoDB](ddb-searchable-encryption.md)
+ [Updating your data model](ddb-update-data-model.md)
+ [AWS Database Encryption SDK for DynamoDB available programming languages](ddb-programming-languages.md)
+ [Legacy DynamoDB Encryption Client](legacy-dynamodb-encryption-client.md)

# Client-side and server-side encryption
<a name="client-server-side"></a>


****  

|  | 
| --- |
| Our client-side encryption library was renamed to the AWS Database Encryption SDK. This developer guide still provides information on the [DynamoDB Encryption Client](legacy-dynamodb-encryption-client.md). | 

The AWS Database Encryption SDK for DynamoDB supports *client-side encryption*, where you encrypt your table data before you send it to your database. However, DynamoDB provides a server-side *encryption at rest* feature that transparently encrypts your table when it is persisted to disk and decrypts it when you access the table. 

The tools that you choose depend on the sensitivity of your data and the security requirements of your application. You can use both the AWS Database Encryption SDK for DynamoDB and encryption at rest. When you send encrypted and signed items to DynamoDB, DynamoDB doesn't recognize the items as being protected. It just detects typical table items with binary attribute values. 

**Server-side encryption at rest**

DynamoDB supports [encryption at rest](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/EncryptionAtRest.html), a *server-side encryption* feature in which DynamoDB transparently encrypts your tables for you when the table is persisted to disk, and decrypts them when you access the table data.

When you use an AWS SDK to interact with DynamoDB, by default, your data is encrypted in transit over an HTTPS connection, decrypted at the DynamoDB endpoint, and then re-encrypted before being stored in DynamoDB.
+ **Encryption by default.** DynamoDB transparently encrypts and decrypts all tables when they are written. There is no option to enable or disable encryption at rest. 
+ **DynamoDB creates and manages the cryptographic keys. **The unique key for each table is protected by an [AWS KMS key](https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#master_keys) that never leaves [AWS Key Management Service](https://docs.aws.amazon.com/kms/latest/developerguide/) (AWS KMS) unencrypted. By default, DynamoDB uses an [AWS owned key](https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#aws-owned-cmk) in the DynamoDB service account, but you can choose an [AWS managed key](https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#aws-managed-cmk) or [customer managed key](https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#customer-cmk) in your account to protect some or all of your tables.
+ **All table data is encrypted on disk. **When an encrypted table is saved to disk, DynamoDB encrypts all table data, including the [primary key](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.CoreComponents.html#HowItWorks.CoreComponents.PrimaryKey) and local and global [secondary indexes](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.CoreComponents.html#HowItWorks.CoreComponents.SecondaryIndexes). If your table has a sort key, some of the sort keys that mark range boundaries are stored in plaintext in the table metadata.
+ **Objects related to tables are encrypted, too.** Encryption at rest protects [DynamoDB streams](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Streams.html), [global tables](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GlobalTables.html), and [backups](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/BackupRestore.html) whenever they are written to durable media.
+ **Your items are decrypted when you access them. **When you access the table, DynamoDB decrypts the part of the table that includes your target item, and returns the plaintext item to you.

**AWS Database Encryption SDK for DynamoDB**

Client-side encryption provides end-to-end protection for your data, in transit and at rest, from its source to storage in DynamoDB. Your plaintext data is never exposed to any third party, including AWS. You can use the AWS Database Encryption SDK for DynamoDB with new DynamoDB tables, or you can migrate your existing Amazon DynamoDB tables to the latest version of the AWS Database Encryption SDK for DynamoDB.
+ **Your data is protected in transit and at rest.** It is never exposed to any third party, including AWS.
+ **You can sign your table Items.** You can direct the AWS Database Encryption SDK for DynamoDB to calculate a signature over all or part of a table item, including the primary key attributes. This signature allows you to detect unauthorized changes to the item as a whole, including adding or deleting attributes, or swapping attribute values.
+ **You determine how your data is protected **by [selecting a keyring](keyrings.md). Your keyring determines the wrapping keys that protect your data keys, and ultimately, your data. Use the most secure wrapping keys that are practical for your task.
+ **The AWS Database Encryption SDK for DynamoDB doesn't encrypt the entire table.** You choose which attributes are encrypted in your items. The AWS Database Encryption SDK for DynamoDB does not encrypt an entire item. It does not encrypt attribute names, or the names or values of the primary key (partition key and sort key) attributes.

**AWS Encryption SDK**

If you are encrypting data that you store in DynamoDB, we recommend the AWS Database Encryption SDK for DynamoDB. 

The [AWS Encryption SDK](https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/) is a client-side encryption library that helps you to encrypt and decrypt generic data. Although it can protect any type of data, it isn't designed to work with structured data, like database records. Unlike the AWS Database Encryption SDK for DynamoDB, the AWS Encryption SDK cannot provide item-level integrity checking and it has no logic to recognize attributes or prevent encryption of primary keys.

If you use the AWS Encryption SDK to encrypt any element of your table, remember that it isn't compatible with the AWS Database Encryption SDK for DynamoDB. You cannot encrypt with one library and decrypt with the other.

# Which fields are encrypted and signed?
<a name="DDB-encrypted-and-signed"></a>


****  

|  | 
| --- |
| Our client-side encryption library was renamed to the AWS Database Encryption SDK. This developer guide still provides information on the [DynamoDB Encryption Client](legacy-dynamodb-encryption-client.md). | 

The AWS Database Encryption SDK for DynamoDB is a client-side encryption library designed especially for Amazon DynamoDB applications. Amazon DynamoDB stores data in [tables](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.CoreComponents.html#HowItWorks.CoreComponents.TablesItemsAttributes), which are a collection of items. Each *item* is a collection of *attributes*. Each attribute has a name and a value. The AWS Database Encryption SDK for DynamoDB encrypts the values of attributes. Then, it calculates a signature over the attributes. You can specify which attribute values to encrypt and which to include in the signature.

Encryption protects the confidentiality of the attribute value. Signing provides integrity of all signed attributes and their relationship to each other, and provides authentication. It enables you to detect unauthorized changes to the item as a whole, including adding or deleting attributes, or substituting one encrypted value for another.

In an encrypted item, some data remains in plaintext, including the table name, all attribute names, the attribute values that you don't encrypt, the names and values of the primary key (partition key and sort key) attributes, and the attribute types. Do not store sensitive data in these fields.

For more information on how the AWS Database Encryption SDK for DynamoDB works, see [How the AWS Database Encryption SDK works](how-it-works.md).

**Note**  
All mentions of *attribute actions* in the AWS Database Encryption SDK for DynamoDB topics refer to [cryptographic actions](concepts.md#crypt-actions).

**Topics**
+ [Encrypting attribute values](#encrypt-attribute-values)
+ [Signing the item](#sign-the-item)

## Encrypting attribute values
<a name="encrypt-attribute-values"></a>

The AWS Database Encryption SDK for DynamoDB encrypts the values (but not the attribute name or type) of the attributes that you specify. To determine which attribute values are encrypted, use [attribute actions](concepts.md#crypt-actions). 

For example, this item includes `example` and `test` attributes.

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

If you encrypt the `example` attribute, but don't encrypt the `test` attribute, the results look like the following. The encrypted `example` attribute value is binary data, instead of a string.

```
'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'
...
```

The primary key attributes—partition key and sort key—of each item must remain in plaintext because DynamoDB uses them to find the item in the table. They should be signed, but not encrypted. 

The AWS Database Encryption SDK for DynamoDB identifies the primary key attributes for you and ensures that their values are signed, but not encrypted. And, if you identify your primary key and then try to encrypt it, the client will throw an exception.

The client stores the [material description](concepts.md#material-description) in a new attribute (`aws_dbe_head`) that it adds to the item. The material description describes how the item was encrypted and signed. The client uses this information to verify and decrypt the item. The field that stores the material description is not encrypted.

## Signing the item
<a name="sign-the-item"></a>

After encrypting the specified attribute values, the AWS Database Encryption SDK for DynamoDB calculates Hash-Based Message Authentication Codes (HMACs) and a [digital signature](concepts.md#digital-sigs) over the canonicalization of the material description, [encryption context](concepts.md#encryption-context), and each field marked `ENCRYPT_AND_SIGN`, `SIGN_ONLY`, or `SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT` in the [attribute actions](concepts.md#crypt-actions). ECDSA signatures are enabled by default, but are not required. The client stores the HMACs and signatures in a new attribute (`aws_dbe_foot`) that it adds to the item.

# Searchable encryption in DynamoDB
<a name="ddb-searchable-encryption"></a>

To configure your Amazon DynamoDB tables for searchable encryption, you must use the [AWS KMS Hierarchical keyring](use-hierarchical-keyring.md) to generate, encrypt, and decrypt the data keys used to protect your items. You must also include the [`SearchConfig`](ddb-net-using.md#ddb-net-search-config) in your table encryption configuration. 

**Note**  
If you're using the Java client-side encryption library for DynamoDB, you must use the low-level AWS Database Encryption SDK for DynamoDB API to encrypt, sign, verify, and decrypt your table items. The DynamoDB Enhanced Client and lower-level `DynamoDBItemEncryptor` do not support searchable encryption.

**Topics**
+ [Configuring secondary indexes with beacons](#ddb-beacon-indexes)
+ [Testing beacon outputs](#ddb-beacon-testing)

## Configuring secondary indexes with beacons
<a name="ddb-beacon-indexes"></a>

After you [configure your beacons](configure-beacons.md), you must configure a secondary index that reflects each beacon before you can search on the encrypted attributes.

When you configure a standard or compound beacon, the AWS Database Encryption SDK adds the `aws_dbe_b_` prefix to the beacon name so that the server can easily identify beacons. For example, if you name a compound beacon, `compoundBeacon`, the full beacon name is actually `aws_dbe_b_compoundBeacon`. If you want to configure [secondary indexes](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/SecondaryIndexes.html) that include a standard or compound beacon, you must include the `aws_dbe_b_` prefix when you identify the beacon name.

**Partition and sort keys**  
You cannot encrypt primary key values. Your partition and sort keys must be signed. Your primary key values cannot be a standard or compound beacon.  
Your primary key values must be `SIGN_ONLY`, unless you specify any `SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT` attributes, then the partition and sort attributes must also be `SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`.  
Your primary key values can be signed beacons. If you configured distinct signed beacons for each of your primary key values, you must specify the attribute name that identifies the primary key value as the signed beacon name. However, the AWS Database Encryption SDK does not add the `aws_dbe_b_` prefix to signed beacons. Even if you configured distinct signed beacons for your primary key values, you only need to specify the attribute names for the primary key values when you configure a secondary index.

**Local secondary indexes**  
The sort key for a [local secondary index](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/LSI.html) can be a beacon.  
If you specify a beacon for the sort key, the type must be String. If you specify a standard or compound beacon for the sort key, you must include the `aws_dbe_b_` prefix when you specify the beacon name. If you specify a signed beacon, specify the beacon name without any prefix.

**Global secondary indexes**  
The partition and sort keys for a [global secondary index](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GSI.html) can both be beacons.  
If you specify a beacon for the partition or sort key, the type must be String. If you specify a standard or compound beacon for the sort key, you must include the `aws_dbe_b_` prefix when you specify the beacon name. If you specify a signed beacon, specify the beacon name without any prefix.

**Attribute projections**  
A [projection](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GSI.html#GSI.Projections) is the set of attributes that is copied from a table into a secondary index. The partition key and sort key of the table are always projected into the index; you can project other attributes to support your application's query requirements. DynamoDB provides three different options for attribute projections: `KEYS_ONLY`, `INCLUDE`, and `ALL`.  
If you use the INCLUDE attribute projection to search on a beacon, you must specify the names for all of the attributes that the beacon is constructed from and the beacon name with the `aws_dbe_b_` prefix. For example, if you configured a compound beacon, `compoundBeacon`, from `field1`, `field2`, and `field3`, you must specify `aws_dbe_b_compoundBeacon`, `field1`, `field2`, and `field3` in the projection.  
A global secondary index can only use the attributes explicitly specified in the projection, but a local secondary index can use any attribute.

## Testing beacon outputs
<a name="ddb-beacon-testing"></a>

If you [configured compound beacons](configure-beacons.md#config-compound-beacons) or constructed your beacons using [virtual fields](configure-beacons.md#create-virtual-field), we recommend verifying that these beacons produce the expected output before populating your DynamoDB table.

The AWS Database Encryption SDK provides the `DynamoDbEncryptionTransforms` service to help you troubleshoot virtual field and compound beacon outputs.

### Testing virtual fields
<a name="ddb-beacon-testing-virtual-field"></a>

The following snippet creates test items, defines the `DynamoDbEncryptionTransforms` service with the [DynamoDB table encryption configuration](ddb-java-using.md#ddb-config-encrypt), and demonstrates how to use `ResolveAttributes` to verify that the virtual field produces the expected output.

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

**See the complete code sample**: [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 ]

**See the complete code sample**: [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 ]

**See the complete code sample**: [virtual\$1beacon\$1searchable\$1encryption.rs](https://github.com/aws/aws-database-encryption-sdk-dynamodb/blob/main/releases/rust/db_esdk/examples/searchableencryption/virtual_beacon_searchable_encryption.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");
```

------

### Testing compound beacons
<a name="ddb-beacon-testing-compound-beacon"></a>

The following snippet creates a test item, defines the `DynamoDbEncryptionTransforms` service with the [DynamoDB table encryption configuration](ddb-java-using.md#ddb-config-encrypt), and demonstrates how to use `ResolveAttributes` to verify that the compound beacon produces the expected output.

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

**See the complete code sample**: [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 ]

**See the complete code sample**: [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 ]

**See the complete code sample**: [compound\$1beacon\$1searchable\$1encryption.rs](https://github.com/aws/aws-database-encryption-sdk-dynamodb/blob/main/releases/rust/db_esdk/examples/searchableencryption/compound_beacon_searchable_encryption.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
```

------

# Updating your data model
<a name="ddb-update-data-model"></a>


****  

|  | 
| --- |
| Our client-side encryption library was renamed to the AWS Database Encryption SDK. This developer guide still provides information on the [DynamoDB Encryption Client](legacy-dynamodb-encryption-client.md). | 

When you configure the AWS Database Encryption SDK for DynamoDB, you provide [attribute actions](concepts.md#crypt-actions). On encrypt, AWS Database Encryption SDK uses the attribute actions to identify which attributes to encrypt and sign, which attributes to sign (but not encrypt), and which to ignore. You also define [allowed unsigned attributes](ddb-java-using.md#allowed-unauth) to explicitly tell the client which attributes are excluded from the signatures. On decrypt, the AWS Database Encryption SDK uses the allowed unsigned attributes that you defined to identify which attributes are not included in the signatures. Attribute actions are not saved in the encrypted item and the AWS Database Encryption SDK does not update your attribute actions automatically.

Choose your attribute actions carefully. When in doubt, use **Encrypt and sign**. After you have used the AWS Database Encryption SDK to protect your items, you cannot change an existing `ENCRYPT_AND_SIGN`, `SIGN_ONLY`, or `SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT` attribute to `DO_NOTHING`. However, you can safely make the following changes.
+ [Add new `ENCRYPT_AND_SIGN`, `SIGN_ONLY`, and `SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT` attributes](#ddb-add-auth-attribute)
+ [Remove existing attributes](#ddb-remove-attribute)
+ [Change an existing `ENCRYPT_AND_SIGN` attribute to `SIGN_ONLY` or `SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`](#ddb-encrypt-to-sign)
+ [Change an existing `SIGN_ONLY` or `SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT` attribute to `ENCRYPT_AND_SIGN`](#ddb-sign-to-encrypt)
+ [Add a new `DO_NOTHING` attribute](#ddb-add-unauth-attribute)
+ [Change an existing `SIGN_ONLY` attribute to `SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`](#ddb-signOnly-to-signInclude)
+ [Change an existing `SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT` attribute to `SIGN_ONLY`](#ddb-signInclude-to-signOnly)

**Considerations for searchable encryption**  
Before you update your data model, carefully consider how your updates might impact any [beacons](beacons.md) you constructed from the attributes. After you have written new records with a beacon, you cannot update the beacon's configuration. You cannot update the attribute actions associated with the attributes you used to construct beacons. If you remove an existing attribute and its associated beacon, you will not be able to query existing records using that beacon. You can create new beacons for new fields that you add to your record, but you cannot update existing beacons to include the new field.

**Considerations for `SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT` attributes**  
By default, the partition and sort keys are the only attribute included in the encryption context. You might consider defining additional fields as `SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT` so that the branch key ID supplier for your [AWS KMS Hierarchical keyring](use-hierarchical-keyring.md) can identify which branch key is required for decryption from the encryption context. For more information, see [branch key ID supplier](use-hierarchical-keyring.md#branch-key-id-supplier). If you specify any `SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT` attributes, then the partition and sort attributes must also be `SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`.

**Note**  
To use the `SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT` cryptographic action, you must use version 3.3 or later of the AWS Database Encryption SDK. Deploy the new version to all readers before [updating your data model](#ddb-update-data-model) to include `SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`.

## Add new `ENCRYPT_AND_SIGN`, `SIGN_ONLY`, and `SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT` attributes
<a name="ddb-add-auth-attribute"></a>

To add a new `ENCRYPT_AND_SIGN`, `SIGN_ONLY`, or `SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT` attribute, define the new attribute in your attribute actions.

You cannot remove an existing `DO_NOTHING` attribute and add it back as an `ENCRYPT_AND_SIGN`, `SIGN_ONLY`, or `SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT` attribute.

**Using an annotated data class**  
If you defined your attribute actions with a `TableSchema`, add the new attribute to your annotated data class. If you do not specify an attribute action annotation for the new attribute, the client will encrypt and sign the new attribute by default (unless the attribute is part of the primary key). If you only want to sign the new attribute, you must add the new attribute with the `@DynamoDBEncryptionSignOnly` or `@DynamoDBEncryptionSignAndIncludeInEncryptionContext` annotation.

**Using an object model**  
If you manually defined your attribute actions, add the new attribute to the attribute actions in your object model and specify `ENCRYPT_AND_SIGN`, `SIGN_ONLY`, or `SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT` as the attribute action.

## Remove existing attributes
<a name="ddb-remove-attribute"></a>

If you decide that you no longer need an attribute, you can stop writing data to that attribute or you can formally remove it from your attribute actions. When you stop writing new data to an attribute, the attribute still shows up in your attribute actions. This can be helpful if you need to start using the attribute again in the future. Formally removing the attribute from your attribute actions does not remove it from your dataset. Your dataset will still contain items that include that attribute.

To formally remove an existing `ENCRYPT_AND_SIGN`, `SIGN_ONLY`, `SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`, or `DO_NOTHING` attribute, update your attribute actions.

If you remove a `DO_NOTHING` attribute, you must not remove that attribute from your [allowed unsigned attributes](ddb-java-using.md#allowed-unauth). Even if you are no longer writing new values to that attribute, the client still needs to know that the attribute is unsigned to read existing items that contain the attribute.

**Using an annotated data class**  
If you defined your attribute actions with a `TableSchema`, remove the attribute from your annotated data class.

**Using an object model**  
If you manually defined your attribute actions, remove the attribute from the attribute actions in your object model.

## Change an existing `ENCRYPT_AND_SIGN` attribute to `SIGN_ONLY` or `SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`
<a name="ddb-encrypt-to-sign"></a>

To change an existing `ENCRYPT_AND_SIGN` attribute to `SIGN_ONLY` or `SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`, you must update your attribute actions. After you deploy the update, the client will be able to verify and decrypt existing values written to the attribute, but will only sign new values written to the attribute.

**Note**  
Carefully consider your security requirements before changing an existing `ENCRYPT_AND_SIGN` attribute to `SIGN_ONLY` or `SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`. Any attribute that can store sensitive data should be encrypted.

**Using an annotated data class**  
If you defined your attribute actions with a `TableSchema`, update the existing attribute to include the `@DynamoDBEncryptionSignOnly` or `@DynamoDBEncryptionSignAndIncludeInEncryptionContext` annotation in your annotated data class.

**Using an object model**  
If you manually defined your attribute actions, update the attribute action associated with the existing attribute from `ENCRYPT_AND_SIGN` to `SIGN_ONLY` or `SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT` in your object model.

## Change an existing `SIGN_ONLY` or `SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT` attribute to `ENCRYPT_AND_SIGN`
<a name="ddb-sign-to-encrypt"></a>

To change an existing `SIGN_ONLY` or `SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT` attribute to `ENCRYPT_AND_SIGN`, you must update your attribute actions. After you deploy the update, the client will be able to verify the existing values written to the attribute, and will encrypt and sign new values written to the attribute.

**Using an annotated data class**  
If you defined your attribute actions with a `TableSchema`, remove the `@DynamoDBEncryptionSignOnly` or `@DynamoDBEncryptionSignAndIncludeInEncryptionContext` annotation from the existing attribute.

**Using an object model**  
If you manually defined your attribute actions, update the attribute action associated with the attribute from `SIGN_ONLY` or `SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT` to `ENCRYPT_AND_SIGN` in your object model.

## Add a new `DO_NOTHING` attribute
<a name="ddb-add-unauth-attribute"></a>

To reduce the risk of error when adding a new `DO_NOTHING` attribute, we recommend specifying a distinct prefix when naming your `DO_NOTHING` attributes, and then using that prefix to define your [allowed unsigned attributes](ddb-java-using.md#allowed-unauth).

You cannot remove an existing `ENCRYPT_AND_SIGN`, `SIGN_ONLY`, or `SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT` attribute from your annotated data class and then add the attribute back as a `DO_NOTHING` attribute. You can only add entirely new `DO_NOTHING` attributes.

The steps you take to add a new `DO_NOTHING` attribute depend on whether your defined your allowed unsigned attributes explicitly in a list or with a prefix.

**Using an allowed unsigned attributes prefix**  
If you defined your attribute actions with a `TableSchema`, add the new `DO_NOTHING` attribute to your annotated data class with the `@DynamoDBEncryptionDoNothing` annotation. If you manually defined your attribute actions, update your attribute actions to include the new attribute. Be sure to explicitly configure the new attribute with the `DO_NOTHING` attribute action. You must include the same distinct prefix in the new attribute's name.

**Using an allowed unsigned attributes list**

1. Add the new `DO_NOTHING` attribute to your allowed unsigned attributes list and deploy the updated list.

1. Deploy the change from **Step 1**.

   You cannot move on to **Step 3** until the change has propagated to all hosts that need to read this data.

1. Add the new `DO_NOTHING` attribute to your attribute actions.

   1. If you defined your attribute actions with a `TableSchema`, add the new `DO_NOTHING` attribute to your annotated data class with the `@DynamoDBEncryptionDoNothing` annotation.

   1. If you manually defined your attribute actions, update your attribute actions to include the new attribute. Be sure to explicitly configure the new attribute with the `DO_NOTHING` attribute action.

1. Deploy the change from **Step 3**.

## Change an existing `SIGN_ONLY` attribute to `SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`
<a name="ddb-signOnly-to-signInclude"></a>

To change an existing `SIGN_ONLY` attribute to `SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`, you must update your attribute actions. After you deploy the update, the client will be able to verify the existing values written to the attribute, and will continue to sign new values written to the attribute. New values written to the attribute will be included in the [encryption context](concepts.md#encryption-context).

If you specify any `SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT` attributes, then the partition and sort attributes must also be `SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`.

**Using an annotated data class**  
If you defined your attribute actions with a `TableSchema`, update the attribute action associated with the attribute from `@DynamoDBEncryptionSignOnly` to `@DynamoDBEncryptionSignAndIncludeInEncryptionContext`.

**Using an object model**  
If you manually defined your attribute actions, update the attribute action associated with the attribute from `SIGN_ONLY` to `SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT` in your object model.

## Change an existing `SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT` attribute to `SIGN_ONLY`
<a name="ddb-signInclude-to-signOnly"></a>

To change an existing `SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT` attribute to `SIGN_ONLY`, you must update your attribute actions. After you deploy the update, the client will be able to verify the existing values written to the attribute, and will continue to sign new values written to the attribute. New values written to the attribute will not be included in the [encryption context](concepts.md#encryption-context).

Before changing an existing `SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT` attribute to `SIGN_ONLY`, carefully consider how your updates might impact the functionality of your [branch key ID supplier](use-hierarchical-keyring.md#branch-key-id-supplier).

**Using an annotated data class**  
If you defined your attribute actions with a `TableSchema`, update the attribute action associated with the attribute from `@DynamoDBEncryptionSignAndIncludeInEncryptionContext` to `@DynamoDBEncryptionSignOnly`.

**Using an object model**  
If you manually defined your attribute actions, update the attribute action associated with the attribute from `SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT` to `SIGN_ONLY` in your object model.

# AWS Database Encryption SDK for DynamoDB available programming languages
<a name="ddb-programming-languages"></a>

The AWS Database Encryption SDK for DynamoDB is available for the following programming languages. The language-specific libraries vary, but the resulting implementations are interoperable. You can encrypt with one language implementation and decrypt with another. Interoperability might be subject to language constraints. If so, these constraints are described in the topic about the language implementation. 

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

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


****  

|  | 
| --- |
| Our client-side encryption library was renamed to the AWS Database Encryption SDK. This developer guide still provides information on the [DynamoDB Encryption Client](legacy-dynamodb-encryption-client.md). | 

This topic explains how to install and use version 3.*x* of the Java client-side encryption library for DynamoDB. For details about programming with the AWS Database Encryption SDK for DynamoDB, see the [Java examples](https://github.com/aws/aws-database-encryption-sdk-dynamodb//tree/main/Examples/runtimes/java/DynamoDbEncryption/src/main/java/software/amazon/cryptography/examples) in the aws-database-encryption-sdk-dynamodb repository on GitHub.

**Note**  
The following topics focus on version 3.*x* of the Java client-side encryption library for DynamoDB.  
Our client-side encryption library was [renamed to AWS Database Encryption SDK](DDBEC-rename.md). The AWS Database Encryption SDK continues to support [legacy DynamoDB Encryption Client versions](legacy-dynamodb-encryption-client.md).

**Topics**
+ [Prerequisites](#ddb-java-prerequisites)
+ [Installation](#ddb-java-installation)
+ [Using the Java client](ddb-java-using.md)
+ [Java examples](ddb-java-examples.md)
+ [Add version 3.x to an existing table](ddb-java-config-existing-table.md)
+ [Migrate to version 3.x](ddb-java-migrate.md)

## Prerequisites
<a name="ddb-java-prerequisites"></a>

Before you install version 3.*x* of the Java client-side encryption library for DynamoDB, be sure you have the following prerequisites.

**A Java development environment**  
You will need Java 8 or later. On the Oracle website, go to [Java SE Downloads](https://www.oracle.com/java/technologies/downloads/), and then download and install the Java SE Development Kit (JDK).  
If you use the Oracle JDK, you must also download and install the [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**  
The AWS Database Encryption SDK for DynamoDB requires the [DynamoDB Enhanced Client](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/dynamodb-enhanced-client.html) module of the AWS SDK for Java 2.x. You can install the entire SDK or just this module.  
For information about updating your version of the AWS SDK for Java, see [Migrating from version 1.x to 2.x of the AWS SDK for Java](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/migration.html).  
The AWS SDK for Java is available through Apache Maven. You can declare a dependency for the entire AWS SDK for Java, or just the `dynamodb-enhanced` module.  

**Install the AWS SDK for Java using Apache Maven**
+ To [import the entire AWS SDK for Java](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/setup-project-maven.html#build-the-entire-sdk-into-your-project) as a dependency, declare it in your `pom.xml` file.
+ To create a dependency only for the Amazon DynamoDB module in the AWS SDK for Java, follow the instructions for [specifying particular modules](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/setup-project-maven.html#modules-dependencies). Set the `groupId` to `software.amazon.awssdk` and the `artifactID` to `dynamodb-enhanced`.
**Note**  
If you use the AWS KMS keyring or AWS KMS Hierarchical keyring, you also need to create a dependency for the AWS KMS module. Set the `groupId` to `software.amazon.awssdk` and the `artifactID` to `kms`.

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

You can install version 3.*x* of the Java client-side encryption library for DynamoDB in the following ways.

**Using Apache Maven**  
The Amazon DynamoDB Encryption Client for Java is available through [Apache Maven](https://maven.apache.org/) with the following dependency definition.  

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

**Using Gradle Kotlin**  
You can use [Gradle](https://gradle.org/) to declare a dependency on The Amazon DynamoDB Encryption Client for Java by adding the following to the *dependencies* section of your Gradle project.  

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

**Manually**  
To install the Java client-side encryption library for DynamoDB, clone or download the [aws-database-encryption-sdk-dynamodb](https://github.com/aws/aws-database-encryption-sdk-dynamodb/) GitHub repository.

After you install the SDK, get started by looking at the example code in this guide and the [Java examples](https://github.com/aws/aws-database-encryption-sdk-dynamodb//tree/main/Examples/runtimes/java/DynamoDbEncryption/src/main/java/software/amazon/cryptography/examples) in the aws-database-encryption-sdk-dynamodb repository on GitHub.

# Using the Java client-side encryption library for DynamoDB
<a name="ddb-java-using"></a>


****  

|  | 
| --- |
| Our client-side encryption library was renamed to the AWS Database Encryption SDK. This developer guide still provides information on the [DynamoDB Encryption Client](legacy-dynamodb-encryption-client.md). | 

This topic explains some of the functions and helper classes in version 3.*x* of the Java client-side encryption library for DynamoDB. 

For details about programming with the Java client-side encryption library for DynamoDB, see the [Java examples](java-examples.md), the [Java examples](https://github.com/aws/aws-database-encryption-sdk-dynamodb//tree/main/Examples/runtimes/java/DynamoDbEncryption/src/main/java/software/amazon/cryptography/examples) in the aws-database-encryption-sdk-dynamodb repository on GitHub.

**Topics**
+ [Item encryptors](#ddb-item-encryptors)
+ [Attribute actions](#ddb-attribute-actions)
+ [Encryption configuration](#ddb-config-encrypt)
+ [Updating items](#ddb-update-items)
+ [Decrypting signed sets](#ddb-java-signed-sets)

## Item encryptors
<a name="ddb-item-encryptors"></a>

At its core, the AWS Database Encryption SDK for DynamoDB is an item encryptor. You can use version 3.*x* of the Java client-side encryption library for DynamoDB to encrypt, sign, verify, and decrypt your DynamoDB table items in the following ways.

**The DynamoDB Enhanced Client**  
You can configure the [DynamoDB Enhanced Client](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/dynamodb-enhanced-client.html) with the `DynamoDbEncryptionInterceptor` to automatically encrypt and sign items client-side with your DynamoDB `PutItem` requests. With the DynamoDB Enhanced Client, you can define your attribute actions using an [annotated data class](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/ddb-en-client-gs-tableschema.html#ddb-en-client-gs-tableschema-anno-bean). We recommend using the DynamoDB Enhanced Client whenever possible.  
The DynamoDB Enhanced Client does not support [searchable encryption](searchable-encryption.md).  
The AWS Database Encryption SDK does not support annotations on [nested attributes](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/ddb-en-client-adv-features-nested.html).

**The low-level DynamoDB API**  
You can configure the [low-level DynamoDB API](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Programming.LowLevelAPI.html) with the `DynamoDbEncryptionInterceptor` to automatically encrypt and sign items client-side with your DynamoDB `PutItem` requests.  
You must use the low-level DynamoDB API to use [searchable encryption](searchable-encryption.md).

**The lower-level `DynamoDbItemEncryptor`**  
The lower-level `DynamoDbItemEncryptor` directly encrypts and signs or decrypts and verifies your table items without calling DynamoDB. It does not make DynamoDB `PutItem` or `GetItem` requests. For example, you can use the lower-level `DynamoDbItemEncryptor` to directly decrypt and verify a DynamoDB item that you have already retrieved.  
The lower-level `DynamoDbItemEncryptor` does not support [searchable encryption](searchable-encryption.md).

## Attribute actions in the AWS Database Encryption SDK for DynamoDB
<a name="ddb-attribute-actions"></a>

[Attribute actions](concepts.md#crypt-actions) determine which attribute values are encrypted and signed, which are only signed, which are signed and included in the encryption context, and which are ignored.

**Note**  
To use the `SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT` cryptographic action, you must use version 3.3 or later of the AWS Database Encryption SDK. Deploy the new version to all readers before [updating your data model](ddb-update-data-model.md) to include `SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`.

If you use the low-level DynamoDB API or the lower-level `DynamoDbItemEncryptor`, you must manually define your attribute actions. If you use the DynamoDB Enhanced Client you can either manually define your attribute actions, or you can use an annotated data class to [generate a `TableSchema`](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/ddb-en-client-gs-tableschema.html). To simplify the configuration process, we recommend using an annotated data class. When you use an annotated data class, you only have to model your object once.

**Note**  
After you define your attribute actions, you must define which attributes are excluded from the signatures. To make it easier to add new unsigned attributes in the future, we recommend choosing a distinct prefix (such as "`:`") to identify your unsigned attributes. Include this prefix in the attribute name for all attributes marked `DO_NOTHING` as you define your DynamoDB schema and attribute actions.

### Use an annotated data class
<a name="ddb-attribute-actions-annotated-data-class"></a>

Use an [annotated data class](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/ddb-en-client-gs-tableschema.html#ddb-en-client-gs-tableschema-anno-bean) to specify your attribute actions with the DynamoDB Enhanced Client and `DynamoDbEncryptionInterceptor`. The AWS Database Encryption SDK for DynamoDB uses the [standard DynamoDB attribute annotations](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/mapper/annotations/package-summary.html) that define the attribute type to determine how to protect an attribute. By default, all attributes are encrypted and signed except for primary keys, which are signed but not encrypted.

**Note**  
To use the `SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT` cryptographic action, you must use version 3.3 or later of the AWS Database Encryption SDK. Deploy the new version to all readers before [updating your data model](ddb-update-data-model.md) to include `SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`.

See [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) in the aws-database-encryption-sdk-dynamodb repository on GitHub for more guidance on the DynamoDB Enhanced Client annotations.

By default, primary key attributes are signed but not encrypted (`SIGN_ONLY`) and all other attributes are encrypted and signed (`ENCRYPT_AND_SIGN`). If you define any attributes as `SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`, then the partition and sort attributes must also be `SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`. To specify exceptions, use the encryption annotations defined in the Java client-side encryption library for DynamoDB. For example, if you want a particular attribute to only be signed use the `@DynamoDbEncryptionSignOnly` annotation. If you want a particular attribute to be signed and included in the encryption context, use the `@DynamoDbEncryptionSignAndIncludeInEncryptionContext`. If you want a particular attribute to be neither signed nor encrypted (`DO_NOTHING`), use the `@DynamoDbEncryptionDoNothing` annotation.

**Note**  
The AWS Database Encryption SDK does not support annotations on [nested attributes](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/ddb-en-client-adv-features-nested.html).

The following example shows the annotations used to define `ENCRYPT_AND_SIGN`, `SIGN_ONLY`, and `DO_NOTHING`attribute actions. For an example that shows the annotations used to define `SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`, see [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;
    }
    
}
```

Use your annotated data class to create the `TableSchema` as shown in the following snippet.

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

### Manually define your attribute actions
<a name="ddb-attribute-actions-manual"></a>

To manually specify attribute actions, create a `Map` object in which the name-value pairs represent attribute names and the specified actions.

Specify `ENCRYPT_AND_SIGN` to encrypt and sign an attribute. Specify `SIGN_ONLY` to sign, but not encrypt, an attribute. Specify `SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT` to sign an attribute and include it in the encryption context. You cannot encrypt an attribute without also signing it. Specify `DO_NOTHING` to ignore an attribute.

The partition and sort attributes must be either `SIGN_ONLY` or `SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`. If you define any attributes as `SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`, then the partition and sort attributes must also be `SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`.

**Note**  
To use the `SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT` cryptographic action, you must use version 3.3 or later of the AWS Database Encryption SDK. Deploy the new version to all readers before [updating your data model](ddb-update-data-model.md) to include `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);
```

## Encryption configuration in the AWS Database Encryption SDK for DynamoDB
<a name="ddb-config-encrypt"></a>

When you use the AWS Database Encryption SDK, you must explicitly define an encryption configuration for your DynamoDB table. The values required in your encryption configuration depend on whether you defined your attribute actions manually or with an annotated data class.

The following snippet defines a DynamoDB table encryption configuration using the DynamoDB Enhanced Client, [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), and allowed unsigned attributes defined by a distinct prefix.

```
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());
```

**Logical table name**  
A logical table name for your DynamoDB table.  
The logical table name is cryptographically bound to all data stored in the table to simplify DynamoDB restore operations. We strongly recommend specifying your DynamoDB table name as the logical table name when you first define your encryption configuration. You must always specify the same logical table name. For decryption to succeed, the logical table name must match the name specified on encryption. In the event that your DynamoDB table name changes after [restoring your DynamoDB table from a backup](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Restore.Tutorial.html), the logical table name ensures that the decrypt operation still recognizes the table.

**Allowed unsigned attributes**  
The attributes marked `DO_NOTHING` in your attribute actions.  
The allowed unsigned attributes tell the client which attributes are excluded from the signatures. The client assumes that all other attributes are included in the signature. Then, when decrypting a record, the client determines which attributes it needs to verify and which to ignore from the allowed unsigned attributes you specified. You cannot remove an attribute from your allowed unsigned attributes.  
You can define the allowed unsigned attributes explicitly by creating an array that lists all of your `DO_NOTHING` attributes. You can also specify a distinct prefix when naming your `DO_NOTHING` attributes and use the prefix to tell the client which attributes are unsigned. We strongly recommend specifying a distinct prefix because it simplifies the process of adding a new `DO_NOTHING` attribute in the future. For more information, see [Updating your data model](ddb-update-data-model.md).  
If you do not specify a prefix for all `DO_NOTHING` attributes, you can configure an `allowedUnsignedAttributes` array that explicitly lists all of the attributes that the client should expect to be unsigned when it encounters them on decryption. You should only explicitly define your allowed unsigned attributes if absolutely necessary.

**Search Configuration (Optional)**  
The `SearchConfig` defines the [beacon version](using-beacons.md#beacon-version).  
The `SearchConfig` must be specified to use [searchable encryption](searchable-encryption.md) or [signed beacons](configure.md#signed-beacons).

**Algorithm Suite (Optional)**  
The `algorithmSuiteId` defines which algorithm suite the AWS Database Encryption SDK uses.  
Unless you explicitly specify an alternative algorithm suite, the AWS Database Encryption SDK uses the [default algorithm suite](supported-algorithms.md#recommended-algorithms). The default algorithm suite uses the AES-GCM algorithm with key derivation, [digital signatures](concepts.md#digital-sigs), and [key commitment](concepts.md#key-commitment). Although the default algorithm suite is likely to be suitable for most applications, you can choose an alternate algorithm suite. For example, some trust models would be satisfied by an algorithm suite without digital signatures. For information about the algorithm suites that the AWS Database Encryption SDK supports, see [Supported algorithm suites in the AWS Database Encryption SDK](supported-algorithms.md).  
To select the [AES-GCM algorithm suite without ECDSA digital signatures](supported-algorithms.md#other-algorithms), include the following snippet in your table encryption configuration.  

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

## Updating items with the AWS Database Encryption SDK
<a name="ddb-update-items"></a>

The AWS Database Encryption SDK does not support [ddb:UpdateItem](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_UpdateItem.html) for items that have been encrypted or signed. To update an encrypted or signed item, you must use [ddb:PutItem](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_PutItem.html). When you specify the same primary key as an existing item in your `PutItem` request, the new item completely replaces the existing item. You can also use [CLOBBER](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/dynamodbv2/datamodeling/DynamoDBMapperConfig.SaveBehavior.html#CLOBBER) to clear and replace all attributes on save after updating your items.

## Decrypting signed sets
<a name="ddb-java-signed-sets"></a>

In versions 3.0.0 and 3.1.0 of the AWS Database Encryption SDK, if you define a [set type](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.NamingRulesDataTypes.html#HowItWorks.DataTypes.SetTypes) attribute as `SIGN_ONLY`, the values of the set are canonicalized in the order that they are provided. DynamoDB does not preserve the order of sets. As a result, there is a chance that signature validation of the item that contains the set will fail. Signature validation fails when the values of the set are returned in a different order than they were provided to the AWS Database Encryption SDK, even if the set attributes contain the same values.

**Note**  
Versions 3.1.1 and later of the AWS Database Encryption SDK canonicalize the values of all set type attributes, so that the values are read in the same order that they were written to DynamoDB.

If signature validation fails, the decrypt operation fails and returns the following error message.


|  | 
| --- |
| software.amazon.cryptography.dbencryptionsdk.structuredencryption.model.StructuredEncryptionException: No recipient tag matched. | 

If you receive the above error message, and believe that the item you are trying to decrypt includes a set that was signed using version 3.0.0 or 3.1.0, see the [DecryptWithPermute](https://github.com/aws/aws-database-encryption-sdk-dynamodb-java/tree/v3.1.1/DecryptWithPermute) directory of the aws-database-encryption-sdk-dynamodb-java repository on GitHub for details on how to successfully validate the set.

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


****  

|  | 
| --- |
| Our client-side encryption library was renamed to the AWS Database Encryption SDK. This developer guide still provides information on the [DynamoDB Encryption Client](legacy-dynamodb-encryption-client.md). | 

The following examples show you how to use the Java client-side encryption library for DynamoDB to protect the table items in your application. You can find more examples (and contribute your own) in the [Java examples](https://github.com/aws/aws-database-encryption-sdk-dynamodb//tree/main/Examples/runtimes/java/DynamoDbEncryption/src/main/java/software/amazon/cryptography/examples) in the aws-database-encryption-sdk-dynamodb repository on GitHub.

The following examples demonstrate how to configure the Java client-side encryption library for DynamoDB in a new, unpopulated Amazon DynamoDB table. If you want to configure your existing Amazon DynamoDB tables for client-side encryption, see [Add version 3.x to an existing table](ddb-java-config-existing-table.md).

**Topics**
+ [Using the DynamoDB enhanced client](#ddb-java-enhanced-client-example)
+ [Using the low-level DynamoDB API](#ddb-java-lowlevel-API-example)
+ [Using the lower-level DynamoDbItemEncryptor](#ddb-java-itemencryptor)

## Using the DynamoDB enhanced client
<a name="ddb-java-enhanced-client-example"></a>

The following example shows how to use the DynamoDB Enhanced Client and `DynamoDbEncryptionInterceptor` with an [AWS KMS keyring](use-kms-keyring.md) to encrypt DynamoDB table items as part of your DynamoDB API calls.

You can use any supported [keyring](keyrings.md) with the DynamoDB Enhanced Client, but we recommend using one of the AWS KMS keyrings whenever possible.

**Note**  
The DynamoDB Enhanced Client does not support [searchable encryption](searchable-encryption.md). Use the `DynamoDbEncryptionInterceptor` with the low-level DynamoDB API to use searchable encryption.

**See the complete code sample**: [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)

**Step 1: Create the AWS KMS keyring**  
The following example uses `CreateAwsKmsMrkMultiKeyring` to create an AWS KMS keyring with a symmetric encryption KMS key. The `CreateAwsKmsMrkMultiKeyring` method ensures that the keyring will correctly handle both single-Region and multi-Region keys.  

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

**Step 2: Create a table schema from the annotated data class**  
The following example uses the annotated data class to create the `TableSchema`.  
This example assumes that the annotated data class and attribute actions were defined using the [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). For more guidance on annotating your attribute actions, see [Use an annotated data class](ddb-java-using.md#ddb-attribute-actions-annotated-data-class).  
The AWS Database Encryption SDK does not support annotations on [nested attributes](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);
```

**Step 3: Define which attributes are excluded from the signatures**  
The following example assumes that all `DO_NOTHING` attributes share the distinct prefix "`:`", and uses the prefix to define the allowed unsigned attributes. The client assumes that any attribute name with the "`:`" prefix is excluded from the signatures. For more information, see [Allowed unsigned attributes](ddb-java-using.md#allowed-unauth).  

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

**Step 4: Create the encryption configuration**  
The following example defines a `tableConfigs` Map that represents the encryption configuration for the DynamoDB table.   
This example specifies the DynamoDB table name as the [logical table name](ddb-java-using.md#logical-table-name). We strongly recommend specifying your DynamoDB table name as the logical table name when you first define your encryption configuration. For more information, see [Encryption configuration in the AWS Database Encryption SDK for DynamoDB](ddb-java-using.md#ddb-config-encrypt).  
To use [searchable encryption](searchable-encryption.md) or [signed beacons](configure.md#signed-beacons), you must also include the [`SearchConfig`](ddb-java-using.md#ddb-search-config) in your encryption configuration.

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

**Step 5: Creates the `DynamoDbEncryptionInterceptor`**  
The following example creates a new `DynamoDbEncryptionInterceptor` with the `tableConfigs` from **Step 4**.  

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

**Step 6: Create a new AWS SDK DynamoDB client**  
The following example creates a new AWS SDK DynamoDB client using the `interceptor` from **Step 5**.  

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

**Step 7: Create the DynamoDB Enhanced Client and create a table**  
The following example creates the DynamoDB Enhanced Client using the AWS SDK DynamoDB client created in **Step 6** and creates a table using the annotated data class.  

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

**Step 8: Encrypt and sign a table item**  
The following example puts an item into the DynamoDB table using the DynamoDB Enhanced Client. The item is encrypted and signed client-side before it is send to 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);
```

## Using the low-level DynamoDB API
<a name="ddb-java-lowlevel-API-example"></a>

The following example shows how to use the low-level DynamoDB API with an [AWS KMS keyring](use-kms-keyring.md) to automatically encrypt and sign items client-side with your DynamoDB `PutItem` requests.

You can use any supported [keyring](keyrings.md), but we recommend using one of the AWS KMS keyrings whenever possible.

**See the complete code sample**: [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)

**Step 1: Create the AWS KMS keyring**  
The following example uses `CreateAwsKmsMrkMultiKeyring` to create an AWS KMS keyring with a symmetric encryption KMS key. The `CreateAwsKmsMrkMultiKeyring` method ensures that the keyring will correctly handle both single-Region and multi-Region keys.  

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

**Step 2: Configure your attribute actions**  
The following example defines an `attributeActionsOnEncrypt` Map that represents sample [attribute actions](concepts.md#crypt-actions) for a table item.  
The following example does not define any attributes as `SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`. If you specify any `SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT` attributes, then the partition and sort attributes must also be `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);
```

**Step 3: Define which attributes are excluded from the signatures**  
The following example assumes that all `DO_NOTHING` attributes share the distinct prefix "`:`", and uses the prefix to define the allowed unsigned attributes. The client assumes that any attribute name with the "`:`" prefix is excluded from the signatures. For more information, see [Allowed unsigned attributes](ddb-java-using.md#allowed-unauth).  

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

**Step 4: Define the DynamoDB table encryption configuration**  
The following example defines a `tableConfigs` Map that represents the encryption configuration for this DynamoDB table.  
This example specifies the DynamoDB table name as the [logical table name](ddb-java-using.md#logical-table-name). We strongly recommend specifying your DynamoDB table name as the logical table name when you first define your encryption configuration. For more information, see [Encryption configuration in the AWS Database Encryption SDK for DynamoDB](ddb-java-using.md#ddb-config-encrypt).  
To use [searchable encryption](searchable-encryption.md) or [signed beacons](configure.md#signed-beacons), you must also include the [`SearchConfig`](ddb-java-using.md#ddb-search-config) in your encryption configuration.

```
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);
```

**Step 5: Create the `DynamoDbEncryptionInterceptor`**  
The following example creates the `DynamoDbEncryptionInterceptor` using the `tableConfigs` from **Step 4**.  

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

**Step 6: Create a new AWS SDK DynamoDB client**  
The following example creates a new AWS SDK DynamoDB client using the `interceptor` from **Step 5**.  

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

**Step 7: Encrypt and sign a DynamoDB table item**  
The following example defines an `item` Map that represents a sample table item and puts the item in the DynamoDB table. The item is encrypted and signed client-side before it is sent to 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);
```

## Using the lower-level DynamoDbItemEncryptor
<a name="ddb-java-itemencryptor"></a>

The following example shows how to use the lower-level `DynamoDbItemEncryptor` with an [AWS KMS keyring](use-kms-keyring.md) to directly encrypt and sign table items. The `DynamoDbItemEncryptor` does not put the item in your DynamoDB table.

You can use any supported [keyring](keyrings.md) with the DynamoDB Enhanced Client, but we recommend using one of the AWS KMS keyrings whenever possible.

**Note**  
The lower-level `DynamoDbItemEncryptor` does not support [searchable encryption](searchable-encryption.md). Use the `DynamoDbEncryptionInterceptor` with the low-level DynamoDB API to use searchable encryption.

**See the complete code sample**: [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)

**Step 1: Create the AWS KMS keyring**  
The following example uses `CreateAwsKmsMrkMultiKeyring` to create an AWS KMS keyring with a symmetric encryption KMS key. The `CreateAwsKmsMrkMultiKeyring` method ensures that the keyring will correctly handle both single-Region and multi-Region keys.  

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

**Step 2: Configure your attribute actions**  
The following example defines an `attributeActionsOnEncrypt` Map that represents sample [attribute actions](concepts.md#crypt-actions) for a table item.  
The following example does not define any attributes as `SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`. If you specify any `SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT` attributes, then the partition and sort attributes must also be `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);
```

**Step 3: Define which attributes are excluded from the signatures**  
The following example assumes that all `DO_NOTHING` attributes share the distinct prefix "`:`", and uses the prefix to define the allowed unsigned attributes. The client assumes that any attribute name with the "`:`" prefix is excluded from the signatures. For more information, see [Allowed unsigned attributes](ddb-java-using.md#allowed-unauth).  

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

**Step 4: Define the `DynamoDbItemEncryptor` configuration**  
The following example defines the configuration for the `DynamoDbItemEncryptor`.  
This example specifies the DynamoDB table name as the [logical table name](ddb-java-using.md#logical-table-name). We strongly recommend specifying your DynamoDB table name as the logical table name when you first define your encryption configuration. For more information, see [Encryption configuration in the AWS Database Encryption SDK for DynamoDB](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();
```

**Step 5: Create the `DynamoDbItemEncryptor`**  
The following example creates a new `DynamoDbItemEncryptor` using the `config` from **Step 4**.  

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

**Step 6: Directly encrypt and sign a table item**  
The following example directly encrypts and signs an item using the `DynamoDbItemEncryptor`. The `DynamoDbItemEncryptor` does not put the item in your DynamoDB table.  

```
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();
```

# Configure an existing DynamoDB table to use the AWS Database Encryption SDK for DynamoDB
<a name="ddb-java-config-existing-table"></a>


****  

|  | 
| --- |
| Our client-side encryption library was renamed to the AWS Database Encryption SDK. This developer guide still provides information on the [DynamoDB Encryption Client](legacy-dynamodb-encryption-client.md). | 

With version 3.*x* of the Java client-side encryption library for DynamoDB, you can configure your existing Amazon DynamoDB tables for client-side encryption. This topic provides guidance on the three steps you must take to add version 3.*x* to an existing, populated DynamoDB table.

**Prerequisites**  
Version 3.*x* of the Java client-side encryption library for DynamoDB requires the [DynamoDB Enhanced Client](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/dynamodb-enhanced-client.html) provided in AWS SDK for Java 2.x . If you still use the [DynamoDBMapper](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBMapper.Methods.html), you must migrate to AWS SDK for Java 2.x to use the DynamoDB Enhanced Client.

 Follow the instructions for [migrating from version 1.x to 2.x of the AWS SDK for Java](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/migration.html).

Then, follow the instructions to [Get Started using the DynamoDB Enhanced Client API](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/ddb-en-client-getting-started.html).

Before configuring your table to use the Java client-side encryption library for DynamoDB, you need to generate a `TableSchema` [using an annotated data class](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/ddb-en-client-gs-tableschema.html#ddb-en-client-gs-tableschema-anno-bean) and [create an enhanced client](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).

## Step 1: Prepare to read and write encrypted items
<a name="ddb-java-add-step1"></a>

Complete the following steps to prepare your AWS Database Encryption SDK client to read and write encrypted items. After you deploy the following changes, your client will continue to read and write plaintext items. It will not encrypt or sign any new items written to the table, but it will be able to decrypt encrypted items as soon as they appear. These changes prepare the client to begin [encrypting new items](#ddb-java-add-step2). The following changes must be deployed to each reader before you proceed to the next step.

**1. Define your [attribute actions](concepts.md#crypt-actions)**  
Update your annotated data class to include attribute actions that define which attribute values will be encrypted and signed, which will be only signed, and which will be ignored.  
See the [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) in the aws-database-encryption-sdk-dynamodb repository on GitHub for more guidance on the DynamoDB Enhanced Client annotations.  
By default, primary key attributes are signed but not encrypted (`SIGN_ONLY`) and all other attributes are encrypted and signed (`ENCRYPT_AND_SIGN`). To specify exceptions, use the encryption annotations defined in the Java client-side encryption library for DynamoDB. For example, if you want a particular attribute to be sign only use the `@DynamoDbEncryptionSignOnly` annotation. If you want a particular attribute to be signed and included in the encryption context, use the `@DynamoDbEncryptionSignAndIncludeInEncryptionContext` annotation. If you want a particular attribute to be neither signed nor encrypted (`DO_NOTHING`), use the `@DynamoDbEncryptionDoNothing` annotation.  
If you specify any `SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT` attributes, then the partition and sort attributes must also be `SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`. For an example that shows the annotations used to define `SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`, see [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).
For example annotations, see [Use an annotated data class](ddb-java-using.md#ddb-attribute-actions-annotated-data-class).

**2. Define which attributes will be excluded from the signatures**  
The following example assumes that all `DO_NOTHING` attributes share the distinct prefix "`:`", and uses the prefix to define the allowed unsigned attributes. The client will assume that any attribute name with the "`:`" prefix is excluded from the signatures. For more information, see [Allowed unsigned attributes](ddb-java-using.md#allowed-unauth).  

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

**3. Create a [keyring](keyrings.md)**  
The following example creates an [AWS KMS keyring](use-kms-keyring.md). The AWS KMS keyring uses symmetric encryption or asymmetric RSA AWS KMS keys to generate, encrypt, and decrypt data keys.  
This example uses `CreateMrkMultiKeyring` to create an AWS KMS keyring with a symmetric encryption KMS key. The `CreateAwsKmsMrkMultiKeyring` method ensures that the keyring will correctly handle both single-Region and multi-Region keys.  

```
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. Define the DynamoDB table encryption configuration **  
The following example defines a `tableConfigs` Map that represents the encryption configuration for this DynamoDB table.  
This example specifies the DynamoDB table name as the [logical table name](ddb-java-using.md#logical-table-name). We strongly recommend specifying your DynamoDB table name as the logical table name when you first define your encryption configuration. For more information, see [Encryption configuration in the AWS Database Encryption SDK for DynamoDB](ddb-java-using.md#ddb-config-encrypt).  
You must specify `FORCE_WRITE_PLAINTEXT_ALLOW_READ_PLAINTEXT` as the plaintext override. This policy continues to read and write plaintext items, reads encrypted items, and prepares the client to write encrypted items.  

```
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. Create the `DynamoDbEncryptionInterceptor`**  
The following example creates the `DynamoDbEncryptionInterceptor` using the `tableConfigs` from **Step 3**.  

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

## Step 2: Write encrypted and signed items
<a name="ddb-java-add-step2"></a>

Update the plaintext policy in your `DynamoDbEncryptionInterceptor` configuration to allow the client to write encrypted and signed items. After you deploy the following change, the client will encrypt and sign new items based on the attribute actions you configured in **Step 1**. The client will be able read plaintext items and encrypted and signed items.

Before you proceed to [Step 3](#ddb-java-add-step3), you must encrypt and sign all existing plaintext items in your table. There is no single metric or query that you can run to quickly encrypt your existing plaintext items. Use the process that makes the most sense for your system. For example, you could use an asynchronous process that slowly scans the table and the rewrites the items using the attribute actions and encryption configuration you defined. To identify the plaintext items in your table, we recommend scanning for all items that do not contain the `aws_dbe_head` and `aws_dbe_foot` attributes that the AWS Database Encryption SDK adds to items when they're encrypted and signed.

The following example updates the table encryption configuration from **Step 1**. You must update the plaintext override with `FORBID_WRITE_PLAINTEXT_ALLOW_READ_PLAINTEXT`. This policy continues to read plaintext items, but also reads and writes encrypted items. Create a new `DynamoDbEncryptionInterceptor` using the updated `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);
```

## Step 3: Only read encrypted and signed items
<a name="ddb-java-add-step3"></a>

After you have encrypted and signed all of your items, update the plaintext override in your `DynamoDbEncryptionInterceptor` configuration to only allow the client to read and write encrypted and signed items. After you deploy the following change, the client will encrypt and sign new items based on the attribute actions you configured in **Step 1**. The client will only be able read encrypted and signed items.

The following example updates the table encryption configuration from **Step 2**. You can either update the plaintext override with `FORBID_WRITE_PLAINTEXT_FORBID_READ_PLAINTEXT` or remove the plaintext policy from your configuration. The client only reads and writes encrypted and signed items by default. Create a new `DynamoDbEncryptionInterceptor` using the updated `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);
```

# Migrate to version 3.x of the Java client-side encryption library for DynamoDB
<a name="ddb-java-migrate"></a>


****  

|  | 
| --- |
| Our client-side encryption library was renamed to the AWS Database Encryption SDK. This developer guide still provides information on the [DynamoDB Encryption Client](legacy-dynamodb-encryption-client.md). | 

Version 3.*x* of the Java client-side encryption library for DynamoDB is a major rewrite of the 2.*x* code base. It includes many updates, such as a new structured data format, improved multitenancy support, seamless schema changes, and searchable encryption support. This topic provides guidance on how to migrate your code to version 3.*x*.

## Migrating from version 1.x to 2.x
<a name="ddb-java-v1-to-v2"></a>

Migrate to version 2.*x* before you migrate to version 3.*x*. Version 2.*x* changed the symbol for the Most Recent Provider from `MostRecentProvider` to `CachingMostRecentProvider`. If you currently use version 1.*x* of the Java client-side encryption library for DynamoDB with the `MostRecentProvider` symbol, you must update the symbol name in your code to `CachingMostRecentProvider`. For more information, see [Updates to the Most Recent Provider](most-recent-provider.md#mrp-versions).

## Migrating from version 2.x to 3.x
<a name="ddb-java-v2-to-v3"></a>

The following procedures describe how to migrate your code from version 2.*x* to version 3.*x* of the Java client-side encryption library for DynamoDB.

### Step 1. Prepare to read items in the new format
<a name="ddb-java-migrate-step1"></a>

Complete the following steps to prepare your AWS Database Encryption SDK client to read items in the new format. After you deploy the following changes, your client will continue to behave in the same manner that it did in version 2.*x*. Your client will continue to read and write items in the version 2.*x* format, but these changes prepare the client to [read items in the new format](#ddb-java-migrate-step2).

**Update your AWS SDK for Java to version 2.x**  
Version 3.*x* of the Java client-side encryption library for DynamoDB requires the [DynamoDB Enhanced Client](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/dynamodb-enhanced-client.html). The DynamoDB Enhanced Client replaces the [DynamoDBMapper](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBMapper.Methods.html) used in previous versions. To use the enhanced client, you must use the AWS SDK for Java 2.x.   
Follow the instructions for [migrating from version 1.x to 2.x of the AWS SDK for Java](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/migration.html).  
For more information on what AWS SDK for Java 2.x modules are required, see [Prerequisites](ddb-java.md#ddb-java-prerequisites).

**Configure your client to read items encrypted by legacy versions**  
The following procedures provide an overview of the steps demonstrated in the code example below.  

1. Create a [keyring](keyrings.md).

   Keyrings and [cryptographic materials managers](concepts.md#crypt-materials-manager) replace the cryptographic materials providers used in previous versions of the Java client-side encryption library for DynamoDB.
**Important**  
The wrapping keys you specify when creating a keyring must be the same wrapping keys you used with your cryptographic materials provider in version 2.*x*.

1. Create a table schema over your annotated class.

   This step defines the attribute actions that will be used when you begin writing items in the new format.

   For guidance on using the new DynamoDB Enhanced Client, see the [Generate a `TableSchema`](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/ddb-en-client-gs-tableschema.html) in the *AWS SDK for Java Developer Guide*.

   The following example assumes you updated your annotated class from version 2.*x* using the new attribute actions annotations. For more guidance on annotating your attribute actions, see [Use an annotated data class](ddb-java-using.md#ddb-attribute-actions-annotated-data-class).
**Note**  
If you specify any `SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT` attributes, then the partition and sort attributes must also be `SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`. For an example that shows the annotations used to define `SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`, see [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. Define which [attributes are excluded from the signature](ddb-java-using.md#allowed-unauth).

1. Configure an explicit map of the attribute actions configured in your version 2.x modeled class.

   This step defines the attribute actions used to write items in the old format.

1. Configure the `DynamoDBEncryptor` you used in version 2.*x* of the Java client-side encryption library for DynamoDB.

1. Configure the legacy behavior.

1. Create a `DynamoDbEncryptionInterceptor`.

1. Create a new AWS SDK DynamoDB client.

1. Create the `DynamoDBEnhancedClient` and create a table with your modeled class.

   For more information on the DynamoDB Enhanced Client, see [create an enhanced client](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);
    }
}
```

### Step 2. Write items in the new format
<a name="ddb-java-migrate-step2"></a>

After you have deployed the changes from Step 1 to all readers, complete the following steps to configure your AWS Database Encryption SDK client to write items in the new format. After you deploy the following changes, your client will continue read items in the old format and start writing and reading items in the new format.

The following procedures provide an overview of the steps demonstrated in the code example below.

1. Continue configuring your keyring, table schema, legacy attribute actions, `allowedUnsignedAttributes`, and `DynamoDBEncryptor` as you did in [**Step 1**](#ddb-java-migrate-step1).

1. Update your legacy behavior to only write new items using the new format.

1. Create a `DynamoDbEncryptionInterceptor `

1. Create a new AWS SDK DynamoDB client.

1. Create the `DynamoDBEnhancedClient` and create a table with your modeled class.

   For more information on the DynamoDB Enhanced Client, see [create an enhanced client](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);
    }
}
```

After deploying the Step 2 changes, you must re-encrypt all old items in your table with the new format before you can continue on to [Step 3](#ddb-java-migrate-step3). There is no single metric or query that you can run to quickly encrypt your existing items. Use the process that makes the most sense for your system. For example, you could use an asynchronous process that slowly scans the table and the rewrites the items using the new attribute actions and encryption configuration you defined.

### Step 3. Only read and write items in the new format
<a name="ddb-java-migrate-step3"></a>

After re-encrypting all of the items in your table with the new format, you can remove the legacy behavior from your configuration. Complete the following steps to configure your client to only read and write items in the new format.

The following procedures provide an overview of the steps demonstrated in the code example below.

1. Continue configuring your keyring, table schema, and `allowedUnsignedAttributes` as you did in [**Step 1**](#ddb-java-migrate-step1). Remove the legacy attribute actions and `DynamoDBEncryptor` from your configuration.

1. Create a `DynamoDbEncryptionInterceptor`.

1. Create a new AWS SDK DynamoDB client.

1. Create the `DynamoDBEnhancedClient` and create a table with your modeled class.

   For more information on the DynamoDB Enhanced Client, see [create an enhanced client](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>

This topic explains how to install and use version 3.*x* of the .NET client-side encryption library for DynamoDB. For details about programming with the AWS Database Encryption SDK for DynamoDB, see the [.NET examples](https://github.com/aws/aws-database-encryption-sdk-dynamodb/tree/main/Examples/runtimes/net/src/) in the aws-database-encryption-sdk-dynamodb repository on GitHub.

The .NET client-side encryption library for DynamoDB is for developers who are writing applications in C\$1 and other .NET programming languages. It is supported on Windows, macOS, and Linux.

All [programming language](ddb-programming-languages.md) implementations of the AWS Database Encryption SDK for DynamoDB are interoperable. However, the SDK for .NET does not support empty values for list or map data types. This means that if you use the Java client-side encryption library for DynamoDB to write an item that contains empty values for a list or map data type, you cannot decrypt and read that item using the .NET client-side encryption library for DynamoDB.

**Topics**
+ [Installing](#ddb-net-install)
+ [Debugging](#ddb-net-debugging)
+ [Using the .NET client](ddb-net-using.md)
+ [.NET examples](ddb-net-examples.md)
+ [Add version 3.x to an existing table](ddb-net-config-existing-table.md)

## Installing the .NET client-side encryption library for DynamoDB
<a name="ddb-net-install"></a>

The .NET client-side encryption library for DynamoDB is available as the [AWS.Cryptography.DbEncryptionSDK.DynamoDb](https://www.nuget.org/packages/AWS.Cryptography.DbEncryptionSDK.DynamoDb/) package in NuGet. For details about installing and building the library, see the [.NET README.md](https://github.com/aws/aws-database-encryption-sdk-dynamodb/blob/main/DynamoDbEncryption/runtimes/net/README.md) file in the aws-database-encryption-sdk-dynamodb repository. The .NET client-side encryption library for DynamoDB requires the SDK for .NET even if you aren't using AWS Key Management Service (AWS KMS) keys. The SDK for .NET is installed with the NuGet package.

Version 3.*x* of the .NET client-side encryption library for DynamoDB supports .NET 6.0 and .NET Framework net48 and later.

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

The .NET client-side encryption library for DynamoDB does not generate any logs. Exceptions in the .NET client-side encryption library for DynamoDB generate an exception message, but no stack traces.

To help you debug, be sure to enable logging in the SDK for .NET. The logs and error messages from the SDK for .NET can help you distinguish errors arising in the SDK for .NET from those in the .NET client-side encryption library for DynamoDB. For help with SDK for .NET logging, see [AWSLogging](https://docs.aws.amazon.com/sdk-for-net/latest/developer-guide/net-dg-config-other.html#config-setting-awslogging) in the *AWS SDK for .NET Developer Guide*. (To see the topic, expand the **Open to view .NET Framework content** section.)

# Using the .NET client-side encryption library for DynamoDB
<a name="ddb-net-using"></a>

This topic explains some of the functions and helper classes in version 3.*x* of the .NET client-side encryption library for DynamoDB. 

For details about programming with the .NET client-side encryption library for DynamoDB, see the [.NET examples](https://github.com/aws/aws-database-encryption-sdk-dynamodb/tree/main/Examples/runtimes/net/src/) in the aws-database-encryption-sdk-dynamodb repository on GitHub.

**Topics**
+ [Item encryptors](#ddb-net-item-encryptors)
+ [Attribute actions](#ddb-net-attribute-actions)
+ [Encryption configuration](#ddb-net-config-encrypt)
+ [Updating items](#ddb-net-update-items)

## Item encryptors
<a name="ddb-net-item-encryptors"></a>

At its core, the AWS Database Encryption SDK for DynamoDB is an item encryptor. You can use version 3.*x* of the .NET client-side encryption library for DynamoDB to encrypt, sign, verify, and decrypt your DynamoDB table items in the following ways.

**The low-level AWS Database Encryption SDK for DynamoDB API**  
You can use your [table encryption configuration](#ddb-net-config-encrypt) to construct a DynamoDB client that automatically encrypts and signs items client-side with your DynamoDB `PutItem` requests. You can use this client directly, or you can construct a [document model](https://docs.aws.amazon.com/sdk-for-net/v3/developer-guide/dynamodb-intro.html#dynamodb-intro-apis-document) or [object persistence model](https://docs.aws.amazon.com/sdk-for-net/v3/developer-guide/dynamodb-intro.html#dynamodb-intro-apis-object-persistence).  
You must use the low-level AWS Database Encryption SDK for DynamoDB API to use [searchable encryption](searchable-encryption.md).

**The lower-level `DynamoDbItemEncryptor`**  
The lower-level `DynamoDbItemEncryptor` directly encrypts and signs or decrypts and verifies your table items without calling DynamoDB. It does not make DynamoDB `PutItem` or `GetItem` requests. For example, you can use the lower-level `DynamoDbItemEncryptor` to directly decrypt and verify a DynamoDB item that you have already retrieved. If you use the lower-level `DynamoDbItemEncryptor`, we recommend using the [low-level programming model](https://docs.aws.amazon.com/sdk-for-net/v3/developer-guide/dynamodb-intro.html#dynamodb-intro-apis-low-level)that the SDK for .NET provides for communicating with DynamoDB.  
The lower-level `DynamoDbItemEncryptor` does not support [searchable encryption](searchable-encryption.md).

## Attribute actions in the AWS Database Encryption SDK for DynamoDB
<a name="ddb-net-attribute-actions"></a>

[Attribute actions](concepts.md#crypt-actions) determine which attribute values are encrypted and signed, which are only signed, which are signed and included in the encryption context, and which are ignored.

To specify attribute actions with the .NET client, manually define attribute actions using an object model. Specify your attribute actions by creating a `Dictionary` object in which the name-value pairs represent attribute names and the specified actions.

Specify `ENCRYPT_AND_SIGN` to encrypt and sign an attribute. Specify `SIGN_ONLY` to sign, but not encrypt, an attribute. Specify `SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT` to sign an attribute and include it in the encryption context. You cannot encrypt an attribute without also signing it. Specify `DO_NOTHING` to ignore an attribute.

The partition and sort attributes must be either `SIGN_ONLY` or `SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`. If you define any attributes as `SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`, then the partition and sort attributes must also be `SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`.

**Note**  
After you define your attribute actions, you must define which attributes are excluded from the signatures. To make it easier to add new unsigned attributes in the future, we recommend choosing a distinct prefix (such as "`:`") to identify your unsigned attributes. Include this prefix in the attribute name for all attributes marked `DO_NOTHING` as you define your DynamoDB schema and attribute actions.

The following object model demonstrates how to specify `ENCRYPT_AND_SIGN`, `SIGN_ONLY`, `SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`, and `DO_NOTHING` attribute actions with the .NET client. This example uses the prefix "`:`" to identify `DO_NOTHING` attributes.

**Note**  
To use the `SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT` cryptographic action, you must use version 3.3 or later of the AWS Database Encryption SDK. Deploy the new version to all readers before [updating your data model](ddb-update-data-model.md) to include `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
};
```

## Encryption configuration in the AWS Database Encryption SDK for DynamoDB
<a name="ddb-net-config-encrypt"></a>

When you use the AWS Database Encryption SDK, you must explicitly define an encryption configuration for your DynamoDB table. The values required in your encryption configuration depend on whether you defined your attribute actions manually or with an annotated data class.

The following snippet defines a DynamoDB table encryption configuration using the low-level AWS Database Encryption SDK for DynamoDB API and allowed unsigned attributes defined by a distinct prefix.

```
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);
```

**Logical table name**  
A logical table name for your DynamoDB table.  
The logical table name is cryptographically bound to all data stored in the table to simplify DynamoDB restore operations. We strongly recommend specifying your DynamoDB table name as the logical table name when you first define your encryption configuration. You must always specify the same logical table name. For decryption to succeed, the logical table name must match the name specified on encryption. In the event that your DynamoDB table name changes after [restoring your DynamoDB table from a backup](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Restore.Tutorial.html), the logical table name ensures that the decrypt operation still recognizes the table.

**Allowed unsigned attributes**  
The attributes marked `DO_NOTHING` in your attribute actions.  
The allowed unsigned attributes tell the client which attributes are excluded from the signatures. The client assumes that all other attributes are included in the signature. Then, when decrypting a record, the client determines which attributes it needs to verify and which to ignore from the allowed unsigned attributes you specified. You cannot remove an attribute from your allowed unsigned attributes.  
You can define the allowed unsigned attributes explicitly by creating an array that lists all of your `DO_NOTHING` attributes. You can also specify a distinct prefix when naming your `DO_NOTHING` attributes and use the prefix to tell the client which attributes are unsigned. We strongly recommend specifying a distinct prefix because it simplifies the process of adding a new `DO_NOTHING` attribute in the future. For more information, see [Updating your data model](ddb-update-data-model.md).  
If you do not specify a prefix for all `DO_NOTHING` attributes, you can configure an `allowedUnsignedAttributes` array that explicitly lists all of the attributes that the client should expect to be unsigned when it encounters them on decryption. You should only explicitly define your allowed unsigned attributes if absolutely necessary.

**Search Configuration (Optional)**  
The `SearchConfig` defines the [beacon version](using-beacons.md#beacon-version).  
The `SearchConfig` must be specified to use [searchable encryption](searchable-encryption.md) or [signed beacons](configure.md#signed-beacons).

**Algorithm Suite (Optional)**  
The `algorithmSuiteId` defines which algorithm suite the AWS Database Encryption SDK uses.  
Unless you explicitly specify an alternative algorithm suite, the AWS Database Encryption SDK uses the [default algorithm suite](supported-algorithms.md#recommended-algorithms). The default algorithm suite uses the AES-GCM algorithm with key derivation, [digital signatures](concepts.md#digital-sigs), and [key commitment](concepts.md#key-commitment). Although the default algorithm suite is likely to be suitable for most applications, you can choose an alternate algorithm suite. For example, some trust models would be satisfied by an algorithm suite without digital signatures. For information about the algorithm suites that the AWS Database Encryption SDK supports, see [Supported algorithm suites in the AWS Database Encryption SDK](supported-algorithms.md).  
To select the [AES-GCM algorithm suite without ECDSA digital signatures](supported-algorithms.md#other-algorithms), include the following snippet in your table encryption configuration.  

```
AlgorithmSuiteId = DBEAlgorithmSuiteId.ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEY_SYMSIG_HMAC_SHA384
```

## Updating items with the AWS Database Encryption SDK
<a name="ddb-net-update-items"></a>

The AWS Database Encryption SDK does not support [ddb:UpdateItem](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_UpdateItem.html) for items that include encrypted or signed attributes. To update an encrypted or signed attribute, you must use [ddb:PutItem](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_PutItem.html). When you specify the same primary key as an existing item in your `PutItem` request, the new item completely replaces the existing item. You can also use [CLOBBER](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/dynamodbv2/datamodeling/DynamoDBMapperConfig.SaveBehavior.html#CLOBBER) to clear and replace all attributes on save after updating your items.

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

The following examples show you how to use the .NET client-side encryption library for DynamoDB to protect the table items in your application. To find more examples (and contribute your own), see the [.NET examples](https://github.com/aws/aws-database-encryption-sdk-dynamodb//tree/main/Examples/runtimes/net/src) in the aws-database-encryption-sdk-dynamodb repository on GitHub.

The following examples demonstrate how to configure the .NET client-side encryption library for DynamoDB in a new, unpopulated Amazon DynamoDB table. If you want to configure your existing Amazon DynamoDB tables for client-side encryption, see [Add version 3.x to an existing table](ddb-net-config-existing-table.md).

**Topics**
+ [Using the low-level AWS Database Encryption SDK for DynamoDB API](#ddb-net-lowlevel-API-example)
+ [Using the lower-level `DynamoDbItemEncryptor`](#ddb-net-itemencryptor)

## Using the low-level AWS Database Encryption SDK for DynamoDB API
<a name="ddb-net-lowlevel-API-example"></a>

The following example shows how to use the low-level AWS Database Encryption SDK for DynamoDB API with an [AWS KMS keyring](use-kms-keyring.md) to automatically encrypt and sign items client-side with your DynamoDB `PutItem` requests.

You can use any supported [keyring](keyrings.md), but we recommend using one of the AWS KMS keyrings whenever possible.

**See the complete code sample**: [BasicPutGetExample.cs](https://github.com/aws/aws-database-encryption-sdk-dynamodb/tree/main/Examples/runtimes/net/src/BasicPutGetExample.cs)

**Step 1: Create the AWS KMS keyring**  
The following example uses `CreateAwsKmsMrkMultiKeyring` to create an AWS KMS keyring with a symmetric encryption KMS key. The `CreateAwsKmsMrkMultiKeyring` method ensures that the keyring will correctly handle both single-Region and multi-Region keys.  

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

**Step 2: Configure your attribute actions**  
The following example defines an `attributeActionsOnEncrypt` Dictionary that represents sample [attribute actions](concepts.md#crypt-actions) for a table item.  
The following example does not define any attributes as `SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`. If you specify any `SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT` attributes, then the partition and sort attributes must also be `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
};
```

**Step 3: Define which attributes are excluded from the signatures**  
The following example assumes that all `DO_NOTHING` attributes share the distinct prefix "`:`", and uses the prefix to define the allowed unsigned attributes. The client assumes that any attribute name with the "`:`" prefix is excluded from the signatures. For more information, see [Allowed unsigned attributes](ddb-net-using.md#net-allowed-unauth).  

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

**Step 4: Define the DynamoDB table encryption configuration**  
The following example defines a `tableConfigs` Map that represents the encryption configuration for this DynamoDB table.  
This example specifies the DynamoDB table name as the [logical table name](ddb-net-using.md#net-logical-table-name). We strongly recommend specifying your DynamoDB table name as the logical table name when you first define your encryption configuration. For more information, see [Encryption configuration in the AWS Database Encryption SDK for DynamoDB](ddb-net-using.md#ddb-net-config-encrypt).  
To use [searchable encryption](searchable-encryption.md) or [signed beacons](configure.md#signed-beacons), you must also include the [`SearchConfig`](ddb-java-using.md#ddb-search-config) in your encryption configuration.

```
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);
```

**Step 5: Create a new AWS SDK DynamoDB client**  
The following example creates a new AWS SDK DynamoDB client using the `TableEncryptionConfigs` from **Step 4**.  

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

**Step 6: Encrypt and sign a DynamoDB table item**  
The following example defines an `item` Dictionary that represents a sample table item and puts the item in the DynamoDB table. The item is encrypted and signed client-side before it is sent to 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);
```

## Using the lower-level `DynamoDbItemEncryptor`
<a name="ddb-net-itemencryptor"></a>

The following example shows how to use the lower-level `DynamoDbItemEncryptor` with an [AWS KMS keyring](use-kms-keyring.md) to directly encrypt and sign table items. The `DynamoDbItemEncryptor` does not put the item in your DynamoDB table.

You can use any supported [keyring](keyrings.md) with the DynamoDB Enhanced Client, but we recommend using one of the AWS KMS keyrings whenever possible.

**Note**  
The lower-level `DynamoDbItemEncryptor` does not support [searchable encryption](searchable-encryption.md). Use the the low-level AWS Database Encryption SDK for DynamoDB API to use searchable encryption.

**See the complete code sample**: [ItemEncryptDecryptExample.cs](https://github.com/aws/aws-database-encryption-sdk-dynamodb/tree/main/Examples/runtimes/net/src/itemencryptor/ItemEncryptDecryptExample.cs)

**Step 1: Create the AWS KMS keyring**  
The following example uses `CreateAwsKmsMrkMultiKeyring` to create an AWS KMS keyring with a symmetric encryption KMS key. The `CreateAwsKmsMrkMultiKeyring` method ensures that the keyring will correctly handle both single-Region and multi-Region keys.  

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

**Step 2: Configure your attribute actions**  
The following example defines an `attributeActionsOnEncrypt` Dictionary that represents sample [attribute actions](concepts.md#crypt-actions) for a table item.  
The following example does not define any attributes as `SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`. If you specify any `SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT` attributes, then the partition and sort attributes must also be `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
};
```

**Step 3: Define which attributes are excluded from the signatures**  
The following example assumes that all `DO_NOTHING` attributes share the distinct prefix "`:`", and uses the prefix to define the allowed unsigned attributes. The client assumes that any attribute name with the "`:`" prefix is excluded from the signatures. For more information, see [Allowed unsigned attributes](ddb-net-using.md#net-allowed-unauth).  

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

**Step 4: Define the `DynamoDbItemEncryptor` configuration**  
The following example defines the configuration for the `DynamoDbItemEncryptor`.  
This example specifies the DynamoDB table name as the [logical table name](ddb-net-using.md#net-logical-table-name). We strongly recommend specifying your DynamoDB table name as the logical table name when you first define your encryption configuration. For more information, see [Encryption configuration in the AWS Database Encryption SDK for DynamoDB](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
};
```

**Step 5: Create the `DynamoDbItemEncryptor`**  
The following example creates a new `DynamoDbItemEncryptor` using the `config` from **Step 4**.  

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

**Step 6: Directly encrypt and sign a table item**  
The following example directly encrypts and signs an item using the `DynamoDbItemEncryptor`. The `DynamoDbItemEncryptor` does not put the item in your DynamoDB table.  

```
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;
```

# Configure an existing DynamoDB table to use the AWS Database Encryption SDK for DynamoDB
<a name="ddb-net-config-existing-table"></a>

With version 3.*x* of the .NET client-side encryption library for DynamoDB, you can configure your existing Amazon DynamoDB tables for client-side encryption. This topic provides guidance on the three steps you must take to add version 3.*x* to an existing, populated DynamoDB table.

## Step 1: Prepare to read and write encrypted items
<a name="ddb-net-add-step1"></a>

Complete the following steps to prepare your AWS Database Encryption SDK client to read and write encrypted items. After you deploy the following changes, your client will continue to read and write plaintext items. It will not encrypt or sign any new items written to the table, but it will be able to decrypt encrypted items as soon as they appear. These changes prepare the client to begin [encrypting new items](#ddb-net-add-step2). The following changes must be deployed to each reader before you proceed to the next step.

**1. Define your [attribute actions](concepts.md#crypt-actions)**  
Create an object model to define which attribute values will be encrypted and signed, which will be only signed, and which will be ignored.  
By default, primary key attributes are signed but not encrypted (`SIGN_ONLY`) and all other attributes are encrypted and signed (`ENCRYPT_AND_SIGN`).  
Specify `ENCRYPT_AND_SIGN` to encrypt and sign an attribute. Specify `SIGN_ONLY` to sign, but not encrypt, an attribute. Specify `SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT` to sign and attribute and include it in the encryption context. You cannot encrypt an attribute without also signing it. Specify `DO_NOTHING` to ignore an attribute. For more information, see [Attribute actions in the AWS Database Encryption SDK for DynamoDB](ddb-net-using.md#ddb-net-attribute-actions).  
If you specify any `SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT` attributes, then the partition and sort attributes must also be `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. Define which attributes will be excluded from the signatures**  
The following example assumes that all `DO_NOTHING` attributes share the distinct prefix "`:`", and uses the prefix to define the allowed unsigned attributes. The client will assume that any attribute name with the "`:`" prefix is excluded from the signatures. For more information, see [Allowed unsigned attributes](ddb-net-using.md#net-allowed-unauth).  

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

**3. Create a [keyring](keyrings.md)**  
The following example creates an [AWS KMS keyring](use-kms-keyring.md). The AWS KMS keyring uses symmetric encryption or asymmetric RSA AWS KMS keys to generate, encrypt, and decrypt data keys.  
This example uses `CreateMrkMultiKeyring` to create an AWS KMS keyring with a symmetric encryption KMS key. The `CreateAwsKmsMrkMultiKeyring` method ensures that the keyring will correctly handle both single-Region and multi-Region keys.  

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

**4. Define the DynamoDB table encryption configuration **  
The following example defines a `tableConfigs` Map that represents the encryption configuration for this DynamoDB table.  
This example specifies the DynamoDB table name as the [logical table name](ddb-net-using.md#net-logical-table-name). We strongly recommend specifying your DynamoDB table name as the logical table name when you first define your encryption configuration.  
You must specify `FORCE_WRITE_PLAINTEXT_ALLOW_READ_PLAINTEXT` as the plaintext override. This policy continues to read and write plaintext items, reads encrypted items, and prepares the client to write encrypted items.  
For more information on the values included in the table encryption configuration, see [Encryption configuration in the AWS Database Encryption SDK for DynamoDB](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. Create a new AWS SDK DynamoDB client**  
he following example creates a new AWS SDK DynamoDB client using the `TableEncryptionConfigs` from **Step 4**.  

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

## Step 2: Write encrypted and signed items
<a name="ddb-net-add-step2"></a>

Update the plaintext policy in your table encryption configuration to allow the client to write encrypted and signed items. After you deploy the following change, the client will encrypt and sign new items based on the attribute actions you configured in **Step 1**. The client will be able read plaintext items and encrypted and signed items.

Before you proceed to [Step 3](#ddb-net-add-step3), you must encrypt and sign all existing plaintext items in your table. There is no single metric or query that you can run to quickly encrypt your existing plaintext items. Use the process that makes the most sense for your system. For example, you could use an asynchronous process that slowly scans the table and the rewrites the items using the attribute actions and encryption configuration you defined. To identify the plaintext items in your table, we recommend scanning for all items that do not contain the `aws_dbe_head` and `aws_dbe_foot` attributes that the AWS Database Encryption SDK adds to items when they're encrypted and signed.

The following example updates the table encryption configuration from **Step 1**. You must update the plaintext override with `FORBID_WRITE_PLAINTEXT_ALLOW_READ_PLAINTEXT`. This policy continues to read plaintext items, but also reads and writes encrypted items. Create a new AWS SDK DynamoDB client using the updated `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);
```

## Step 3: Only read encrypted and signed items
<a name="ddb-net-add-step3"></a>

After you have encrypted and signed all of your items, update the plaintext override in your table encryption configuration to only allow the client to read and write encrypted and signed items. After you deploy the following change, the client will encrypt and sign new items based on the attribute actions you configured in **Step 1**. The client will only be able read encrypted and signed items.

The following example updates the table encryption configuration from **Step 2**. You can either update the plaintext override with `FORBID_WRITE_PLAINTEXT_FORBID_READ_PLAINTEXT` or remove the plaintext policy from your configuration. The client only reads and writes encrypted and signed items by default. Create a new AWS SDK DynamoDB client using the updated `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>

This topic explains how to install and use version 1.*x* of the Rust client-side encryption library for DynamoDB. For details about programming with the AWS Database Encryption SDK for DynamoDB, see the [Rust examples](https://github.com/aws/aws-database-encryption-sdk-dynamodb/blob/main/releases/rust/db_esdk/examples/) in the aws-database-encryption-sdk-dynamodb repository on GitHub.

All programming language implementations of the AWS Database Encryption SDK for DynamoDB are interoperable.

**Topics**
+ [Prerequisites](#ddb-rust-prerequisites)
+ [Installation](#ddb-rust-install)
+ [Using the Rust client](ddb-rust-using.md)

## Prerequisites
<a name="ddb-rust-prerequisites"></a>

Before you install the Rust client-side encryption library for DynamoDB, be sure you have the following prerequisites.

**Install Rust and Cargo**  
Install the current stable release of [Rust](https://www.rust-lang.org/) using [rustup](https://rustup.rs/).  
For more information on downloading and installing rustup, see the [installation procedures](https://doc.rust-lang.org/cargo/getting-started/installation.html) in The Cargo Book.

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

The Rust client-side encryption library for DynamoDB is available as the [aws-db-esdk](https://crates.io/crates/aws-db-esdk) crate on Crates.io. For details about installing and building the library, see the [ README.md](https://github.com/aws/aws-database-encryption-sdk-dynamodb/) file in the aws-database-encryption-sdk-dynamodb GitHub repository.

**Manually**  
To install the Rust client-side encryption library for DynamoDB, clone or download the [aws-database-encryption-sdk-dynamodb](https://github.com/aws/aws-database-encryption-sdk-dynamodb/) GitHub repository.

**To install the latest version**  
Run the following Cargo command in your project directory:  

```
cargo add aws-db-esdk
```
Or add the following line to your Cargo.toml:  

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

# Using the Rust client-side encryption library for DynamoDB
<a name="ddb-rust-using"></a>

This topic explains some of the functions and helper classes in version 1.*x* of the Rust client-side encryption library for DynamoDB. 

For details about programming with the Rust client-side encryption library for DynamoDB, see the [Rust examples](https://github.com/aws/aws-database-encryption-sdk-dynamodb/blob/main/releases/rust/db_esdk/examples/) in the aws-database-encryption-sdk-dynamodb repository on GitHub.

**Topics**
+ [Item encryptors](#ddb-rust-item-encryptors)
+ [Attribute actions](#ddb-rust-attribute-actions)
+ [Encryption configuration](#ddb-rust-config-encrypt)
+ [Updating items](#ddb-rust-update-items)

## Item encryptors
<a name="ddb-rust-item-encryptors"></a>

At its core, the AWS Database Encryption SDK for DynamoDB is an item encryptor. You can use version 1.*x* of the Rust client-side encryption library for DynamoDB to encrypt, sign, verify, and decrypt your DynamoDB table items in the following ways.

**The low-level AWS Database Encryption SDK for DynamoDB API**  
You can use your [table encryption configuration](#ddb-rust-config-encrypt) to construct a DynamoDB client that automatically encrypts and signs items client-side with your DynamoDB `PutItem` requests.  
You must use the low-level AWS Database Encryption SDK for DynamoDB API to use [searchable encryption](searchable-encryption.md).  
For an example demonstrating how to use the low-level AWS Database Encryption SDK for DynamoDB API, see [basic\$1get\$1put\$1example.rs](https://github.com/aws/aws-database-encryption-sdk-dynamodb/blob/main/releases/rust/db_esdk/examples/basic_get_put_example.rs) in the aws-database-encryption-sdk-dynamodb repository on GitHub.

**The lower-level `DynamoDbItemEncryptor`**  
The lower-level `DynamoDbItemEncryptor` directly encrypts and signs or decrypts and verifies your table items without calling DynamoDB. It does not make DynamoDB `PutItem` or `GetItem` requests. For example, you can use the lower-level `DynamoDbItemEncryptor` to directly decrypt and verify a DynamoDB item that you have already retrieved.  
The lower-level `DynamoDbItemEncryptor` does not support [searchable encryption](searchable-encryption.md).  
For an example demonstrating how to use the lower-level `DynamoDbItemEncryptor`, see [item\$1encrypt\$1decrypt.rs](https://github.com/aws/aws-database-encryption-sdk-dynamodb/blob/main/releases/rust/db_esdk/examples/itemencryptor/item_encrypt_decrypt.rs) in the aws-database-encryption-sdk-dynamodb repository on GitHub.

## Attribute actions in the AWS Database Encryption SDK for DynamoDB
<a name="ddb-rust-attribute-actions"></a>

[Attribute actions](concepts.md#crypt-actions) determine which attribute values are encrypted and signed, which are only signed, which are signed and included in the encryption context, and which are ignored.

To specify attribute actions with the Rust client, manually define attribute actions using an object model. Specify your attribute actions by creating a `HashMap` object in which the name-value pairs represent attribute names and the specified actions.

Specify `ENCRYPT_AND_SIGN` to encrypt and sign an attribute. Specify `SIGN_ONLY` to sign, but not encrypt, an attribute. Specify `SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT` to sign an attribute and include it in the encryption context. You cannot encrypt an attribute without also signing it. Specify `DO_NOTHING` to ignore an attribute.

The partition and sort attributes must be either `SIGN_ONLY` or `SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`. If you define any attributes as `SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`, then the partition and sort attributes must also be `SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`.

**Note**  
After you define your attribute actions, you must define which attributes are excluded from the signatures. To make it easier to add new unsigned attributes in the future, we recommend choosing a distinct prefix (such as "`:`") to identify your unsigned attributes. Include this prefix in the attribute name for all attributes marked `DO_NOTHING` as you define your DynamoDB schema and attribute actions.

The following object model demonstrates how to specify `ENCRYPT_AND_SIGN`, `SIGN_ONLY`, `SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT`, and `DO_NOTHING` attribute actions with the Rust client. This example uses the prefix "`:`" to identify `DO_NOTHING` attributes.

```
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),
]);
```

## Encryption configuration in the AWS Database Encryption SDK for DynamoDB
<a name="ddb-rust-config-encrypt"></a>

When you use the AWS Database Encryption SDK, you must explicitly define an encryption configuration for your DynamoDB table. The values required in your encryption configuration depend on whether you defined your attribute actions manually or with an annotated data class.

The following snippet defines a DynamoDB table encryption configuration using the low-level AWS Database Encryption SDK for DynamoDB API and allowed unsigned attributes defined by a distinct prefix.

```
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()?;
```

**Logical table name**  
A logical table name for your DynamoDB table.  
The logical table name is cryptographically bound to all data stored in the table to simplify DynamoDB restore operations. We strongly recommend specifying your DynamoDB table name as the logical table name when you first define your encryption configuration. You must always specify the same logical table name. For decryption to succeed, the logical table name must match the name specified on encryption. In the event that your DynamoDB table name changes after [restoring your DynamoDB table from a backup](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Restore.Tutorial.html), the logical table name ensures that the decrypt operation still recognizes the table.

**Allowed unsigned attributes**  
The attributes marked `DO_NOTHING` in your attribute actions.  
The allowed unsigned attributes tell the client which attributes are excluded from the signatures. The client assumes that all other attributes are included in the signature. Then, when decrypting a record, the client determines which attributes it needs to verify and which to ignore from the allowed unsigned attributes you specified. You cannot remove an attribute from your allowed unsigned attributes.  
You can define the allowed unsigned attributes explicitly by creating an array that lists all of your `DO_NOTHING` attributes. You can also specify a distinct prefix when naming your `DO_NOTHING` attributes and use the prefix to tell the client which attributes are unsigned. We strongly recommend specifying a distinct prefix because it simplifies the process of adding a new `DO_NOTHING` attribute in the future. For more information, see [Updating your data model](ddb-update-data-model.md).  
If you do not specify a prefix for all `DO_NOTHING` attributes, you can configure an `allowedUnsignedAttributes` array that explicitly lists all of the attributes that the client should expect to be unsigned when it encounters them on decryption. You should only explicitly define your allowed unsigned attributes if absolutely necessary.

**Search Configuration (Optional)**  
The `SearchConfig` defines the [beacon version](using-beacons.md#beacon-version).  
The `SearchConfig` must be specified to use [searchable encryption](searchable-encryption.md) or [signed beacons](configure.md#signed-beacons).

**Algorithm Suite (Optional)**  
The `algorithmSuiteId` defines which algorithm suite the AWS Database Encryption SDK uses.  
Unless you explicitly specify an alternative algorithm suite, the AWS Database Encryption SDK uses the [default algorithm suite](supported-algorithms.md#recommended-algorithms). The default algorithm suite uses the AES-GCM algorithm with key derivation, [digital signatures](concepts.md#digital-sigs), and [key commitment](concepts.md#key-commitment). Although the default algorithm suite is likely to be suitable for most applications, you can choose an alternate algorithm suite. For example, some trust models would be satisfied by an algorithm suite without digital signatures. For information about the algorithm suites that the AWS Database Encryption SDK supports, see [Supported algorithm suites in the AWS Database Encryption SDK](supported-algorithms.md).  
To select the [AES-GCM algorithm suite without ECDSA digital signatures](supported-algorithms.md#other-algorithms), include the following snippet in your table encryption configuration.  

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

## Updating items with the AWS Database Encryption SDK
<a name="ddb-rust-update-items"></a>

The AWS Database Encryption SDK does not support [ddb:UpdateItem](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_UpdateItem.html) for items that include encrypted or signed attributes. To update an encrypted or signed attribute, you must use [ddb:PutItem](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_PutItem.html). When you specify the same primary key as an existing item in your `PutItem` request, the new item completely replaces the existing item.

# Legacy DynamoDB Encryption Client
<a name="legacy-dynamodb-encryption-client"></a>

On June 9, 2023, our client-side encryption library was renamed to AWS Database Encryption SDK. The AWS Database Encryption SDK continues to support legacy DynamoDB Encryption Client versions. For more information on the different parts of the client-side encryption library that changed with the rename, see [Amazon DynamoDB Encryption Client rename](DDBEC-rename.md).

To migrate to the latest version of the Java client-side encryption library for DynamoDB, see [Migrate to version 3.x](ddb-java-migrate.md).

**Topics**
+ [AWS Database Encryption SDK for DynamoDB version support](#legacy-support)
+ [How the DynamoDB Encryption Client works](DDBEC-legacy-how-it-works.md)
+ [Amazon DynamoDB Encryption Client concepts](DDBEC-legacy-concepts.md)
+ [Cryptographic materials provider](crypto-materials-providers.md)
+ [Amazon DynamoDB Encryption Client available programming languages](programming-languages.md)
+ [Changing your data model](data-model.md)
+ [Troubleshooting issues in your DynamoDB Encryption Client application](troubleshooting.md)

## AWS Database Encryption SDK for DynamoDB version support
<a name="legacy-support"></a>

The topics in the Legacy chapter provide information on versions 1.*x*—2.*x* of the DynamoDB Encryption Client for Java and versions 1.*x*—3.*x* of the DynamoDB Encryption Client for Python.

The following table lists the languages and versions that support client-side encryption in Amazon DynamoDB.


| Programming language | Version | SDK major version life-cycle phase | 
| --- | --- | --- | 
|  Java  |  Versions 1.*x*  |  [End-of-Support phase](https://docs.aws.amazon.com/sdkref/latest/guide/maint-policy.html#version-life-cycle), effective July 2022  | 
|  Java  |  Versions 2.*x*  |  [General Availability](https://docs.aws.amazon.com/sdkref/latest/guide/maint-policy.html#version-life-cycle) (GA)  | 
|  Java  |  Version 3.*x*  |  [General Availability](https://docs.aws.amazon.com/sdkref/latest/guide/maint-policy.html#version-life-cycle) (GA)  | 
|  Python  |  Versions 1.*x*  |  [End-of-Support phase](https://docs.aws.amazon.com/sdkref/latest/guide/maint-policy.html#version-life-cycle), effective July 2022  | 
|  Python  |  Versions 2.*x*  |  [End-of-Support phase](https://docs.aws.amazon.com/sdkref/latest/guide/maint-policy.html#version-life-cycle), effective July 2022  | 
|  Python  |  Versions 3.*x*  |  [General Availability](https://docs.aws.amazon.com/sdkref/latest/guide/maint-policy.html#version-life-cycle) (GA)  | 

# How the DynamoDB Encryption Client works
<a name="DDBEC-legacy-how-it-works"></a>

**Note**  
Our client-side encryption library was [renamed to AWS Database Encryption SDK](DDBEC-rename.md). The following topic provides information on versions 1.*x*—2.*x* of the DynamoDB Encryption Client for Java and versions 1.*x*—3.*x* of the DynamoDB Encryption Client for Python. For more information, see [AWS Database Encryption SDK for DynamoDB version support](legacy-dynamodb-encryption-client.md#legacy-support).

The DynamoDB Encryption Client is designed specifically to protect the data that you store in DynamoDB. The libraries include secure implementations that you can extend or use unchanged. And, most elements are represented by abstract elements so you can create and use compatible custom components.

**Encrypting and signing table items**

At the core of the DynamoDB Encryption Client is an *item encryptor* that encrypts, signs, verifies, and decrypts table items. It takes in information about your table items and instructions about which items to encrypt and sign. It gets the encryption materials, and instructions on how to use them, from a [cryptographic material provider](DDBEC-legacy-concepts.md#concept-material-provider) that you select and configure. 

The following diagram shows a high-level view of this process.

![\[Encrypting and signing items in the DynamoDB Encryption Client\]](http://docs.aws.amazon.com/database-encryption-sdk/latest/devguide/images/arch-encrypt.png)


To encrypt and sign a table item, the DynamoDB Encryption Client needs:
+ **Information about the table. ** It gets information about the table from a [DynamoDB encryption context](concepts.md#encryption-context) that you supply. Some helpers get the required information from DynamoDB and create the DynamoDB encryption context for you. 
**Note**  
The *DynamoDB encryption context* in the DynamoDB Encryption Client is not related to the *encryption context* in AWS Key Management Service (AWS KMS) and the AWS Encryption SDK.
+ **Which attributes to encrypt and sign.** It gets this information from the [attribute actions](DDBEC-legacy-concepts.md#legacy-attribute-actions) that you supply.
+ **Encryption materials, including encryption and signing keys.** It gets these from a [cryptographic materials provider](DDBEC-legacy-concepts.md#concept-material-provider) (CMP) that you select and configure. 
+ **Instructions for encrypting and signing the item**. The CMP adds instructions for using the encryption materials, including encryption and signing algorithms, to the [actual material description](DDBEC-legacy-concepts.md#legacy-material-description).

The [item encryptor](DDBEC-legacy-concepts.md#item-encryptor) uses all of these elements to encrypt and sign the item. The item encryptor also adds two attributes to the item: a [material description attribute](DDBEC-legacy-concepts.md#legacy-material-description) that contains the encryption and signing instructions (the actual material description), and an attribute that contains the signature. You can interact with the item encryptor directly, or use helper features that interact with the item encryptor for you to implement secure default behavior.

The result is a DynamoDB item containing encrypted and signed data.

**Verifying and decrypting table items**

These components also work together to verify and decrypt your item, as shown in the following diagram.

![\[Verifying and decrypting items in the DynamoDB Encryption Client\]](http://docs.aws.amazon.com/database-encryption-sdk/latest/devguide/images/arch-decrypt.png)


To verify and decrypt an item, the DynamoDB Encryption Client needs the same components, components with the same configuration, or components especially designed for decrypting the items, as follows:
+ **Information about the table** from the [DynamoDB encryption context](concepts.md#encryption-context).
+ **Which attributes to verify and decrypt.** It gets these from the [attribute actions](DDBEC-legacy-concepts.md#legacy-attribute-actions).
+ **Decryption materials, including verification and decryption keys**, from the [cryptographic materials provider](DDBEC-legacy-concepts.md#concept-material-provider) (CMP) that you select and configure.

  The encrypted item doesn't include any record of the CMP that was used to encrypt it. You must supply the same CMP, a CMP with the same configuration, or a CMP that is designed to decrypt items.
+ **Information about how the item was encrypted and signed**, including the encryption and signing algorithms. The client gets these from the [material description attribute](DDBEC-legacy-concepts.md#legacy-material-description) in the item.

The [item encryptor](DDBEC-legacy-concepts.md#item-encryptor) uses all of these elements to verify and decrypt the item. It also removes the material description and signature attributes. The result is a plaintext DynamoDB item.

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

**Note**  
Our client-side encryption library was [renamed to AWS Database Encryption SDK](DDBEC-rename.md). The following topic provides information on versions 1.*x*—2.*x* of the DynamoDB Encryption Client for Java and versions 1.*x*—3.*x* of the DynamoDB Encryption Client for Python. For more information, see [AWS Database Encryption SDK for DynamoDB version support](legacy-dynamodb-encryption-client.md#legacy-support).

This topic explains the concepts and terminology used in the Amazon DynamoDB Encryption Client. 

To learn how the components of the DynamoDB Encryption Client interact, see [How the DynamoDB Encryption Client works](DDBEC-legacy-how-it-works.md).

**Topics**
+ [Cryptographic materials provider (CMP)](#concept-material-provider)
+ [Item encryptors](#item-encryptor)
+ [Attribute actions](#legacy-attribute-actions)
+ [Material description](#legacy-material-description)
+ [DynamoDB encryption context](#legacy-encryption-context)
+ [Provider store](#provider-store)

## Cryptographic materials provider (CMP)
<a name="concept-material-provider"></a>

When implementing the DynamoDB Encryption Client, one of your first tasks is to [select a cryptographic materials provider](crypto-materials-providers.md) (CMP) (also known as an *encryption materials provider*). Your choice determines much of the rest of the implementation. 

A *cryptographic materials provider* (CMP) collects, assembles, and returns the cryptographic materials that the [item encryptor](#item-encryptor) uses to encrypt and sign your table items. The CMP determines the encryption algorithms to use and how to generate and protect encryption and signing keys.

The CMP interacts with the item encryptor. The item encryptor requests encryption or decryption materials from the CMP, and the CMP returns them to the item encryptor. Then, the item encryptor uses the cryptographic materials to encrypt and sign, or verify and decrypt, the item.

You specify the CMP when you configure the client. You can create a compatible custom CMP, or use one of the many CMPs in the library. Most CMPs are available for multiple programming languages. 

## Item encryptors
<a name="item-encryptor"></a>

The *item encryptor* is a lower-level component that performs cryptographic operations for the DynamoDB Encryption Client. It requests cryptographic materials from a [cryptographic materials provider](#concept-material-provider) (CMP), then uses the materials that the CMP returns to encrypt and sign, or verify and decrypt, your table item.

You can interact with the item encryptor directly or use the helpers that your library provides. For example, the DynamoDB Encryption Client for Java includes an `AttributeEncryptor` helper class that you can use with the `DynamoDBMapper`, instead of interacting directly with the `DynamoDBEncryptor` item encryptor. The Python library includes `EncryptedTable`, `EncryptedClient`, and `EncryptedResource` helper classes that interact with the item encryptor for you.

## Attribute actions
<a name="legacy-attribute-actions"></a>

*Attribute actions* tell the item encryptor which actions to perform on each attribute of the item. 

The attribute action values can be one of the following:
+ **Encrypt and sign** – Encrypt the attribute value. Include the attribute (name and value) in the item signature.
+ **Sign only** – Include the attribute in the item signature.
+ **Do nothing** – Do not encrypt or sign the attribute.

For any attribute that can store sensitive data, use **Encrypt and sign**. For primary key attributes (partition key and sort key), use **Sign only**. The [material description attribute](#legacy-material-description) and the signature attribute are not signed or encrypted. You don't need to specify attribute actions for these attributes.

Choose your attribute actions carefully. When in doubt, use **Encrypt and sign**. Once you have used the DynamoDB Encryption Client to protect your table items, you cannot change the action for an attribute without risking a signature validation error. For details, see [Changing your data model](data-model.md).

**Warning**  
Do not encrypt the primary key attributes. They must remain in plaintext so DynamoDB can find the item without running a full table scan.

If the [DynamoDB encryption context](concepts.md#encryption-context) identifies your primary key attributes, the client will throw an error if you try to encrypt them.

The technique that you use to specify the attribute actions is different for each programming language. It might also be specific to helper classes that you use.

For details, see the documentation for your programming language.
+ [Python](python-using.md#python-attribute-actions)
+ [Java](java-using.md#attribute-actions-java)

## Material description
<a name="legacy-material-description"></a>

The *material description* for an encrypted table item consists of information, such as encryption algorithms, about how the table item is encrypted and signed. The [cryptographic materials provider](#concept-material-provider) (CMP) records the material description as it assembles the cryptographic materials for encryption and signing. Later, when it needs to assemble cryptographic materials to verify and decrypt the item, it uses the material description as its guide. 

In the DynamoDB Encryption Client, the material description refers to three related elements:

**Requested material description**  
Some [cryptographic materials providers](#concept-material-provider) (CMPs) let you specify advanced options, such as an encryption algorithm. To indicate your choices, you add name-value pairs to the material description property of the [DynamoDB encryption context](concepts.md#encryption-context) in your request to encrypt a table item. This element is known as the *requested material description*. The valid values in the requested material description are defined by the CMP that you choose.   
Because the material description can override secure default values, we recommend that you omit the requested material description unless you have a compelling reason to use it.

**Actual material description**  
The material description that the [cryptographic materials providers](#concept-material-provider) (CMPs) return is known as the *actual material description*. It describes the actual values that the CMP used when it assembled the cryptographic materials. It usually consists of the requested material description, if any, with additions and changes.

**Material description attribute**  
The client saves the actual material description in the *material description attribute* of the encrypted item. The material description attribute name is `amzn-ddb-map-desc` and its value is the actual material description. The client uses the values in the material description attribute to verify and decrypt the item.

## DynamoDB encryption context
<a name="legacy-encryption-context"></a>

The *DynamoDB encryption context* supplies information about the table and item to the [cryptographic materials provider](#concept-material-provider) (CMP). In advanced implementations, the DynamoDB encryption context can include a [requested material description](#legacy-material-description).

When you encrypt table items, the DynamoDB encryption context is cryptographically bound to the encrypted attribute values. When you decrypt, if the DynamoDB encryption context is not an exact, case-sensitive match for the DynamoDB encryption context that was used to encrypt, the decrypt operation fails. If you interact with the [item encryptor](#item-encryptor) directly, you must provide a DynamoDB encryption context when you call an encrypt or decrypt method. Most helpers create the DynamoDB encryption context for you.

**Note**  
The *DynamoDB encryption context* in the DynamoDB Encryption Client is not related to the *encryption context* in AWS Key Management Service (AWS KMS) and the AWS Encryption SDK.

The DynamoDB encryption context can include the following fields. All fields and values are optional.
+ Table name
+ Partition key name
+ Sort key name
+ Attribute name-value pairs
+ [Requested material description](#legacy-material-description)

## Provider store
<a name="provider-store"></a>

A *provider store* is a component that returns [cryptographic materials providers](#concept-material-provider) (CMPs). The provider store can create the CMPs or get them from another source, such as another provider store. The provider store saves versions of the CMPs that it creates in persistent storage in which each stored CMP is identified by the material name of the requester and version number. 

The [Most Recent Provider](most-recent-provider.md) in the DynamoDB Encryption Client gets its CMPs from a provider store, but you can use the provider store to supply CMPs to any component. Each Most Recent Provider is associated with one provider store, but a provider store can supply CMPs to many requesters across multiple hosts.

The provider store creates new versions of CMPs on demand, and returns new and existing versions. It also returns the latest version number for a given material name. This lets the requester know when the provider store has a new version of its CMP that it can request.

The DynamoDB Encryption Client includes a[ MetaStore](most-recent-provider.md#about-metastore), which is a provider store that creates Wrapped CMPs with keys that are stored in DynamoDB and encrypted by using an internal DynamoDB Encryption Client. 

**Learn more:**
+ Provider store: [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)

# Cryptographic materials provider
<a name="crypto-materials-providers"></a>

**Note**  
Our client-side encryption library was [renamed to AWS Database Encryption SDK](DDBEC-rename.md). The following topic provides information on versions 1.*x*—2.*x* of the DynamoDB Encryption Client for Java and versions 1.*x*—3.*x* of the DynamoDB Encryption Client for Python. For more information, see [AWS Database Encryption SDK for DynamoDB version support](legacy-dynamodb-encryption-client.md#legacy-support).

One of the most important decisions you make when using the DynamoDB Encryption Client is selecting a [cryptographic materials provider](DDBEC-legacy-concepts.md#concept-material-provider) (CMP). The CMP assembles and returns cryptographic materials to the item encryptor. It also determines how encryption and signing keys are generated, whether new key materials are generated for each item or are reused, and the encryption and signing algorithms that are used. 

You can choose a CMP from the implementations provided in the DynamoDB Encryption Client libraries or build a compatible custom CMP. Your CMP choice might also depend on the [programming language](programming-languages.md) that you use.

This topic describes the most common CMPs and offers some advice to help you choose the best one for your application.

**Direct KMS Materials Provider**  
The Direct KMS Materials Provider protects your table items under an [AWS KMS key](https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#master_keys) that never leaves [AWS Key Management Service](https://docs.aws.amazon.com/kms/latest/developerguide/) (AWS KMS) unencrypted. Your application doesn't have to generate or manage any cryptographic materials. Because it uses the AWS KMS key to generate unique encryption and signing keys for each item, this provider calls AWS KMS every time it encrypts or decrypts an item.   
If you use AWS KMS and one AWS KMS call per transaction is practical for your application, this provider is a good choice.  
For details, see [Direct KMS Materials Provider](direct-kms-provider.md).

**Wrapped Materials Provider (Wrapped CMP)**  
The Wrapped Materials Provider (Wrapped CMP) lets you generate and manage your wrapping and signing keys outside of the DynamoDB Encryption Client.   
The Wrapped CMP generates a unique encryption key for each item. Then it uses wrapping (or unwrapping) and signing keys that you supply. As such, you determine how the wrapping and signing keys are generated and whether they are unique to each item or are reused. The Wrapped CMP is a secure alternative to the [Direct KMS Provider](direct-kms-provider.md) for applications that don't use AWS KMS and can safely manage cryptographic materials.  
For details, see [Wrapped Materials Provider](wrapped-provider.md).

**Most Recent Provider**  
The *Most Recent Provider* is a [cryptographic materials provider](DDBEC-legacy-concepts.md#concept-material-provider) (CMP) that is designed to work with a [provider store](DDBEC-legacy-concepts.md#provider-store). It gets CMPs from the provider store, and gets the cryptographic materials that it returns from the CMPs. The Most Recent Provider typically uses each CMP to satisfy multiple requests for cryptographic materials, but you can use the features of the provider store to control the extent to which materials are reused, determine how often its CMP is rotated, and even change the type of CMP that is used without changing the Most Recent Provider.  
You can use the Most Recent Provider with any compatible provider store. The DynamoDB Encryption Client includes a MetaStore, which is a provider store that returns Wrapped CMPs.  
The Most Recent Provider is a good choice for applications that need to minimize calls to their cryptographic source, and applications that can reuse some cryptographic materials without violating their security requirements. For example, it allows you to protect your cryptographic materials under an [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) without calling AWS KMS every time you encrypt or decrypt an item.  
For details, see [Most Recent Provider](most-recent-provider.md).

**Static Materials Provider**  
The Static Materials Provider is designed for testing, proof-of-concept demonstrations, and legacy compatibility. It doesn't generate any unique cryptographic materials for each item. It returns the same encryption and signing keys that you supply, and those keys are used directly to encrypt, decrypt, and sign your table items.   
The [Asymmetric Static Provider](https://aws.github.io/aws-dynamodb-encryption-java/com/amazonaws/services/dynamodbv2/datamodeling/encryption/providers/AsymmetricStaticProvider.html) in the Java library is not a static provider. It just supplies alternate constructors for the [Wrapped CMP](wrapped-provider.md). It is safe for production use, but you should use the Wrapped CMP directly whenever possible.

**Topics**
+ [Direct KMS Materials Provider](direct-kms-provider.md)
+ [Wrapped Materials Provider](wrapped-provider.md)
+ [Most Recent Provider](most-recent-provider.md)
+ [Static Materials Provider](static-provider.md)

# Direct KMS Materials Provider
<a name="direct-kms-provider"></a>

**Note**  
Our client-side encryption library was [renamed to AWS Database Encryption SDK](DDBEC-rename.md). The following topic provides information on versions 1.*x*—2.*x* of the DynamoDB Encryption Client for Java and versions 1.*x*—3.*x* of the DynamoDB Encryption Client for Python. For more information, see [AWS Database Encryption SDK for DynamoDB version support](legacy-dynamodb-encryption-client.md#legacy-support).

The *Direct KMS Materials Provider* (Direct KMS Provider) protects your table items under an [AWS KMS key](https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#master_keys) that never leaves [AWS Key Management Service](https://docs.aws.amazon.com/kms/latest/developerguide/) (AWS KMS) unencrypted. This [cryptographic materials provider](DDBEC-legacy-concepts.md#concept-material-provider) returns a unique encryption key and signing key for every table item. To do so, it calls AWS KMS every time you encrypt or decrypt an item.

If you're processing DynamoDB items at a high frequency and large scale, you might exceed the AWS KMS [requests-per-second limits](https://docs.aws.amazon.com/kms/latest/developerguide/limits.html#requests-per-second), causing processing delays. If you need to exceed a limit, create a case in the [AWS Support Center](https://console.aws.amazon.com/support/home). You might also consider using a cryptographic materials provider with limited key reuse, such as the [Most Recent Provider](most-recent-provider.md).

To use the Direct KMS Provider, the caller must have [an AWS account](https://aws.amazon.com/premiumsupport/knowledge-center/create-and-activate-aws-account/), at least one AWS KMS key, and permission to call the [GenerateDataKey](https://docs.aws.amazon.com/kms/latest/APIReference/API_GenerateDataKey.html) and [Decrypt](https://docs.aws.amazon.com/kms/latest/APIReference/API_Decrypt.html) operations on the AWS KMS key. The AWS KMS key must be a symmetric encryption key; the DynamoDB Encryption Client does not support asymmetric encryption. If you are using a [DynamoDB global table](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GlobalTables.html), you might want to specify an [AWS KMS multi-Region key](https://docs.aws.amazon.com/kms/latest/developerguide/multi-region-keys-overview.html). For details, see [How to use it](#provider-kms-how-to-use).

**Note**  
When you use the Direct KMS Provider, the names and values of your primary key attributes appear in plaintext in the [AWS KMS encryption context](https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#encrypt_context) and AWS CloudTrail logs of related AWS KMS operations. However, the DynamoDB Encryption Client never exposes the plaintext of any encrypted attribute values.

The Direct KMS Provider is one of several [cryptographic materials providers](DDBEC-legacy-concepts.md#concept-material-provider) (CMPs) that the DynamoDB Encryption Client supports. For information about the other CMPs, see [Cryptographic materials provider](crypto-materials-providers.md).

**For example code, see:**
+ 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**
+ [How to use it](#provider-kms-how-to-use)
+ [How it works](#provider-kms-how-it-works)

## How to use it
<a name="provider-kms-how-to-use"></a>

To create a Direct KMS Provider, use the key ID parameter to specify a symmetric encryption [KMS key](https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#master_keys) in your account. The value of the key ID parameter can be the key ID, key ARN, alias name, or alias ARN of the AWS KMS key. For details about the key identifiers, see [Key identifiers](https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#key-id) in the *AWS Key Management Service Developer Guide*.

The Direct KMS Provider requires a symmetric encryption KMS key. You cannot use an asymmetric KMS key. However, you can use a multi-Region KMS key, a KMS key with imported key material, or a KMS key in a custom key store. You must have [kms:GenerateDataKey](https://docs.aws.amazon.com/kms/latest/APIReference/API_GenerateDataKey.html) and [kms:Decrypt](https://docs.aws.amazon.com/kms/latest/APIReference/API_Decrypt.html) permission on the KMS key. As such, you must use a customer managed key, not an AWS managed or AWS owned KMS key.

The DynamoDB Encryption Client for Python determines the Region for calling AWS KMS from the Region in the key ID parameter value, if it includes one. Otherwise, it uses the Region in the AWS KMS client, if you specify one, or the Region that you configure in the AWS SDK for Python (Boto3). For information about Region selection in Python, see [Configuration](https://boto3.amazonaws.com/v1/documentation/api/latest/guide/configuration.html) in the AWS SDK for Python (Boto3) API Reference.

The DynamoDB Encryption Client for Java determines the Region for calling AWS KMS from the Region in the AWS KMS client, if the client you specify includes a Region. Otherwise, it uses the Region that you configure in the AWS SDK for Java. For information about Region selection in the AWS SDK for Java, see [AWS Region selection](https://docs.aws.amazon.com/sdk-for-java/v1/developer-guide/java-dg-region-selection.html) in the AWS SDK for Java Developer Guide.

------
#### [ 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 ]

The following example uses the key ARN to specify the AWS KMS key. If your key identifier doesn't include an AWS Region, the DynamoDB Encryption Client gets the Region from the configured Botocore session, if there is one, or from Boto defaults.

```
# 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)
```

------

If you are using [Amazon DynamoDB global tables](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GlobalTables.html), we recommend that you encrypt your data under an AWS KMS multi-Region key. Multi-Region keys are AWS KMS keys in different AWS Regions that can be used interchangeably because they have the same key ID and key material. For details, see [Using multi-Region keys](https://docs.aws.amazon.com/kms/latest/developerguide/multi-region-keys-overview.html) in the *AWS Key Management Service Developer Guide*.

**Note**  
If you are using the global tables [version 2017.11.29](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/globaltables.V1.html), you must set attribute actions so the reserved replication fields are not encrypted or signed. For details, see [Issues with older version global tables](troubleshooting.md#fix-global-tables).

To use a multi-Region key with the DynamoDB Encryption Client, create a multi-Region key and replicate it into the Regions in which your application runs. Then configure the Direct KMS Provider to use the multi-Region key in the Region in which the DynamoDB Encryption Client calls AWS KMS.

The following example configures the DynamoDB Encryption Client to encrypt data in the US East (N. Virginia) (us-east-1) Region and decrypt it in the US West (Oregon) (us-west-2) Region using a multi-Region key.

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

In this example, the DynamoDB Encryption Client gets the Region for calling AWS KMS from the Region in the AWS KMS client. The `keyArn` value identifies a multi-Region key in the same Region.

```
// 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 ]

In this example, the DynamoDB Encryption Client gets the Region for calling AWS KMS from the Region in the key ARN.

```
# 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)
```

------

## How it works
<a name="provider-kms-how-it-works"></a>

The Direct KMS Provider returns encryption and signing keys that are protected by an AWS KMS key that you specify, as shown in the following diagram.

![\[The input, processing, and output of the Direct KMS Provider in the DynamoDB Encryption Client\]](http://docs.aws.amazon.com/database-encryption-sdk/latest/devguide/images/directKMS.png)

+ To generate encryption materials, the Direct KMS Provider asks AWS KMS to [generate a unique data key](https://docs.aws.amazon.com/kms/latest/APIReference/API_GenerateDataKey.html) for each item using an AWS KMS key that you specify. It derives encryption and signing keys for the item from the plaintext copy of the [data key](https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#data-keys), and then returns the encryption and signing keys, along with the encrypted data key, which is stored in the [material description attribute](DDBEC-legacy-concepts.md#legacy-material-description) of the item. 

  The item encryptor uses the encryption and signing keys and removes them from memory as soon as possible. Only the encrypted copy of the data key from which they were derived is saved in the encrypted item.
+ To generate decryption materials, the Direct KMS Provider asks AWS KMS to decrypt the encrypted data key. Then, it derives verification and signing keys from the plaintext data key, and returns them to the item encryptor.

  The item encryptor verifies the item and, if verification succeeds, decrypts the encrypted values. Then, it removes the keys from memory as soon as possible.

### Get encryption materials
<a name="direct-kms-get-encryption-materials"></a>

This section describes in detail the inputs, outputs, and processing of the Direct KMS Provider when it receives a request for encryption materials from the [item encryptor](DDBEC-legacy-concepts.md#item-encryptor).

**Input ** (from the application)
+ The key ID of an AWS KMS key. 

**Input** (from the item encryptor)
+ [DynamoDB encryption context](concepts.md#encryption-context)

**Output** (to the item encryptor)
+ Encryption key (plaintext)
+ Signing key
+ In [actual material description](DDBEC-legacy-concepts.md#legacy-material-description): These values are saved in the material description attribute that the client adds to the item.
  + amzn-ddb-env-key: Base64-encoded data key encrypted by the AWS KMS key
  + amzn-ddb-env-alg: Encryption algorithm, by default [AES/256](https://csrc.nist.gov/projects/cryptographic-standards-and-guidelines/archived-crypto-projects/aes-development)
  + amzn-ddb-sig-alg: Signing algorithm, by default, [HmacSHA256/256](https://en.wikipedia.org/wiki/HMAC)
  + amzn-ddb-wrap-alg: kms

**Processing**

1. The Direct KMS Provider sends AWS KMS a request to use the specified AWS KMS key to [generate a unique data key](https://docs.aws.amazon.com/kms/latest/APIReference/API_GenerateDataKey.html) for the item. The operation returns a plaintext key and a copy that is encrypted under the AWS KMS key. This is known as the *initial key material*.

   The request includes the following values in plaintext in [AWS KMS encryption context](https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#encrypt_context). These non-secret values are cryptographically bound to the encrypted object, so the same encryption context is required on decrypt. You can use these values to identify the call to AWS KMS in [AWS CloudTrail logs](https://docs.aws.amazon.com/kms/latest/developerguide/monitoring-overview.html).
   + amzn-ddb-env-alg – Encryption algorithm, by default AES/256
   + amzn-ddb-sig-alg – Signing algorithm, by default HmacSHA256/256
   + (Optional) aws-kms-table – *table name*
   + (Optional) *partition key name* – *partition key value* (binary values are Base64-encoded)
   + (Optional) *sort key name* – *sort key value* (binary values are Base64-encoded)

   The Direct KMS Provider gets the values for the AWS KMS encryption context from the [DynamoDB encryption context](concepts.md#encryption-context) for the item. If the DynamoDB encryption context doesn't include a value, such as the table name, that name-value pair is omitted from the AWS KMS encryption context.

1. The Direct KMS Provider derives a symmetric encryption key and a signing key from the data key. By default, it uses [Secure Hash Algorithm (SHA) 256](https://en.wikipedia.org/wiki/SHA-2) and [RFC5869 HMAC-based Key Derivation Function](https://tools.ietf.org/html/rfc5869) to derive a 256-bit AES symmetric encryption key and a 256-bit HMAC-SHA-256 signing key. 

1. The Direct KMS Provider returns the output to the item encryptor.

1. The item encryptor uses the encryption key to encrypt the specified attributes and the signing key to sign them, using the algorithms specified in the actual material description. It removes the plaintext keys from memory as soon as possible.

### Get decryption materials
<a name="direct-kms-get-decryption-materials"></a>

This section describes in detail the inputs, outputs, and processing of the Direct KMS Provider when it receives a request for decryption materials from the [item encryptor](DDBEC-legacy-concepts.md#item-encryptor).

**Input ** (from the application)
+ The key ID of an AWS KMS key. 

  The value of the key ID can be the key ID, key ARN, alias name or alias ARN of the AWS KMS key. Any values that aren't included in the key ID, such as the Region, must be available in the [AWS named profile](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-files.html#cli-configure-files-using-profiles). The key ARN provides all of the values that AWS KMS needs.

**Input** (from the item encryptor)
+ A copy of the [DynamoDB encryption context](concepts.md#encryption-context) that contains the contents of the material description attribute.

**Output** (to the item encryptor)
+ Encryption key (plaintext)
+ Signing key

**Processing**

1. The Direct KMS Provider gets the encrypted data key from the material description attribute in the encrypted item. 

1. It asks AWS KMS to use the specified AWS KMS key to [decrypt](https://docs.aws.amazon.com/kms/latest/APIReference/API_GenerateDataKey.html) the encrypted data key. The operation returns a plaintext key.

   This request must use the same [AWS KMS encryption context](https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#encrypt_context) that was used to generate and encrypt the data key.
   + aws-kms-table – *table name*
   + *partition key name* – *partition key value* (binary values are Base64-encoded)
   + (Optional) *sort key name* – *sort key value* (binary values are Base64-encoded)
   + amzn-ddb-env-alg – Encryption algorithm, by default AES/256
   + amzn-ddb-sig-alg – Signing algorithm, by default HmacSHA256/256

1. The Direct KMS Provider uses [Secure Hash Algorithm (SHA) 256](https://en.wikipedia.org/wiki/SHA-2) and [RFC5869 HMAC-based Key Derivation Function](https://tools.ietf.org/html/rfc5869) to derive a 256-bit AES symmetric encryption key and a 256-bit HMAC-SHA-256 signing key from the data key. 

1. The Direct KMS Provider returns the output to the item encryptor.

1. The item encryptor uses the signing key to verify the item. If it succeeds, it uses the symmetric encryption key to decrypt the encrypted attribute values. These operations use the encryption and signing algorithms specified in the actual material description. The item encryptor removes the plaintext keys from memory as soon as possible.

# Wrapped Materials Provider
<a name="wrapped-provider"></a>

**Note**  
Our client-side encryption library was [renamed to AWS Database Encryption SDK](DDBEC-rename.md). The following topic provides information on versions 1.*x*—2.*x* of the DynamoDB Encryption Client for Java and versions 1.*x*—3.*x* of the DynamoDB Encryption Client for Python. For more information, see [AWS Database Encryption SDK for DynamoDB version support](legacy-dynamodb-encryption-client.md#legacy-support).

The *Wrapped Materials Provider* (Wrapped CMP) lets you use wrapping and signing keys from any source with the DynamoDB Encryption Client. The Wrapped CMP does not depend on any AWS service. However, you must generate and manage your wrapping and signing keys outside of the client, including providing the correct keys to verify and decrypt the item. 

The Wrapped CMP generates a unique item encryption key for each item. It wraps the item encryption key with the wrapping key that you provide and saves the wrapped item encryption key in the [material description attribute](DDBEC-legacy-concepts.md#legacy-material-description) of the item. Because you supply the wrapping and signing keys, you determine how the wrapping and signing keys are generated and whether they are unique to each item or are reused. 

The Wrapped CMP is a secure implementation and a good choice for applications that can manage cryptographic materials.

The Wrapped CMP is one of several [cryptographic materials providers](DDBEC-legacy-concepts.md#concept-material-provider) (CMPs) that the DynamoDB Encryption Client supports. For information about the other CMPs, see [Cryptographic materials provider](crypto-materials-providers.md).

**For example code, see:**
+ 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**
+ [How to use it](#wrapped-cmp-how-to-use)
+ [How it works](#wrapped-cmp-how-it-works)

## How to use it
<a name="wrapped-cmp-how-to-use"></a>

To create a Wrapped CMP, specify a wrapping key (required on encrypt), an unwrapping key (required on decrypt), and a signing key. You must supply keys when you encrypt and decrypt items.

The wrapping, unwrapping, and signing keys can be symmetric keys or asymmetric key pairs. 

------
#### [ 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
)
```

------

## How it works
<a name="wrapped-cmp-how-it-works"></a>

The Wrapped CMP generates a new item encryption key for every item. It uses the wrapping, unwrapping, and signing keys that you provide, as shown in the following diagram.

![\[The input, processing, and output of the Wrapped Materials Provider in the DynamoDB Encryption Client\]](http://docs.aws.amazon.com/database-encryption-sdk/latest/devguide/images/wrappedCMP.png)


### Get encryption materials
<a name="wrapped-cmp-get-encryption-materials"></a>

This section describes in detail the inputs, outputs, and processing of the Wrapped Materials Provider (Wrapped CMP) when it receives a request for encryption materials. 

**Input** (from application)
+ Wrapping key: An [Advanced Encryption Standard](https://en.wikipedia.org/wiki/Advanced_Encryption_Standard) (AES) symmetric key, or an [RSA](https://en.wikipedia.org/wiki/RSA_(cryptosystem)) public key. Required if any attribute values are encrypted. Otherwise, it is optional and ignored.
+ Unwrapping key: Optional and ignored. 
+ Signing key

**Input** (from the item encryptor)
+ [DynamoDB encryption context](concepts.md#encryption-context)

**Output** (to the item encryptor):
+ Plaintext item encryption key
+ Signing key (unchanged)
+ [Actual material description](DDBEC-legacy-concepts.md#legacy-material-description): These values are saved in the [material description attribute](DDBEC-legacy-concepts.md#legacy-material-description) that the client adds to the item. 
  + `amzn-ddb-env-key`: Base64-encoded wrapped item encryption key
  + `amzn-ddb-env-alg`: Encryption algorithm used to encrypt the item. The default is AES-256-CBC.
  + `amzn-ddb-wrap-alg`: The wrapping algorithm that the Wrapped CMP used to wrap the item encryption key. If the wrapping key is an AES key, the key is wrapped using unpadded `AES-Keywrap` as defined in [RFC 3394](https://tools.ietf.org/html/rfc3394.html). If the wrapping key is an RSA key, the key is encrypted by using RSA OAEP with MGF1 padding. 

**Processing**

When you encrypt an item, you pass in a wrapping key and a signing key. An unwrapping key is optional and ignored.

1. The Wrapped CMP generates a unique symmetric item encryption key for the table item.

1. It uses the wrapping key that you specify to wrap the item encryption key. Then, it removes it from memory as soon as possible.

1. It returns the plaintext item encryption key, the signing key that you supplied, and an [actual material description](DDBEC-legacy-concepts.md#legacy-material-description) that includes the wrapped item encryption key, and the encryption and wrapping algorithms.

1. The item encryptor uses the plaintext encryption key to encrypt the item. It uses the signing key that you supplied to sign the item. Then, it removes the plaintext keys from memory as soon as possible. It copies the fields in the actual material description, including the wrapped encryption key (`amzn-ddb-env-key`), to the material description attribute of the item.

### Get decryption materials
<a name="wrapped-cmp-get-decryption-materials"></a>

This section describes in detail the inputs, outputs, and processing of the Wrapped Materials Provider (Wrapped CMP) when it receives a request for decryption materials. 

**Input** (from application)
+ Wrapping key: Optional and ignored.
+ Unwrapping key: The same [Advanced Encryption Standard](https://en.wikipedia.org/wiki/Advanced_Encryption_Standard) (AES) symmetric key or [RSA](https://en.wikipedia.org/wiki/RSA_(cryptosystem)) private key that corresponds to the RSA public key used to encrypt. Required if any attribute values are encrypted. Otherwise, it is optional and ignored.
+ Signing key

**Input** (from the item encryptor)
+ A copy of the [DynamoDB encryption context](concepts.md#encryption-context) that contains the contents of the material description attribute.

**Output** (to the item encryptor)
+ Plaintext item encryption key
+ Signing key (unchanged)

**Processing**

When you decrypt an item, you pass in an unwrapping key and a signing key. A wrapping key is optional and ignored.

1. The Wrapped CMP gets the wrapped item encryption key from the material description attribute of the item.

1. It uses the unwrapping key and algorithm to unwrap the item encryption key. 

1. It returns the plaintext item encryption key, the signing key, and encryption and signing algorithms to the item encryptor.

1. The item encryptor uses the signing key to verify the item. If it succeeds, it uses the item encryption key to decrypt the item. Then, it removes the plaintext keys from memory as soon as possible.

# Most Recent Provider
<a name="most-recent-provider"></a>

**Note**  
Our client-side encryption library was [renamed to AWS Database Encryption SDK](DDBEC-rename.md). The following topic provides information on versions 1.*x*—2.*x* of the DynamoDB Encryption Client for Java and versions 1.*x*—3.*x* of the DynamoDB Encryption Client for Python. For more information, see [AWS Database Encryption SDK for DynamoDB version support](legacy-dynamodb-encryption-client.md#legacy-support).

The *Most Recent Provider* is a [cryptographic materials provider](DDBEC-legacy-concepts.md#concept-material-provider) (CMP) that is designed to work with a [provider store](DDBEC-legacy-concepts.md#provider-store). It gets CMPs from the provider store, and gets the cryptographic materials that it returns from the CMPs. It typically uses each CMP to satisfy multiple requests for cryptographic materials. But you can use the features of its provider store to control the extent to which materials are reused, determine how often its CMP is rotated, and even change the type of CMP that it uses without changing the Most Recent Provider.

**Note**  
The code associated with the `MostRecentProvider` symbol for the Most Recent Provider might store cryptographic materials in memory for the lifetime of the process. It might allow a caller to use keys that they're no longer authorized to use.   
The `MostRecentProvider` symbol is deprecated in older supported versions of the DynamoDB Encryption Client and removed from version 2.0.0. It is replaced by the `CachingMostRecentProvider` symbol. For details, see [Updates to the Most Recent Provider](#mrp-versions).

The Most Recent Provider is a good choice for applications that need to minimize calls to the provider store and its cryptographic source, and applications that can reuse some cryptographic materials without violating their security requirements. For example, It allows you to protect your cryptographic materials under an [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) without calling AWS KMS every time you encrypt or decrypt an item.

The provider store that you choose determines the type of CMPs that the Most Recent Provider uses and how often it gets a new CMP. You can use any compatible provider store with the Most Recent Provider, including custom provider stores that you design. 

The DynamoDB Encryption Client includes a *MetaStore* that creates and returns [Wrapped Materials Providers](wrapped-provider.md) (Wrapped CMPs). The MetaStore saves multiple versions of the Wrapped CMPs that it generates in an internal DynamoDB table and protects them with client-side encryption by an internal instance of the DynamoDB Encryption Client. 

You can configure the MetaStore to use any type of internal CMP to protect the materials in the table, including a [Direct KMS Provider](direct-kms-provider.md) that generates cryptographic materials protected by your AWS KMS key, a Wrapped CMP that uses wrapping and signing keys that you supply, or a compatible custom CMP that you design.

**For example code, see:**
+ 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**
+ [How to use it](#mrp-how-to-use-it)
+ [How it works](#mrp-how-it-works)
+ [Updates to the Most Recent Provider](#mrp-versions)

## How to use it
<a name="mrp-how-to-use-it"></a>

To create a Most Recent Provider, you need to create and configure a provider store, and then create a Most Recent Provider that uses the provider store. 

The following examples show how to create a Most Recent Provider that uses a MetaStore and protects the versions in its internal DynamoDB table with cryptographic materials from a [Direct KMS Provider](direct-kms-provider.md). These examples use the [`CachingMostRecentProvider`](#mrp-versions) symbol. 

Each Most Recent Provider has a name that identifies its CMPs in the MetaStore table, a [time-to-live](#most-recent-provider-ttl) (TTL) setting, and a cache size setting that determines how many entries the cache can hold. These examples set the cache size to 1000 entries and a TTL of 60 seconds.

------
#### [ 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
)
```

------

## How it works
<a name="mrp-how-it-works"></a>

The Most Recent Provider gets CMPs from a provider store. Then, it uses the CMP to generate the cryptographic materials that it returns to the item encryptor.

### About the Most Recent Provider
<a name="about-mrp"></a>

The Most Recent Provider gets a [cryptographic materials provider](DDBEC-legacy-concepts.md#concept-material-provider) (CMP) from a [provider store](DDBEC-legacy-concepts.md#provider-store). Then, it uses the CMP to generate the cryptographic materials it returns. Each Most Recent Provider is associated with one provider store, but a provider store can supply CMPs to multiple providers across multiple hosts.

The Most Recent Provider can work with any compatible CMP from any provider store. It requests encryption or decryption materials from the CMP and returns the output to the item encryptor. It does not perform any cryptographic operations.

To request a CMP from its provider store, the Most Recent Provider supplies its material name and the version of an existing CMP it wants to use. For encryption materials, the Most Recent Provider always requests the maximum ("most recent") version. For decryption materials, it requests the version of the CMP that was used to create the encryption materials, as shown in the following diagram.

![\[A Most Recent Provider\]](http://docs.aws.amazon.com/database-encryption-sdk/latest/devguide/images/most-recent-provider-1.png)


The Most Recent Provider saves versions of the CMPs that the provider store returns in a local Least Recently Used (LRU) cache in memory. The cache enables the Most Recent Provider to get the CMPs that it needs without calling the provider store for every item. You can clear the cache on demand.

The Most Recent Provider uses a configurable [time-to-live value](#most-recent-provider-ttl) that you can adjust based on the characteristics of your application.

### About the MetaStore
<a name="about-metastore"></a>

You can use a Most Recent Provider with any provider store, including a compatible custom provider store. The DynamoDB Encryption Client includes a MetaStore, a secure implementation that you can configure and customize.

A *MetaStore* is a [provider store](DDBEC-legacy-concepts.md#provider-store) that creates and returns [Wrapped CMPs](wrapped-provider.md) that are configured with the wrapping key, unwrapping key, and signing key that Wrapped CMPs require. A MetaStore is a secure option for a Most Recent Provider because Wrapped CMPs always generate unique item encryption keys for every item. Only the wrapping key that protects the item encryption key and the signing keys are reused.

The following diagram shows the components of the MetaStore and how it interacts with the Most Recent Provider.

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


The MetaStore generates the Wrapped CMPs, and then stores them (in encrypted form) in an internal DynamoDB table. The partition key is the name of the Most Recent Provider material; the sort key its version number. The materials in the table are protected by an internal DynamoDB Encryption Client, including an item encryptor and internal [cryptographic materials provider](DDBEC-legacy-concepts.md#concept-material-provider) (CMP).

You can use any type of internal CMP in your MetaStore, including the a [Direct KMS Provider](wrapped-provider.md), a Wrapped CMP with cryptographic materials that you provide, or a compatible custom CMP. If the internal CMP in your MetaStore is a Direct KMS Provider, your reusable wrapping and signing keys are protected under a [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). The MetaStore calls AWS KMS every time it adds a new CMP version to its internal table or gets a CMP version from its internal table.

### Setting a time-to-live value
<a name="most-recent-provider-ttl"></a>

You can set a time-to-live (TTL) value for each Most Recent Provider that you create. In general, use the lowest TTL value that is practical for your application.

The use of the TTL value is changed in the `CachingMostRecentProvider` symbol for the Most Recent Provider. 

**Note**  
The `MostRecentProvider` symbol for the Most Recent Provider is deprecated in older supported versions of the DynamoDB Encryption Client and removed from version 2.0.0. It is replaced by the `CachingMostRecentProvider` symbol. We recommend that you update your code as soon as possible. For details, see [Updates to the Most Recent Provider](#mrp-versions).

**`CachingMostRecentProvider`**  
The `CachingMostRecentProvider` uses the TTL value in two different ways.   
+ The TTL determines how often the Most Recent Provider checks the provider store for a new version of the CMP. If a new version is available, the Most Recent Provider replaces its CMP and refreshes its cryptographic materials. Otherwise, it continues to use its current CMP and cryptographic materials.
+ The TTL determines how long CMPs in the cache can be used. Before it uses a cached CMP for encryption, the Most Recent Provider evaluates its time in the cache. If the CMP cache time exceeds the TTL, the CMP is evicted from the cache and the Most Recent Provider gets a new, latest-version CMP from its provider store.

**`MostRecentProvider`**  
In the `MostRecentProvider`, the TTL determines how often the Most Recent Provider checks the provider store for a new version of the CMP. If a new version is available, the Most Recent Provider replaces its CMP and refreshes its cryptographic materials. Otherwise, it continues to use its current CMP and cryptographic materials.

The TTL does not determine how often a new CMP version is created. You create new CMP versions by [rotating the cryptographic materials](#most-recent-provider-rotate).

An ideal TTL value varies with the application and its latency and availability goals. A lower TTL improves your security profile by reducing the time that cryptographic materials are stored in memory. Also, a lower TTL refreshes critical information more frequently. For example, if your internal CMP is a [Direct KMS Provider](direct-kms-provider.md), it verifies more frequently that the caller is still authorized to use an AWS KMS key.

However, if the TTL is too brief, the frequent calls to the provider store can increase your costs and cause your provider store to throttle requests from your application and other applications that share your service account. You might also benefit from coordinating the TTL with the rate at which you rotate cryptographic materials. 

During testing, vary the TTL and cache size under different work loads until you find a configuration that works for your application and your security and performance standards.

### Rotating cryptographic materials
<a name="most-recent-provider-rotate"></a>

When a Most Recent Provider needs encryption materials, it always uses the most recent version of its CMP that it knows about. The frequency that it checks for a newer version is determined by the [time-to-live](#most-recent-provider-ttl) (TTL) value that you set when you configure the Most Recent Provider. 

When the TTL expires, the Most Recent Provider checks the provider store for newer version of the CMP. If one is available, the Most Recent Provider get it and replaces the CMP in its cache. It uses this CMP and its cryptographic materials until it discovers that provider store has a newer version.

To tell the provider store to create a new version of a CMP for a Most Recent Provider, call the provider store's Create New Provider operation with the material name of the Most Recent Provider. The provider store creates a new CMP and saves an encrypted copy in its internal storage with a greater version number. (It also returns a CMP, but you can discard it.) As a result, the next time the Most Recent Provider queries the provider store for the maximum version number of its CMPs, it gets the new greater version number, and uses it in subsequent requests to the store to see if a new version of the CMP has been created.

You can schedule your Create New Provider calls based on time, the number of items or attributes processed, or any other metric that makes sense for your application.

### Get encryption materials
<a name="most-recent-provider-encrypt"></a>

The Most Recent Provider uses the following process, shown in this diagram, to get the encryption materials that it returns to the item encryptor. The output depends on the type of CMP that the provider store returns. The Most Recent Provider can use any compatible provider store, including the MetaStore that is included in the DynamoDB Encryption Client.

![\[Input, processing, and output of the Most Recent Provider in the DynamoDB Encryption Client\]](http://docs.aws.amazon.com/database-encryption-sdk/latest/devguide/images/most-recent-provider-provider-store.png)


When you create a Most Recent Provider by using the [`CachingMostRecentProvider` symbol](#mrp-versions), you specify a provider store, a name for the Most Recent Provider, and a [time-to-live](#most-recent-provider-ttl) (TTL) value. You can also optionally specify a cache size, which determines the maximum number of cryptographic materials that can exist in the cache.

When the item encryptor asks the Most Recent Provider for encryption materials, the Most Recent Provider begins by searching its cache for the latest version of its CMP.
+ If it finds the latest version CMP in its cache and the CMP has not exceeded the TTL value, the Most Recent Provider uses the CMP to generate encryption materials. Then, it returns the encryption materials to the item encryptor. This operation does not require a call to the provider store.
+ If the latest version of the CMP is not in its cache, or if it is in the cache but has exceeded its TTL value, the Most Recent Provider requests a CMP from its provider store. The request includes the Most Recent Provider material name and the maximum version number that it knows.

  1. The provider store returns a CMP from its persistent storage. If the provider store is a MetaStore, it gets an encrypted Wrapped CMP from its internal DynamoDB table by using the Most Recent Provider material name as the partition key and the version number as the sort key. The MetaStore uses its internal item encryptor and internal CMP to decrypt the Wrapped CMP. Then, it returns the plaintext CMP to the Most Recent Provider . If the internal CMP is a [Direct KMS Provider](direct-kms-provider.md), this step includes a call to the [AWS Key Management Service](https://docs.aws.amazon.com/kms/latest/developerguide/) (AWS KMS).

  1. The CMP adds the `amzn-ddb-meta-id` field to the [actual material description](DDBEC-legacy-concepts.md#legacy-material-description). Its value is the material name and version of the CMP in its internal table. The provider store returns the CMP to the Most Recent Provider.

  1. The Most Recent Provider caches the CMP in memory.

  1. The Most Recent Provider uses the CMP to generate encryption materials. Then, it returns the encryption materials to the item encryptor.

### Get decryption materials
<a name="most-recent-provider-decrypt"></a>

When the item encryptor asks the Most Recent Provider for decryption materials, the Most Recent Provider uses the following process to get and return them.

1. The Most Recent Provider asks the provider store for the version number of the cryptographic materials that were used to encrypt the item. It passes in the actual material description from the [material description attribute](DDBEC-legacy-concepts.md#legacy-material-description) of the item.

1. The provider store gets the encrypting CMP version number from the `amzn-ddb-meta-id` field in the actual material description and returns it to the Most Recent Provider.

1. The Most Recent Provider searches its cache for the version of CMP that was used to encrypt and sign the item.
+ If it finds the matching version of the CMP is in its cache and the CMP has not exceeded the [time-to-live (TTL) value](#most-recent-provider-ttl), the Most Recent Provider uses the CMP to generate decryption materials. Then, it returns the decryption materials to the item encryptor. This operation does not require a call to the provider store or any other CMP.
+ If the matching version of the CMP is not in its cache, or if the cached AWS KMS key has exceeded its TTL value, the Most Recent Provider requests a CMP from its provider store. It sends its material name and the encrypting CMP version number in the request.

  1. The provider store searches its persistent storage for the CMP by using the Most Recent Provider name as the partition key and the version number as the sort key.
     + If the name and version number are not in its persistent storage, the provider store throws an exception. If the provider store was used to generate the CMP, the CMP should be stored in its persistent storage, unless it was intentionally deleted.
     + If the CMP with the matching name and version number are in the provider store's persistent storage, the provider store returns the specified CMP to the Most Recent Provider. 

       If the provider store is a MetaStore, it gets the encrypted CMP from its DynamoDB table. Then, it uses cryptographic materials from its internal CMP to decrypt the encrypted CMP before it returns the CMP to Most Recent Provider. If the internal CMP is a [Direct KMS Provider](direct-kms-provider.md), this step includes a call to the [AWS Key Management Service](https://docs.aws.amazon.com/kms/latest/developerguide/) (AWS KMS).

  1. The Most Recent Provider caches the CMP in memory.

  1. The Most Recent Provider uses the CMP to generate decryption materials. Then, it returns the decryption materials to the item encryptor.

## Updates to the Most Recent Provider
<a name="mrp-versions"></a>

The symbol for the Most Recent Provider is changed from `MostRecentProvider` to `CachingMostRecentProvider`. 

**Note**  
The `MostRecentProvider` symbol, which represents the Most Recent Provider, is deprecated in version 1.15 of the DynamoDB Encryption Client for Java and version 1.3 of the DynamoDB Encryption Client for Python and removed from versions 2.0.0 of the DynamoDB Encryption Client in both language implementations. Instead, use the `CachingMostRecentProvider`.

The `CachingMostRecentProvider` implements the following changes:
+ The `CachingMostRecentProvider` periodically removes cryptographic materials from memory when their time in memory exceeds the configured [time-to-live (TTL) value](#most-recent-provider-ttl). 

  The `MostRecentProvider` might store cryptographic materials in memory for the lifetime of the process. As a result, the Most Recent Provider might not be aware of authorization changes. It might use encryption keys after the caller's permissions to use them are revoked. 

  If you can't update to this new version, you can get a similar effect by periodically calling the `clear()` method on the cache. This method manually flushes the cache contents and requires the Most Recent Provider to request a new CMP and new cryptographic materials. 
+ The `CachingMostRecentProvider` also includes a cache size setting that gives you more control over the cache.

To update to the `CachingMostRecentProvider`, you have to change the symbol name in your code. In all other respects, the `CachingMostRecentProvider` is fully backwards compatible with the `MostRecentProvider`. You don't need to re-encrypt any table items.

However, the `CachingMostRecentProvider` generates more calls to the underlying key infrastructure. It calls the provider store at least once in each time-to-live (TTL) interval. Applications with numerous active CMPs (due to frequent rotation) or applications with large fleets are most likely to be sensitive to this change. 

Before releasing your updated code, test it thoroughly to ensure that the more frequent calls don't impair your application or cause throttling by services on which your provider depends, such as AWS Key Management Service (AWS KMS) or Amazon DynamoDB. To mitigate any performance problems, adjust the cache size and the time-to-live of the `CachingMostRecentProvider` based on the performance characteristics you observe. For guidance, see [Setting a time-to-live value](#most-recent-provider-ttl).

# Static Materials Provider
<a name="static-provider"></a>

**Note**  
Our client-side encryption library was [renamed to AWS Database Encryption SDK](DDBEC-rename.md). The following topic provides information on versions 1.*x*—2.*x* of the DynamoDB Encryption Client for Java and versions 1.*x*—3.*x* of the DynamoDB Encryption Client for Python. For more information, see [AWS Database Encryption SDK for DynamoDB version support](legacy-dynamodb-encryption-client.md#legacy-support).

The *Static Materials Provider* (Static CMP) is a very simple [cryptographic materials provider](DDBEC-legacy-concepts.md#concept-material-provider) (CMP) that is intended for testing, proof-of-concept demonstrations, and legacy compatibility.

To use the Static CMP to encrypt a table item, you supply an [Advanced Encryption Standard](https://en.wikipedia.org/wiki/Advanced_Encryption_Standard) (AES) symmetric encryption key and a signing key or key pair. You must supply the same keys to decrypt the encrypted item. The Static CMP does not perform any cryptographic operations. Instead, it passes the encryption keys that you supply to the item encryptor unchanged. The item encryptor encrypts the items directly under the encryption key. Then, it uses the signing key directly to sign them. 

Because the Static CMP does not generate any unique cryptographic materials, all table items that you process are encrypted with the same encryption key and signed by the same signing key. When you use the same key to encrypt the attributes values in numerous items or use the same key or key pair to sign all items, you risk exceeding the cryptographic limits of the keys. 

**Note**  
The [Asymmetric Static Provider](https://aws.github.io/aws-dynamodb-encryption-java/com/amazonaws/services/dynamodbv2/datamodeling/encryption/providers/AsymmetricStaticProvider.html) in the Java library is not a static provider. It just supplies alternate constructors for the [Wrapped CMP](wrapped-provider.md). It's safe for production use, but you should use the Wrapped CMP directly whenever possible.

The Static CMP is one of several [cryptographic materials providers](DDBEC-legacy-concepts.md#concept-material-provider) (CMPs) that the DynamoDB Encryption Client supports. For information about the other CMPs, see [Cryptographic materials provider](crypto-materials-providers.md).

**For example code, see:**
+ Java: [SymmetricEncryptedItem](https://github.com/aws/aws-dynamodb-encryption-java/blob/master/examples/src/main/java/com/amazonaws/examples/SymmetricEncryptedItem.java)

**Topics**
+ [How to use it](#static-cmp-how-to-use)
+ [How it works](#static-cmp-how-it-works)

## How to use it
<a name="static-cmp-how-to-use"></a>

To create a static provider, supply an encryption key or key pair and a signing key or key pair. You need to provide key material to encrypt and decrypt table items.

------
#### [ 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
)
```

------

## How it works
<a name="static-cmp-how-it-works"></a>

The Static Provider passes the encryption and signing keys that you supply to the item encryptor, where they are used directly to encrypt and sign your table items. Unless you supply different keys for each item, the same keys are used for every item.

![\[The input, processing, and output of the Static Materials Provider in the DynamoDB Encryption Client\]](http://docs.aws.amazon.com/database-encryption-sdk/latest/devguide/images/staticCMP.png)


### Get encryption materials
<a name="static-cmp-get-encryption-materials"></a>

This section describes in detail the inputs, outputs, and processing of the Static Materials Provider (Static CMP) when it receives a request for encryption materials.

**Input** (from the application)
+ An encryption key – This must be a symmetric key, such as an [Advanced Encryption Standard](https://tools.ietf.org/html/rfc3394.html) (AES) key. 
+ A signing key – This can be a symmetric key or an asymmetric key pair. 

**Input** (from the item encryptor)
+ [DynamoDB encryption context](concepts.md#encryption-context)

**Output** (to the item encryptor)
+ The encryption key passed as input.
+ The signing key passed as input.
+ Actual material description: The [requested material description](DDBEC-legacy-concepts.md#legacy-material-description), if any, unchanged.

### Get decryption materials
<a name="static-cmp-get-decryption-materials"></a>

This section describes in detail the inputs, outputs, and processing of the Static Materials Provider (Static CMP) when it receives a request for decryption materials.

Although it includes separate methods for getting encryption materials and getting decryption materials, the behavior is the same. 

**Input** (from the application)
+ An encryption key – This must be a symmetric key, such as an [Advanced Encryption Standard](https://tools.ietf.org/html/rfc3394.html) (AES) key. 
+ A signing key – This can be a symmetric key or an asymmetric key pair. 

**Input** (from the item encryptor)
+ [DynamoDB encryption context](concepts.md#encryption-context) (not used)

**Output** (to the item encryptor)
+ The encryption key passed as input.
+ The signing key passed as input.

# Amazon DynamoDB Encryption Client available programming languages
<a name="programming-languages"></a>

**Note**  
Our client-side encryption library was [renamed to AWS Database Encryption SDK](DDBEC-rename.md). The following topic provides information on versions 1.*x*—2.*x* of the DynamoDB Encryption Client for Java and versions 1.*x*—3.*x* of the DynamoDB Encryption Client for Python. For more information, see [AWS Database Encryption SDK for DynamoDB version support](legacy-dynamodb-encryption-client.md#legacy-support).

The Amazon DynamoDB Encryption Client is available for the following programming languages. The language-specific libraries vary, but the resulting implementations are interoperable. For example, you can encrypt (and sign) an item with the Java client and decrypt the item with the Python client.

For more information, see the corresponding topic.

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

# Amazon DynamoDB Encryption Client for Java
<a name="java"></a>

**Note**  
Our client-side encryption library was [renamed to AWS Database Encryption SDK](DDBEC-rename.md). The following topic provides information on versions 1.*x*—2.*x* of the DynamoDB Encryption Client for Java and versions 1.*x*—3.*x* of the DynamoDB Encryption Client for Python. For more information, see [AWS Database Encryption SDK for DynamoDB version support](legacy-dynamodb-encryption-client.md#legacy-support).

This topic explains how to install and use the Amazon DynamoDB Encryption Client for Java. For details about programming with the DynamoDB Encryption Client, see the [Java examples](java-examples.md), the [examples](https://github.com/aws/aws-dynamodb-encryption-java/tree/master/examples) in the aws-dynamodb-encryption-java repository on GitHub, and the [Javadoc](https://aws.github.io/aws-dynamodb-encryption-java/) for the DynamoDB Encryption Client.

**Note**  
Versions 1.*x*.*x* of the DynamoDB Encryption Client for Java are in [end-of-support phase](what-is-database-encryption-sdk.md#support) effective July 2022. Upgrade to a newer version as soon as possible.

**Topics**
+ [Prerequisites](#java-prerequisites)
+ [Installation](#java-installation)
+ [Using the DynamoDB Encryption Client for Java](java-using.md)
+ [Java examples](java-examples.md)

## Prerequisites
<a name="java-prerequisites"></a>

Before you install the Amazon DynamoDB Encryption Client for Java, be sure you have the following prerequisites.

**A Java development environment**  
You will need Java 8 or later. On the Oracle website, go to [Java SE Downloads](https://www.oracle.com/java/technologies/downloads/), and then download and install the Java SE Development Kit (JDK).  
If you use the Oracle JDK, you must also download and install the [Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files](http://www.oracle.com/java/technologies/javase-jce8-downloads.html).

**AWS SDK for Java**  
The DynamoDB Encryption Client requires the DynamoDB module of the AWS SDK for Java even if your application doesn't interact with DynamoDB. You can install the entire SDK or just this module. If you are using Maven, add `aws-java-sdk-dynamodb` to your `pom.xml` file.   
For more information about installing and configuring the AWS SDK for Java, see [AWS SDK for Java](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/getting-started.html).

## Installation
<a name="java-installation"></a>

You can install the Amazon DynamoDB Encryption Client for Java in the following ways.

**Manually**  
To install the Amazon DynamoDB Encryption Client for Java, clone or download the [aws-dynamodb-encryption-java](https://github.com/aws/aws-dynamodb-encryption-java/) GitHub repository.

**Using Apache Maven**  
The Amazon DynamoDB Encryption Client for Java is available through [Apache Maven](https://maven.apache.org/) with the following dependency definition.  

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

After you install the SDK, get started by looking at the example code in this guide and the [DynamoDB Encryption Client Javadoc](https://aws.github.io/aws-dynamodb-encryption-java/) on GitHub.

# Using the DynamoDB Encryption Client for Java
<a name="java-using"></a>

**Note**  
Our client-side encryption library was [renamed to AWS Database Encryption SDK](DDBEC-rename.md). The following topic provides information on versions 1.*x*—2.*x* of the DynamoDB Encryption Client for Java and versions 1.*x*—3.*x* of the DynamoDB Encryption Client for Python. For more information, see [AWS Database Encryption SDK for DynamoDB version support](legacy-dynamodb-encryption-client.md#legacy-support).

This topic explains some of the features of the DynamoDB Encryption Client in Java that might not be found in other programming language implementations. 

For details about programming with the DynamoDB Encryption Client, see the [Java examples](java-examples.md), the [examples](https://github.com/aws/aws-dynamodb-encryption-java/tree/master/examples) in the `aws-dynamodb-encryption-java repository` on GitHub, and the [Javadoc](https://aws.github.io/aws-dynamodb-encryption-java/) for the DynamoDB Encryption Client.



**Topics**
+ [Item encryptors](#attribute-encryptor)
+ [Configuring save behavior](#save-behavior)
+ [Attribute actions in Java](#attribute-actions-java)
+ [Overriding table names](#override-table-name)

## Item encryptors: AttributeEncryptor and DynamoDBEncryptor
<a name="attribute-encryptor"></a>

The DynamoDB Encryption Client in Java has two [item encryptors](DDBEC-legacy-concepts.md#item-encryptor): the lower-level [DynamoDBEncryptor](https://aws.github.io/aws-dynamodb-encryption-java/com/amazonaws/services/dynamodbv2/datamodeling/encryption/DynamoDBEncryptor.html) and the [AttributeEncryptor](#attribute-encryptor). 

The `AttributeEncryptor` is a helper class that helps you use the [DynamoDBMapper](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBMapper.Methods.html) in the AWS SDK for Java with the `DynamoDB Encryptor` in the DynamoDB Encryption Client. When you use the `AttributeEncryptor` with the `DynamoDBMapper`, it transparently encrypts and signs your items when you save them. It also transparently verifies and decrypts your items when you load them.

## Configuring save behavior
<a name="save-behavior"></a>

You can use the `AttributeEncryptor` and `DynamoDBMapper` to add or replace table items with attributes that are signed only or encrypted and signed. For these tasks, we recommend that you configure it to use the `PUT` save behavior, as shown in the following example. Otherwise, you might not be able to decrypt your data. 

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

If you use the default save behavior, which updates only the attributes that are modeled in the table item, attributes that are not modeled are not included in the signature, and are not changed by table writes. As a result, on later reads of all attributes, the signature will not validate, because it doesn't include un-modeled attributes.

You can also use the `CLOBBER` save behavior. This behavior is identical to the `PUT` save behavior except that it disables optimistic locking and overwrites the item in the table.

To prevent signature errors, the DynamoDB Encryption Client throws a runtime exception if an `AttributeEncryptor` is used with a `DynamoDBMapper` that is not configured with a save behavior of `CLOBBER` or `PUT`.

To see this code used in an example, see [Using the DynamoDBMapper](java-examples.md#java-example-dynamodb-mapper) and the [AwsKmsEncryptedObject.java](https://github.com/aws/aws-dynamodb-encryption-java/blob/master/examples/src/main/java/com/amazonaws/examples/AwsKmsEncryptedObject.java) example in the `aws-dynamodb-encryption-java` repository in GitHub.

## Attribute actions in Java
<a name="attribute-actions-java"></a>

[Attribute actions](DDBEC-legacy-concepts.md#legacy-attribute-actions) determine which attribute values are encrypted and signed, which are only signed, and which are ignored. The method you use to specify attribute actions depends on whether you use the `DynamoDBMapper` and `AttributeEncryptor`, or the lower-level [DynamoDBEncryptor](https://aws.github.io/aws-dynamodb-encryption-java/com/amazonaws/services/dynamodbv2/datamodeling/encryption/DynamoDBEncryptor.html).

**Important**  
After you use your attribute actions to encrypt your table items, adding or removing attributes from your data model might cause a signature validation error that prevents you from decrypting your data. For a detailed explanation, see [Changing your data model](data-model.md).

### Attribute actions for the DynamoDBMapper
<a name="attribute-action-java-mapper"></a>

When you use the `DynamoDBMapper` and `AttributeEncryptor`, you use annotations to specify the attribute actions. The DynamoDB Encryption Client uses the [standard DynamoDB attribute annotations](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBMapper.Annotations.html) that define the attribute type to determine how to protect an attribute. By default, all attributes are encrypted and signed except for primary keys, which are signed but not encrypted.

**Note**  
Do not encrypt the value of attributes with the [@DynamoDBVersionAttribute annotation](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBMapper.OptimisticLocking.html), although you can (and should) sign them. Otherwise, conditions that use its value will have unintended effects.

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

To specify exceptions, use the encryption annotations defined in the DynamoDB Encryption Client for Java. If you specify them at the class level, they become the default value for the class.

```
// Sign only
@DoNotEncrypt

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

For example, these annotations sign but do not encrypt the `PublicationYear` attribute, and do not encrypt or sign the `ISBN` attribute value.

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

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

### Attribute actions for the DynamoDBEncryptor
<a name="attribute-action-default"></a>

To specify attribute actions when you use the [DynamoDBEncryptor](https://aws.github.io/aws-dynamodb-encryption-java/com/amazonaws/services/dynamodbv2/datamodeling/encryption/DynamoDBEncryptor.html) directly, create a `HashMap` object in which the name-value pairs represent attribute names and the specified actions. 

The valid values are for the attribute actions are defined in the `EncryptionFlags` enumerated type. You can use `ENCRYPT` and `SIGN` together, use `SIGN` alone, or omit both. However, if you use `ENCRYPT` alone, the DynamoDB Encryption Client throws an error. You cannot encrypt an attribute that you don't sign.

```
ENCRYPT
SIGN
```

**Warning**  
Do not encrypt the primary key attributes. They must remain in plaintext so DynamoDB can find the item without running a full table scan.

If you specify a primary key in the encryption context and then specify `ENCRYPT` in the attribute action for either primary key attribute, the DynamoDB Encryption Client throws an exception.

For example, the following Java code creates an `actions` HashMap that encrypts and signs all attributes in the `record` item. The exceptions are the partition key and sort key attributes, which are signed but not encrypted, and the `test` attribute, which is not signed or encrypted.

```
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;
  }
}
```

Then, when you call the [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-) method of the `DynamoDBEncryptor`, specify the map as the value of the `attributeFlags` parameter. For example, this call to `encryptRecord` uses the `actions` map.

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

## Overriding table names
<a name="override-table-name"></a>

In the DynamoDB Encryption Client, the name of the DynamoDB table is an element of the [DynamoDB encryption context](concepts.md#encryption-context) that is passed to the encryption and decryption methods. When you encrypt or sign table items, the DynamoDB encryption context, including the table name, is cryptographically bound to the ciphertext. If the DynamoDB encryption context that is passed to the decrypt method doesn't match the DynamoDB encryption context that was passed to the encrypt method, the decrypt operation fails.

Occasionally, the name of a table changes, such as when you back up a table or perform a [point-in-time recovery](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/PointInTimeRecovery.html). When you decrypt or verify the signature of these items, you must pass in the same DynamoDB encryption context that was used to encrypt and sign the items, including the original table name. The current table name is not needed. 

When you use the `DynamoDBEncryptor`, you assemble the DynamoDB encryption context manually. However, if you are using the `DynamoDBMapper`, the `AttributeEncryptor` creates the DynamoDB encryption context for you, including the current table name. To tell the `AttributeEncryptor` to create an encryption context with a different table name, use the `EncryptionContextOverrideOperator`. 

For example, the following code creates instances of the cryptographic materials provider (CMP) and the `DynamoDBEncryptor`. Then it calls the `setEncryptionContextOverrideOperator` method of the `DynamoDBEncryptor`. It uses the `overrideEncryptionContextTableName` operator, which overrides one table name. When it is configured this way, the `AttributeEncryptor` creates a DynamoDB encryption context that includes `newTableName` in place of `oldTableName`. For a complete example, see [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));
```

When you call the load method of the `DynamoDBMapper`, which decrypts and verifies the item, you specify the original table name.

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

You can also use the `overrideEncryptionContextTableNameUsingMap` operator, which overrides multiple table names. 

The table name override operators are typically used when decrypting data and verifying signatures. However, you can use them to set the table name in the DynamoDB encryption context to a different value when encrypting and signing.

Do not use the table name override operators if you are using the `DynamoDBEncryptor`. Instead, create an encryption context with the original table name and submit it to the decryption method.

# Example code for the DynamoDB Encryption Client for Java
<a name="java-examples"></a>

**Note**  
Our client-side encryption library was [renamed to AWS Database Encryption SDK](DDBEC-rename.md). The following topic provides information on versions 1.*x*—2.*x* of the DynamoDB Encryption Client for Java and versions 1.*x*—3.*x* of the DynamoDB Encryption Client for Python. For more information, see [AWS Database Encryption SDK for DynamoDB version support](legacy-dynamodb-encryption-client.md#legacy-support).

The following examples show you how to use the DynamoDB Encryption Client for Java to protect DynamoDB table items in your application. You can find more examples (and contribute your own) in the [examples](https://github.com/aws/aws-dynamodb-encryption-java/tree/master/examples) directory of the [aws-dynamodb-encryption-java](https://github.com/aws/aws-dynamodb-encryption-java/) repository on GitHub.

**Topics**
+ [Using the DynamoDBEncryptor](#java-example-ddb-encryptor)
+ [Using the DynamoDBMapper](#java-example-dynamodb-mapper)

## Using the DynamoDBEncryptor
<a name="java-example-ddb-encryptor"></a>

This example shows how to use the lower-level [DynamoDBEncryptor](https://aws.github.io/aws-dynamodb-encryption-java/com/amazonaws/services/dynamodbv2/datamodeling/encryption/DynamoDBEncryptor.html) with the [Direct KMS Provider](direct-kms-provider.md). The Direct KMS Provider generates and protects its cryptographic materials under an [AWS KMS key](https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#master_keys) in AWS Key Management Service (AWS KMS) that you specify.

You can use any compatible [cryptographic materials provider](DDBEC-legacy-concepts.md#concept-material-provider) (CMP) with the `DynamoDBEncryptor`, and you can use the Direct KMS Provider with the `DynamoDBMapper` and [AttributeEncryptor](java-using.md#attribute-encryptor).

**See the complete code sample**: [AwsKmsEncryptedItem.java](https://github.com/aws/aws-dynamodb-encryption-java/blob/master/examples/src/main/java/com/amazonaws/examples/AwsKmsEncryptedItem.java)

Step 1: Create the Direct KMS Provider  
Create an instance of the AWS KMS client with the specified region. Then, use the client instance to create an instance of the Direct KMS Provider with your preferred AWS KMS key.   
This example uses the Amazon Resource Name (ARN) to identify the AWS KMS key, but you can use [any valid key identifier](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);
```

Step 2: Create an item  
This example defines a `record` HashMap that represents a sample table item.  

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

Step 3: Create a DynamoDBEncryptor  
Create an instance of the `DynamoDBEncryptor` with the Direct KMS Provider.  

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

Step 4: Create a DynamoDB encryption context  
The [DynamoDB encryption context](concepts.md#encryption-context) contains information about the table structure and how it is encrypted and signed. If you use the `DynamoDBMapper`, the `AttributeEncryptor` creates the encryption context for you.  

```
final String tableName = "testTable";

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

Step 5: Create the attribute actions object  
[Attribute actions](DDBEC-legacy-concepts.md#legacy-attribute-actions) determine which attributes of the item are encrypted and signed, which are only signed, and which are not encrypted or signed.  
In Java, to specify attribute actions, you create a HashMap of attribute name and `EncryptionFlags` value pairs.   
For example, the following Java code creates an `actions` HashMap that encrypts and signs all attributes in the `record` item, except for the partition key and sort key attributes, which are signed, but not encrypted, and the `test` attribute, which is not signed or encrypted.  

```
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;
  }
}
```

Step 6: Encrypt and sign the item  
To encrypt and sign the table item, call the `encryptRecord` method on the instance of the `DynamoDBEncryptor`. Specify the table item (`record`), the attribute actions (`actions`), and the encryption context (`encryptionContext`).  

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

Step 7: Put the item in the DynamoDB table  
Finally, put the encrypted and signed item in the DynamoDB table.  

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

## Using the DynamoDBMapper
<a name="java-example-dynamodb-mapper"></a>

The following example shows you how to use the DynamoDB mapper helper class with the [Direct KMS Provider](direct-kms-provider.md). The Direct KMS Provider generates and protects its cryptographic materials under an [AWS KMS key](https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#master_keys) in AWS Key Management Service (AWS KMS) that you specify.

You can use any compatible [cryptographic materials provider](DDBEC-legacy-concepts.md#concept-material-provider) (CMP) with the `DynamoDBMapper`, and you can use the Direct KMS Provider with the lower-level `DynamoDBEncryptor`.

**See the complete code sample**: [AwsKmsEncryptedObject.java](https://github.com/aws/aws-dynamodb-encryption-java/blob/master/examples/src/main/java/com/amazonaws/examples/AwsKmsEncryptedObject.java)

Step 1: Create the Direct KMS Provider  
Create an instance of the AWS KMS client with the specified region. Then, use the client instance to create an instance of the Direct KMS Provider with your preferred AWS KMS key.   
This example uses the Amazon Resource Name (ARN) to identify the AWS KMS key, but you can use [any valid key identifier](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);
```

Step 2: Create the DynamoDB Encryptor and DynamoDBMapper  
Use the Direct KMS Provider that you created in the previous step to create an instance of the [DynamoDB Encryptor](java-using.md#attribute-encryptor). You need to instantiate the lower-level DynamoDB Encryptor to use the DynamoDB Mapper.  
Next, create an instance of your DynamoDB database and a mapper configuration, and use them to create an instance of the DynamoDB Mapper.   
When using the `DynamoDBMapper` to add or edit signed (or encrypted and signed) items, configure it to [use a save behavior](java-using.md#save-behavior), such as `PUT`, that includes all attributes, as shown in the following example. Otherwise, you might not be able to decrypt your data. 

```
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));
```

Step 3: Define your DynamoDB table  
Next, define your DynamoDB table. Use annotations to specify the [attribute actions](java-using.md#attribute-actions-java). This example creates a DynamoDB table, `ExampleTable`, and a `DataPoJo` class that represents table items.   
In this sample table, the primary key attributes will be signed but not encrypted. This applies to the `partition_attribute`, which is annotated with `@DynamoDBHashKey`, and the `sort_attribute`, which is annotated with `@DynamoDBRangeKey`.   
Attributes that are annotated with `@DynamoDBAttribute`, such as `some numbers`, will be encrypted and signed. The exceptions are attributes that use the `@DoNotEncrypt` (sign only) or `@DoNotTouch` (do not encrypt or sign) encryption annotations defined by the DynamoDB Encryption Client. For example, because the `leave me` attribute has a `@DoNotTouch` annotation, it will not be encrypted or signed.  

```
@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 + "]";
  }
}
```

Step 4: Encrypt and save a table item  
Now, when you create a table item and use the DynamoDB Mapper to save it, the item is automatically encrypted and signed before it is added to the table.  
This example defines a table item called `record`. Before it is saved in the table, its attributes are encrypted and signed based on the annotations in the `DataPoJo` class. In this case, all attributes except for `PartitionAttribute`, `SortAttribute`, and `LeaveMe` are encrypted and signed. `PartitionAttribute` and `SortAttributes` are only signed. The `LeaveMe` attribute is not encrypted or signed.  
To encrypt and sign the `record` item, and then add it to the `ExampleTable`, call the `save` method of the `DynamoDBMapper` class. Because your DynamoDB Mapper is configured to use the `PUT` save behavior, the item replaces any item with the same primary keys, instead of updating it. This ensures that the signatures match and you can decrypt the item when you get it from the table.  

```
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);
```

# DynamoDB Encryption Client for Python
<a name="python"></a>

**Note**  
Our client-side encryption library was [renamed to AWS Database Encryption SDK](DDBEC-rename.md). The following topic provides information on versions 1.*x*—2.*x* of the DynamoDB Encryption Client for Java and versions 1.*x*—3.*x* of the DynamoDB Encryption Client for Python. For more information, see [AWS Database Encryption SDK for DynamoDB version support](legacy-dynamodb-encryption-client.md#legacy-support).

This topic explains how to install and use the DynamoDB Encryption Client for Python. You can find the code in the [aws-dynamodb-encryption-python](https://github.com/aws/aws-dynamodb-encryption-python/) repository on GitHub, including complete and tested [sample code](https://github.com/aws/aws-dynamodb-encryption-python/tree/master/examples) to help you get started.

**Note**  
Versions 1.*x*.*x* and 2.*x*.*x* of the DynamoDB Encryption Client for Python are in [end-of-support phase](what-is-database-encryption-sdk.md#support) effective July 2022. Upgrade to a newer version as soon as possible.

**Topics**
+ [Prerequisites](#python-prerequisites)
+ [Installation](#python-installation)
+ [Using the DynamoDB Encryption Client for Python](python-using.md)
+ [Python examples](python-examples.md)

## Prerequisites
<a name="python-prerequisites"></a>

Before you install the Amazon DynamoDB Encryption Client for Python, be sure you have the following prerequisites.

**A supported version of Python**  
Python 3.8 or later is required by the Amazon DynamoDB Encryption Client for Python versions 3.3.0 and later. To download Python, see [Python downloads](https://www.python.org/downloads/).  
Earlier versions of the Amazon DynamoDB Encryption Client for Python support Python 2.7 and Python 3.4 and later, but we recommend that you use the latest version of the DynamoDB Encryption Client.

**The pip installation tool for Python**  
Python 3.6 and later include **pip**, although you might want to upgrade it. For more information about upgrading or installing pip, see [Installation](https://pip.pypa.io/en/latest/installation/) in the **pip** documentation.

## Installation
<a name="python-installation"></a>

Use **pip** to install the Amazon DynamoDB Encryption Client for Python, as shown in the following examples.

**To install the latest version**  

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

For more details about using **pip** to install and upgrade packages, see [Installing Packages](https://packaging.python.org/tutorials/installing-packages/).

The DynamoDB Encryption Client requires the [cryptography library](https://cryptography.io/en/latest/) on all platforms. All versions of **pip** install and build the **cryptography** library on Windows. **pip** 8.1 and later installs and builds **cryptography** on Linux. If you are using an earlier version of **pip** and your Linux environment doesn't have the tools needed to build the **cryptography** library, you need to install them. For more information, see [Building cryptography on Linux](https://cryptography.io/en/latest/installation/#building-cryptography-on-linux).

You can get the latest development version of the DynamoDB Encryption Client from the [aws-dynamodb-encryption-python](https://github.com/aws/aws-dynamodb-encryption-python/) repository on GitHub.

After you install the DynamoDB Encryption Client, get started by looking at the example Python code in this guide.

# Using the DynamoDB Encryption Client for Python
<a name="python-using"></a>

**Note**  
Our client-side encryption library was [renamed to AWS Database Encryption SDK](DDBEC-rename.md). The following topic provides information on versions 1.*x*—2.*x* of the DynamoDB Encryption Client for Java and versions 1.*x*—3.*x* of the DynamoDB Encryption Client for Python. For more information, see [AWS Database Encryption SDK for DynamoDB version support](legacy-dynamodb-encryption-client.md#legacy-support).

This topic explains some of the features of the DynamoDB Encryption Client for Python that might not be found in other programming language implementations. These features are designed to make it easier to use the DynamoDB Encryption Client in the most secure way. Unless you have an unusual use case, we recommend that you use them.

For details about programming with the DynamoDB Encryption Client, see the [Python examples](python-examples.md) in this guide, the [examples](https://github.com/aws/aws-dynamodb-encryption-python/tree/master/examples) in the aws-dynamodb-encryption-python repository on GitHub, and the [Python documentation](https://aws-dynamodb-encryption-python.readthedocs.io/en/latest/) for the DynamoDB Encryption Client.

**Topics**
+ [Client helper classes](#python-helpers)
+ [TableInfo class](#table-info)
+ [Attribute actions in Python](#python-attribute-actions)

## Client helper classes
<a name="python-helpers"></a>

The DynamoDB Encryption Client for Python includes several client helper classes that mirror the Boto 3 classes for DynamoDB. These helper classes are designed to make it easier to add encryption and signing to your existing DynamoDB application and avoid the most common problems, as follows:
+ Prevent you from encrypting the primary key in your item, either by adding an override action for the primary key to the [AttributeActions](#python-attribute-actions) object, or by throwing an exception if your `AttributeActions` object explicitly tells the client to encrypt the primary key. If the default action in your `AttributeActions` object is `DO_NOTHING`, the client helper classes use that action for the primary key. Otherwise, they use `SIGN_ONLY`.
+ Create a [TableInfo object](#python-helpers) and populate the [DynamoDB encryption context](concepts.md#encryption-context) based on a call to DynamoDB. This helps to ensure that your DynamoDB encryption context is accurate and the client can identify the primary key.
+ Support methods, such as `put_item` and `get_item`, that transparently encrypt and decrypt your table items when you write to or read from a DynamoDB table. Only the `update_item` method is unsupported.

You can use the client helper classes instead of interacting directly with the lower-level [item encryptor](DDBEC-legacy-concepts.md#item-encryptor). Use these classes unless you need to set advanced options in the item encryptor.

The client helper classes include:
+ [EncryptedTable](https://aws-dynamodb-encryption-python.readthedocs.io/en/latest/lib/encrypted/table.html#module-dynamodb_encryption_sdk.encrypted.table) for applications that use the [Table](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb.html#table) resource in DynamoDB to process one table at a time.
+ [EncryptedResource](https://aws-dynamodb-encryption-python.readthedocs.io/en/latest/lib/encrypted/resource.html) for applications that use the [Service Resource](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb.html#service-resource) class in DynamoDB for batch processing.
+ [EncryptedClient](https://aws-dynamodb-encryption-python.readthedocs.io/en/latest/lib/encrypted/client.html) for applications that use the [lower-level client](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb.html#client) in DynamoDB.

To use the client helper classes, the caller must have permission to call the DynamoDB [DescribeTable](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_DescribeTable.html) operation on the target table.

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

The [TableInfo](https://aws-dynamodb-encryption-python.readthedocs.io/en/latest/lib/tools/structures.html#dynamodb_encryption_sdk.structures.TableInfo) class is a helper class that represents a DynamoDB table, complete with fields for its primary key and secondary indexes. It helps you to get accurate, real-time information about the table.

If you use a [client helper class](#python-helpers), it creates and uses a `TableInfo` object for you. Otherwise, you can create one explicitly. For an example, see [Use the item encryptor](python-examples.md#python-example-item-encryptor).

When you call the `refresh_indexed_attributes` method on a `TableInfo` object, it populates the property values of the object by calling the DynamoDB [DescribeTable](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_DescribeTable.html) operation. Querying the table is much more reliable than hard-coding index names. The `TableInfo` class also includes an `encryption_context_values` property that provides the required values for the [DynamoDB encryption context](concepts.md#encryption-context). 

To use the `refresh_indexed_attributes` method, the caller must have permission to call the DynamoDB [DescribeTable](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_DescribeTable.html) operation on the target table.

## Attribute actions in Python
<a name="python-attribute-actions"></a>

[Attribute actions](DDBEC-legacy-concepts.md#legacy-attribute-actions) tell the item encryptor which actions to perform on each attribute of the item. To specify attribute actions in Python, create an `AttributeActions` object with a default action and any exceptions for particular attributes. The valid values are defined in the `CryptoAction` enumerated type.

**Important**  
After you use your attribute actions to encrypt your table items, adding or removing attributes from your data model might cause a signature validation error that prevents you from decrypting your data. For a detailed explanation, see [Changing your data model](data-model.md).

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

For example, this `AttributeActions` object establishes `ENCRYPT_AND_SIGN` as the default for all attributes, and specifies exceptions for the `ISBN` and `PublicationYear` attributes.

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

If you use a [client helper class](#python-helpers), you don't need to specify an attribute action for the primary key attributes. The client helper classes prevent you from encrypting your primary key.

If you do not use a client helper class and the default action is `ENCRYPT_AND_SIGN`, you must specify an action for the primary key. The recommended action for primary keys is `SIGN_ONLY`. To make this easy, use the `set_index_keys` method, which uses SIGN\$1ONLY for primary keys, or DO\$1NOTHING, when that is the default action.

**Warning**  
Do not encrypt the primary key attributes. They must remain in plaintext so DynamoDB can find the item without running a full table scan.

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

# Example code for the DynamoDB Encryption Client for Python
<a name="python-examples"></a>

**Note**  
Our client-side encryption library was [renamed to AWS Database Encryption SDK](DDBEC-rename.md). The following topic provides information on versions 1.*x*—2.*x* of the DynamoDB Encryption Client for Java and versions 1.*x*—3.*x* of the DynamoDB Encryption Client for Python. For more information, see [AWS Database Encryption SDK for DynamoDB version support](legacy-dynamodb-encryption-client.md#legacy-support).

The following examples show you how to use the DynamoDB Encryption Client for Python to protect DynamoDB data in your application. You can find more examples (and contribute your own) in the [examples](https://github.com/aws/aws-dynamodb-encryption-python/tree/master/examples) directory of the [aws-dynamodb-encryption-python](https://github.com/aws/aws-dynamodb-encryption-python/) repository on GitHub.

**Topics**
+ [Use the EncryptedTable client helper class](#python-example-table)
+ [Use the item encryptor](#python-example-item-encryptor)

## Use the EncryptedTable client helper class
<a name="python-example-table"></a>

The following example shows you how to use the [Direct KMS Provider](direct-kms-provider.md) with the `EncryptedTable` [client helper class](python-using.md#python-helpers). This example uses the same [cryptographic materials provider](DDBEC-legacy-concepts.md#concept-material-provider) as the [Use the item encryptor](#python-example-item-encryptor) example that follows. However, it uses the `EncryptedTable` class instead of interacting directly with the lower-level [item encryptor](DDBEC-legacy-concepts.md#item-encryptor).

By comparing these examples, you can see the work that the client helper class does for you. This includes creating the [DynamoDB encryption context](concepts.md#encryption-context) and making sure the primary key attributes are always signed, but never encrypted. To create the encryption context and discover the primary key, the client helper classes call the DynamoDB [DescribeTable](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_DescribeTable.html) operation. To run this code, you must have permission to call this operation.

**See the complete code sample**: [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)

Step 1: Create the table  
Start by creating an instance of a standard DynamoDB table with the table name.  

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

Step 2: Create a cryptographic materials provider  
Create an instance of the [cryptographic materials provider](crypto-materials-providers.md) (CMP) that you selected.  
This example uses the [Direct KMS Provider](direct-kms-provider.md), but you can use any compatible CMP. To create a Direct KMS Provider, specify an [AWS KMS key](https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#master_keys). This example uses the Amazon Resource Name (ARN) of the AWS KMS key, but you can use any valid key identifier.  

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

Step 3: Create the attribute actions object  
[Attribute actions](DDBEC-legacy-concepts.md#legacy-attribute-actions) tell the item encryptor which actions to perform on each attribute of the item. The `AttributeActions` object in this example encrypts and signs all items except for the `test` attribute, which is ignored.  
Do not specify attribute actions for the primary key attributes when you use a client helper class. The `EncryptedTable` class signs, but never encrypts, the primary key attributes.  

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

Step 4: Create the encrypted table  
Create the encrypted table using the standard table, the Direct KMS Provider, and the attribute actions. This step completes the configuration.   

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

Step 5: Put the plaintext item in the table  
When you call the `put_item` method on the `encrypted_table`, your table items are transparently encrypted, signed, and added to your DynamoDB table.  
First, define the table item.  

```
plaintext_item = {
    'partition_attribute': 'value1',
    'sort_attribute': 55
    'example': 'data',
    'numbers': 99,
    'binary': Binary(b'\x00\x01\x02'),
    'test': 'test-value'
}
```
Then, put it in the table.  

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

To get the item from the DynamoDB table in its encrypted form, call the `get_item` method on the `table` object. To get the decrypted item, call the `get_item` method on the `encrypted_table` object.

## Use the item encryptor
<a name="python-example-item-encryptor"></a>

This example shows you how to interact directly with the [item encryptor](DDBEC-legacy-concepts.md#item-encryptor) in the DynamoDB Encryption Client when encrypting table items, instead of using the [client helper classes](python-using.md#python-helpers) that interact with the item encryptor for you. 

When you use this technique, you create the DynamoDB encryption context and configuration object (`CryptoConfig`) manually. Also, you encrypt the items in one call and put them in your DynamoDB table in a separate call. This allows you to customize your `put_item` calls and use the DynamoDB Encryption Client to encrypt and sign structured data that is never sent to DynamoDB.

This example uses the [Direct KMS Provider](direct-kms-provider.md), but you can use any compatible CMP.

**See the complete code sample**: [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)

Step 1: Create the table  
Start by creating an instance of a standard DynamoDB table resource with the table name.  

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

Step 2: Create a cryptographic materials provider  
Create an instance of the [cryptographic materials provider](crypto-materials-providers.md) (CMP) that you selected.  
This example uses the [Direct KMS Provider](direct-kms-provider.md), but you can use any compatible CMP. To create a Direct KMS Provider, specify an [AWS KMS key](https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#master_keys). This example uses the Amazon Resource Name (ARN) of the AWS KMS key, but you can use any valid key identifier.  

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

Step 3: Use the TableInfo helper class  
To get information about the table from DynamoDB, create an instance of the [TableInfo](python-using.md#python-helpers) helper class. When you work directly with the item encryptor, you need to create a `TableInfo` instance and call its methods. The [client helper classes](python-using.md#python-helpers) do this for you.  
The `refresh_indexed_attributes` method of `TableInfo` uses the [DescribeTable](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_DescribeTable.html) DynamoDB operation to get real-time, accurate information about the table. This includes its primary key and its local and global secondary indexes. The caller needs to have permission to call `DescribeTable`.  

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

Step 4: Create the DynamoDB encryption context  
The [DynamoDB encryption context](concepts.md#encryption-context) contains information about the table structure and how it is encrypted and signed. This example creates a DynamoDB encryption context explicitly, because it interacts with the item encryptor. The [client helper classes](python-using.md#python-helpers) create the DynamoDB encryption context for you.   
To get the partition key and sort key, you can use the properties of the [TableInfo](python-using.md#python-helpers) helper class.   

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

Step 5: Create the attribute actions object  
[Attribute actions](DDBEC-legacy-concepts.md#legacy-attribute-actions) tell the item encryptor which actions to perform on each attribute of the item. The `AttributeActions` object in this example encrypts and signs all items except for the primary key attributes, which are signed, but not encrypted, and the `test` attribute, which is ignored.  
When you interact directly with the item encryptor and your default action is `ENCRYPT_AND_SIGN`, you must specify an alternative action for the primary key. You can use the `set_index_keys` method, which uses `SIGN_ONLY` for the primary key, or it uses `DO_NOTHING` if it's the default action.  
To specify the primary key, this example uses the index keys in the [TableInfo](python-using.md#python-helpers) object, which is populated by a call to DynamoDB. This technique is safer than hard-coding primary key names.  

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

Step 6: Create the configuration for the item  
To configure the DynamoDB Encryption Client, use the objects that you just created in a [CryptoConfig](https://aws-dynamodb-encryption-python.readthedocs.io/en/latest/lib/encrypted/config.html) configuration for the table item. The client helper classes create the CryptoConfig for you.   

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

Step 7: Encrypt the item  
This step encrypts and signs the item, but it doesn't put it in the DynamoDB table.   
When you use a client helper class, your items are transparently encrypted and signed, and then added to your DynamoDB table when you call the `put_item` method of the helper class. When you use the item encryptor directly, the encrypt and put actions are independent.  
First, create a plaintext item.  

```
plaintext_item = {
    'partition_attribute': 'value1',
    'sort_key': 55,
    'example': 'data',
    'numbers': 99,
    'binary': Binary(b'\x00\x01\x02'),
    'test': 'test-value'
}
```
Then, encrypt and sign it. The `encrypt_python_item` method requires the `CryptoConfig` configuration object.  

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

Step 8: Put the item in the table  
This step puts the encrypted and signed item in the DynamoDB table.  

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

To view the encrypted item, call the `get_item` method on the original `table` object, instead of the `encrypted_table` object. It gets the item from the DynamoDB table without verifying and decrypting it.

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

The following image shows part of an example encrypted and signed table item.

The encrypted attribute values are binary data. The names and values of the primary key attributes (`partition_attribute` and `sort_attribute`) and the `test` attribute remain in plaintext. The output also shows the attribute that contains the signature (`*amzn-ddb-map-sig*`) and the [materials description attribute](DDBEC-legacy-concepts.md#legacy-material-description) (`*amzn-ddb-map-desc*`).

![\[An excerpt of an encrypted and signed item\]](http://docs.aws.amazon.com/database-encryption-sdk/latest/devguide/images/encrypted-item-closeup.png)


# Changing your data model
<a name="data-model"></a>

**Note**  
Our client-side encryption library was [renamed to AWS Database Encryption SDK](DDBEC-rename.md). The following topic provides information on versions 1.*x*—2.*x* of the DynamoDB Encryption Client for Java and versions 1.*x*—3.*x* of the DynamoDB Encryption Client for Python. For more information, see [AWS Database Encryption SDK for DynamoDB version support](legacy-dynamodb-encryption-client.md#legacy-support).

Every time you encrypt or decrypt an item, you need to provide [attribute actions](DDBEC-legacy-concepts.md#legacy-attribute-actions) that tell the DynamoDB Encryption Client which attributes to encrypt and sign, which attributes to sign (but not encrypt), and which to ignore. Attribute actions are not saved in the encrypted item and the DynamoDB Encryption Client does not update your attribute actions automatically.

**Important**  
The DynamoDB Encryption Client does not support the encryption of existing, unencrypted DynamoDB table data.

Whenever you change your data model, that is, when you add or remove attributes from your table items, you risk an error. If the attribute actions that you specify do not account for all attributes in the item, the item might not be encrypted and signed the way that you intend. More importantly, if the attribute actions that you provide when decrypting an item differ from the attribute actions that you provided when encrypting the item, the signature verification might fail. 

For example, if the attribute actions used to encrypt the item tell it to sign the `test` attribute, the signature in the item will include the `test` attribute. But if the attribute actions used to decrypt the item do not account for the `test` attribute, the verification will fail because the client will try to verify a signature that does not include the `test` attribute. 

This is a particular problem when multiple applications read and write the same DynamoDB items because the DynamoDB Encryption Client must calculate the same signature for items in all applications. It's also a problem for any distributed application because changes in attribute actions must propagate to all hosts. Even if your DynamoDB tables are accessed by one host in one process, establishing a best practice process will help prevent errors if the project ever becomes more complex.

To avoid signature validation errors that prevent you from reading your table items, use the following guidance.
+ [Adding an attribute](#add-attribute) — If the new attribute changes your attribute actions, fully deploy the attribute action change before including the new attribute in an item.
+ [Removing an attribute](#remove-attribute) — If you stop using an attribute in your items, do not change your attribute actions. 
+ Changing the action — After you have used an attribute actions configuration to encrypt your table items, you cannot safely change the default action or the action for an existing attribute without re-encrypting every item in your table.

Signature validation errors can be extremely difficult to resolve, so the best approach is to prevent them. 

**Topics**
+ [Adding an attribute](#add-attribute)
+ [Removing an attribute](#remove-attribute)

## Adding an attribute
<a name="add-attribute"></a>

When you add a new attribute to table items, you might need to change your attribute actions. To prevent signature validation errors, we recommend that you implement this change in a two-stage process. Verify that the first stage is complete before starting the second stage.

1. Change the attribute actions in all applications that read or write to the table. Deploy these changes and confirm that the update has been propagated to all destination hosts. 

1. Write values to the new attribute in your table items.

This two-stage approach ensures that all applications and hosts have the same attribute actions, and will calculate the same signature, before any encounter the new attribute. This is important even when the action for the attribute is *Do nothing* (don't encrypt or sign), because the default for some encryptors is to encrypt and sign.

The following examples show the code for the first stage in this process. They add a new item attribute, `link`, which stores a link to another table item. Because this link must remain in plain text, the example assigns it the sign-only action. After fully deploying this change and then verifying that all applications and hosts have the new attribute actions, you can begin to use the `link` attribute in your table items.

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

When using the `DynamoDB Mapper` and `AttributeEncryptor`, by default, all attributes are encrypted and signed except for primary keys, which are signed but not encrypted. To specify a sign-only action, use the `@DoNotEncrypt` annotation. 

This example uses the `@DoNotEncrypt` annotation for the new `link` attribute.

```
@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 ]

 In the lower-level DynamoDB encryptor, you must set actions for each attribute. This example uses a switch statement where the default is `encryptAndSign` and exceptions are specified for the partition key, sort key, and the new `link` attribute. In this example, if the link attribute code was not fully deployed before it was used, the link attribute would be encrypted and signed by some applications, but only signed by others.

```
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 ]

In the DynamoDB Encryption Client for Python, you can specify a default action for all attributes and then specify exceptions. 

If you use a Python [client helper class](python-using.md#python-helpers), you don't need to specify an attribute action for the primary key attributes. The client helper classes prevent you from encrypting your primary key. However, if you are not using a client helper class, you must set the SIGN\$1ONLY action on your partition key and sort key. If you accidentally encrypt your partition or sort key, you won't be able to recover your data without a full table scan.

This example specifies an exception for the new `link` attribute, which gets the `SIGN_ONLY` action.

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

------

## Removing an attribute
<a name="remove-attribute"></a>

If you no longer need an attribute in items that have been encrypted with the DynamoDB Encryption Client, you can stop using the attribute. However, do not delete or change the action for that attribute. If you do, and then encounter an item with that attribute, the signature calculated for the item will not match the original signature, and the signature validation will fail.

Although you might be tempted to remove all traces of the attribute from your code, add a comment that the item is no longer used instead of deleting it. Even if you do a full table scan to delete all instances of the attribute, an encrypted item with that attribute might be cached or in process somewhere in your configuration.

# Troubleshooting issues in your DynamoDB Encryption Client application
<a name="troubleshooting"></a>

**Note**  
Our client-side encryption library was [renamed to AWS Database Encryption SDK](DDBEC-rename.md). The following topic provides information on versions 1.*x*—2.*x* of the DynamoDB Encryption Client for Java and versions 1.*x*—3.*x* of the DynamoDB Encryption Client for Python. For more information, see [AWS Database Encryption SDK for DynamoDB version support](legacy-dynamodb-encryption-client.md#legacy-support).

This section describes problems that you might encounter when using the DynamoDB Encryption Client and offers suggestions for resolving them.

To provide feedback on the DynamoDB Encryption Client, file an issue in the [aws-dynamodb-encryption-java](https://github.com/aws/aws-dynamodb-encryption-java/) or [aws-dynamodb-encryption-python](https://github.com/aws/aws-dynamodb-encryption-python/) GitHub repository.

To provide feedback on this documentation, use the feedback link on any page.

**Topics**
+ [Access denied](#kms-permissions)
+ [Signature verification fails](#change-data-model)
+ [Issues with older version global tables](#fix-global-tables)
+ [Poor performance of the Most Recent Provider](#mrp-ttl-delay)

## Access denied
<a name="kms-permissions"></a>

**Problem**: Your application is denied access to a resource that it needs.

**Suggestion**: Learn about the required permissions and add them to the security context in which your application runs.

**Details**

To run an application that uses the a DynamoDB Encryption Client library, the caller must have permission to use its components. Otherwise, they will be denied access to the required elements. 
+ The DynamoDB Encryption Client does not require an Amazon Web Services (AWS) account or depend on any AWS service. However, if your application uses AWS, you need [an AWS account](https://aws.amazon.com/premiumsupport/knowledge-center/create-and-activate-aws-account/) and [users who have permission](https://docs.aws.amazon.com/IAM/latest/UserGuide/getting-started_create-admin-group.html) to use the account.
+ The DynamoDB Encryption Client does not require Amazon DynamoDB. However, If the application that uses the client creates DynamoDB tables, puts items into a table, or gets items from a table, the caller must have permission to use the required DynamoDB operations in your AWS account. For details, see the [access control topics](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/access-control-overview.html) in the *Amazon DynamoDB Developer Guide*.
+ If your application uses a [client helper class](python-using.md#python-helpers) in the DynamoDB Encryption Client for Python, the caller must have permission to call the DynamoDB [DescribeTable](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_DescribeTable.html) operation.
+ The DynamoDB Encryption Client does not require AWS Key Management Service (AWS KMS). However, if your application uses a [Direct KMS Materials Provider](direct-kms-provider.md), or it uses a [Most Recent Provider](most-recent-provider.md) with a provider store that uses AWS KMS, the caller must have permission to use the AWS KMS [GenerateDataKey](https://docs.aws.amazon.com/kms/latest/APIReference/API_GenerateDataKey.html) and [Decrypt](https://docs.aws.amazon.com/kms/latest/APIReference/API_Decrypt.html) operations.

## Signature verification fails
<a name="change-data-model"></a>

**Problem**: An item cannot be decrypted because signature verification fails. The item also might not be encrypted and signed as you intend.

**Suggestion**: Be sure that the attribute actions that you provide account for all attributes in the item. When decrypting an item, be sure to provide attribute actions that match the actions used to encrypt the item.

**Details**

The [attribute actions](DDBEC-legacy-concepts.md#legacy-attribute-actions) that you provide tell the DynamoDB Encryption Client which attributes to encrypt and sign, which attributes to sign (but not encrypt), and which to ignore. 

If the attribute actions that you specify do not account for all attributes in the item, the item might not be encrypted and signed the way that you intend. If the attribute actions that you provide when decrypting an item differ from the attribute actions that you provided when encrypting the item, the signature verification might fail. This is a particular problem for distributed applications in which new attribute actions might not have propagated to all hosts.

Signature validation errors are difficult to resolve. For help preventing them, take extra precautions when changing your data model. For details, see [Changing your data model](data-model.md).

## Issues with older version global tables
<a name="fix-global-tables"></a>

**Problem**: Items in an older version Amazon DynamoDB global table cannot be decrypted because signature verification fails.

**Suggestion**: Set attribute actions so the reserved replication fields are not encrypted or signed.

**Details**

You can use the DynamoDB Encryption Client with [DynamoDB global tables](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GlobalTables.html). We recommend that you use global tables with a [multi-Region KMS key](https://docs.aws.amazon.com/kms/latest/developerguide/multi-region-keys-overview.html) and replicate the KMS key into all AWS Regions where the global table is replicated.

Beginning with global tables [version 2019.11.21](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/globaltables.V2.html), you can use global tables with the DynamoDB Encryption Client without any special configuration. However, if you use global tables [version 2017.11.29](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/globaltables.V1.html), you must ensure that reserved replication fields are not encrypted or signed.

If you are using the global tables version 2017.11.29, you must set the attribute actions for the following attributes to `DO_NOTHING` in [Java](java-using.md#attribute-actions-java) or `@DoNotTouch` in [Python](python-using.md#python-attribute-actions).
+ `aws:rep:deleting`
+ `aws:rep:updatetime`
+ `aws:rep:updateregion`

If you are using any other version of global tables, no action is required.

## Poor performance of the Most Recent Provider
<a name="mrp-ttl-delay"></a>

**Problem**: Your application is less responsive, especially after updating to a newer version of the DynamoDB Encryption Client.

**Suggestion**: Adjust the time-to-live value and cache size.

**Details**

The Most Recent Provider is designed to improve the performance of applications that use the DynamoDB Encryption Client by allowing limited reuse of cryptographic materials. When you configure the Most Recent Provider for your application, you have to balance improved performance with the security concerns that arise from caching and reuse. 

In newer versions of the DynamoDB Encryption Client, the time-to-live (TTL) value determines how long cached cryptographic material providers (CMPs) can be used. The TTL also determines how often the Most Recent Provider checks for a new version of the CMP. 

If your TTL is too long, your application might violate your business rules or security standards. If your TTL is too brief, frequent calls to the provider store can cause your provider store to throttle requests from your application and other applications that share your service account. To resolve this issue, adjust the TTL and cache size to a value that meets your latency and availability goals and conforms to your security standards. For details, see [Setting a time-to-live value](most-recent-provider.md#most-recent-provider-ttl).