📣 Note: Version 3.x of this library is available, and has been renamed to the AWS Database Encryption SDK. See the AWS Database Encryption SDK 3.x section for more information.
The Amazon DynamoDB Client-side Encryption in Java supports encryption and signing of your data when stored in Amazon DynamoDB.
A typical use of this library is when you are using DynamoDBMapper, where transparent protection of all objects serialized through the mapper can be enabled via configuring an AttributeEncryptor.
Important: Use SaveBehavior.PUT
or SaveBehavior.CLOBBER
with AttributeEncryptor
. If you do not do so you risk corrupting your signatures and encrypted data.
When PUT or CLOBBER is not specified, fields that are present in the record may not be passed down to the encryptor, which results in fields being left out of the record signature. This in turn can result in records failing to decrypt.
For more advanced use cases where tighter control over the encryption and signing process is necessary, the low-level DynamoDBEncryptor can be used directly.
See Support Policy for for details on the current support status of all major versions of this library.
The 3.x version of this library is generally available, and has been renamed to the AWS Database Encryption SDK. It is a major rewrite of the DynamoDB Encryption Client for Java and includes many updates, such as a new structured data format, improved multitenancy support, seamless schema changes, and searchable encryption support.
For more information see the AWS Database Encryption SDK Developer Guide. or check the project repository at https://github.com/aws/aws-database-encryption-sdk-dynamodb-java/.
To use this SDK you must have:
-
A Java 8 development environment
If you do not have one, go to Java SE Downloads on the Oracle website, then download and install the Java SE Development Kit (JDK). Java 8 or higher is required.
Note: If you use the Oracle JDK, you must also download and install the Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files.
Suppose you have created (sample code) a DynamoDB table "MyStore", and want to store some Book objects. The security requirement involves classifying the attributes Title and Authors as sensitive information. This is how the Book class may look like:
@DynamoDBTable(tableName="MyStore")
public class Book {
private Integer id;
private String title;
private String ISBN;
private Set<String> bookAuthors;
private String someProp;
// Not encrypted because it is a hash key
@DynamoDBHashKey(attributeName="Id")
public Integer getId() { return id;}
public void setId(Integer id) {this.id = id;}
// Encrypted by default
@DynamoDBAttribute(attributeName="Title")
public String getTitle() {return title; }
public void setTitle(String title) { this.title = title; }
// Specifically not encrypted
@DoNotEncrypt
@DynamoDBAttribute(attributeName="ISBN")
public String getISBN() { return ISBN; }
public void setISBN(String ISBN) { this.ISBN = ISBN; }
// Encrypted by default
@DynamoDBAttribute(attributeName = "Authors")
public Set<String> getBookAuthors() { return bookAuthors; }
public void setBookAuthors(Set<String> bookAuthors) { this.bookAuthors = bookAuthors; }
// Not encrypted nor signed
@DoNotTouch
public String getSomeProp() { return someProp;}
public void setSomeProp(String someProp) {this.someProp = someProp;}
}
As a typical use case of DynamoDBMapper, you can easily save and retrieve a Book object to and from Amazon DynamoDB without encryption (nor signing). For example,
AmazonDynamoDBClient client = new AmazonDynamoDBClient(...);
DynamoDBMapper mapper = new DynamoDBMapper(client);
Book book = new Book();
book.setId(123);
book.setTitle("Secret Book Title ");
// ... etc. setting other properties
// Saves the book unencrypted to DynamoDB
mapper.save(book);
// Loads the book back from DynamoDB
Book bookTo = new Book();
bookTo.setId(123);
Book bookTo = mapper.load(bookTo);
To enable transparent encryption and signing, simply specify the necessary encryption material via an EncryptionMaterialsProvider. For example:
AmazonDynamoDBClient client = new AmazonDynamoDBClient(...);
SecretKey cek = ...; // Content encrypting key
SecretKey macKey = ...; // Signing key
EncryptionMaterialsProvider provider = new SymmetricStaticProvider(cek, macKey);
mapper = new DynamoDBMapper(client, DynamoDBMapperConfig.builder().withSaveBehavior(SaveBehavior.PUT).build(),
new AttributeEncryptor(provider));
Book book = new Book();
book.setId(123);
book.setTitle("Secret Book Title ");
// ... etc. setting other properties
// Saves the book both encrypted and signed to DynamoDB
mapper.save(bookFrom);
// Loads the book both with signature verified and decrypted from DynamoDB
Book bookTo = new Book();
bookTo.setId(123);
Book bookTo = mapper.load(bookTo);
Note that by default all attributes except the primary keys are both encrypted and signed for maximum security. To selectively disable encryption, the annotation @DoNotEncrypt can be used as shown in the Book class above. To disable both encryption and signing, the annotation @DoNotTouch can be used.
There is a variety of existing EncryptionMaterialsProvider implementations that you can use to provide the encryption material, including KeyStoreMaterialsProvider which makes use of a Java keystore. Alternatively, you can also plug in your own custom implementation.
Every time you encrypt or decrypt an item, you need to provide 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.
Whenever you change your data model, that is, when you add or remove attributes from your table items, you need to take additional steps to safely migrate the client-side encryption configuration.
For guidance on this process, please see the developer guide on Changing Your Data Model.
You can download the latest snapshot release or pick it up from Maven:
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-dynamodb-encryption-java</artifactId>
<version>2.0.3</version>
</dependency>
Don't forget to enable the download of snapshot jars from Maven:
<profiles>
<profile>
<id>allow-snapshots</id>
<activation><activeByDefault>true</activeByDefault></activation>
<repositories>
<repository>
<id>snapshots-repo</id>
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
<releases><enabled>false</enabled></releases>
<snapshots><enabled>true</enabled></snapshots>
</repository>
</repositories>
</profile>
</profiles>
For content encryption, the encryption algorithm is determined by the user specified SecretKey, as long as it is a block cipher that can be used with the encryption mode "CBC" and "PKCS5Padding". Typically, this means "AES".
For signing, the user specified signing key can be either symmetric or asymmetric. For asymmetric signing (where the user would provide a signing key in the form of a PrivateKey), the default algorithm is "SHA256withRSA". For symmetric signing (where the user would provide the signing key in the form of a SecretKey), the algorithm would be determined by the provided key. A typical algorithm for a symmetric signing key is "HmacSHA256".
- Do the content-encrypting key and signing key get encrypted and stored along side with the data in Amazon DynamoDB ?
- No, neither the content-encrypting key nor the signing key get persisted by this library. However, in order to locate the material for decryption purposes, the identifying information (i.e. material descriptions) for the encryption material is indeed stored along side with the data in Amazon DynamoDB. In particular, the user specified EncryptionMaterialsProvider is responsible for not only providing the keys, but also the corresponding material descriptions.
- How is the IV generated and where is it stored ?
- For each attribute that needs to be encrypted, a unique IV is randomly generated, and get stored along side with the binary representation of the attribute value.
- How many bits are used for the random IV ?
- The bit size used for each random IV is the same as the block size of the block cipher used for content encryption. The IV bit-size therefore depends on the specific algorithm of the content encrypting key provided by the user. Typically this means AES, or 128 bits.
- What is the key length for the content encrypting key ?
- This depends on the specific content encrypting key provided by the user. A typical length of an AES key is 128 bits or 256 bits.
- During retrieval of an item, all the attributes of the item that have been involved for encryption or signing must also be included for signature verification. Otherwise, the signature would fail to verify.