Amazon DynamoDB Encryption Client
Developer Guide

Using the DynamoDB Encryption Client for Java

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, the examples in the aws-dynamodb-encryption-java repository on GitHub, and the Javadoc for the DynamoDB Encryption Client.

Item Encryptors: AttributeEncryptor and DynamoDBEncryptor

The DynamoDB Encryption Client in Java has two item encryptors: the lower-level DynamoDBEncryptor and the AttributeEncryptor.

The AttributeEncryptor is a helper class that enables you to use the DynamoDBMapper 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, and transparently verifies and decrypts your items when you load them.

Configuring Save Behavior

When you use the AttributeEncryptor and DynamoDBMapper to add or edit table items with attributes that are signed only or encrypted and signed, 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 the attributes in the table item, only attributes that have changed are included in the signature. That signature might not match the signature of the entire item that is calculated on decrypt.

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

To see this code used in an example, see Using the DynamoDB Mapper and the AwsKmsEncryptedObject.java example in the aws-dynamodb-encryption-java repository in GitHub.

Attribute Actions in Java

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.

Attribute Actions for the DynamoDB Mapper

When you use the DynamoDBMapper and AttributeEncryptor helper classes, you use annotations to specify the attribute actions. The DynamoDB Encryption Client uses the standard DynamoDB attribute annotations 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, 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

To specify attribute actions when you use the DynamoDBEncryptor 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 will throw an exception.

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: // 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 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);