Java examples - AWS Database Encryption SDK

Java examples

Our client-side encryption library was renamed to the AWS Database Encryption SDK. This developer guide still provides information on the DynamoDB Encryption Client.

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

Using the DynamoDB enhanced client

The following example shows how to use the DynamoDB Enhanced Client and DynamoDbEncryptionInterceptor with an AWS KMS keyring to encrypt DynamoDB table items as part of your DynamoDB API calls.

You can use any supported keyring 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. Use the DynamoDbEncryptionInterceptor with the low-level DynamoDB API to use searchable encryption.

See the complete code sample: 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. For more guidance on annotating your attribute actions, see Use an annotated data class.

Note

The AWS Database Encryption SDK does not support annotations on nested attributes.

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.

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

Note

To use searchable encryption or signed beacons, you must also include the SearchConfig 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

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

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

See the complete code sample: 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 for a table item.

Note

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.

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

Note

To use searchable encryption or signed beacons, you must also include the SearchConfig 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

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

You can use any supported keyring 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. Use the DynamoDbEncryptionInterceptor with the low-level DynamoDB API to use searchable encryption.

See the complete code sample: 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 for a table item.

Note

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.

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

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