GithubHelp home page GithubHelp logo

aws-dynamodb-encryption-java's Introduction

Client-side Encryption for Amazon DynamoDB

๐Ÿ“ฃ 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.

Security issue notifications

See Support Policy for for details on the current support status of all major versions of this library.

AWS Database Encryption SDK 3.x

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

Getting Started

Required Prerequisites

To use this SDK you must have:

Get Started

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.

Changing Your Data Model

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.

Downloads

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>

Supported Algorithms

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

FAQ

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

Known Limitations

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

aws-dynamodb-encryption-java's People

Contributors

acioc avatar alex-chew avatar apivovarov avatar bdonlan avatar bhuvangu avatar bmaizels avatar david-koenig avatar dependabot[bot] avatar farleyb-amazon avatar hansonchar avatar imabhichow avatar johnwalker avatar josecorella avatar juneb avatar kaiyaok2 avatar lavaleri avatar lizroth avatar lucasmcdonald3 avatar mattsb42-aws avatar mmarston avatar robin-aws avatar salusasecondus avatar seebees avatar texastony avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

aws-dynamodb-encryption-java's Issues

Don't print AttributeValues in EncryptionContext.toString()

https://github.com/aws/aws-dynamodb-encryption-java/blob/master/sdk1/src/main/java/com/amazonaws/services/dynamodbv2/datamodeling/encryption/EncryptionContext.java#L220

https://github.com/aws/aws-dynamodb-encryption-java/blob/master/sdk2/src/main/java/software/amazon/cryptools/dynamodbencryptionclientsdk2/encryption/EncryptionContext.java#L182

A safe toString() method for EncryptionContext would be extremely useful for logging within material providers, and we can get there by excluding attributeValues from being printed. Since it is likely that tests rely on this today, we should consider doing this with a minor bump. (Note: We haven't published the sdk2 version yet, so it's not necessary to do a bump there.)

Support Point in time restore with client side encryption

Point in time restore takes table name as an input. In DynamoDB if a table already exists you can not overwrite the table data by doing a restore, you have to restore to new table with a different name.

If customers were using client side encryption library all the data items will be signed using the table name and stored with the item. If they do a point in time restore on this table restoring the table to a new table name will mean the restored data is not readable as the signatures stored on the items would fail to verify.

We need some way for customers to be able to specify that they want to use the older table name for the restored table so that they can still read and write data to the DynamoDB table even though it was restored as a new table.

Support DoNotEncrypt/DoNotTouch field level annotations

They're only targeting ElementType.METHOD at the moment, unlike DynamoDbAttribute which can be on a ElementType.FIELD.

The project I'm working on makes use of code generation on field properties and we annotate the fields with their dynamo information directly. I'd rather not have to hand write the getters with their annotation separate to the field definition, breaking our code generation.

Having a look at the code for SDK V1 it seems like this could be relatively straight forward (albeit with extra reflection) by checking in shouldEncryptAttribute

StandardAnnotationMaps.of(mapping.getter(), null)
            .actualOf(DoNotEncrypt.class) != null;

on the mapping.

Adding some notion of DynamoDB key to the KMS encryption context

I was poking around the DirectKmsMaterialProvider and although I had assumed that the table and key (in the DynamoDB sense) ended up in the KMS encryption context somehow, it doesn't appear to. Would that be possible? Are there downsides to adding it? It would make KMS logs much more useful, since we could tell from KMS logs which table entries were being decrypted by whom.

API review notes for SDK2

  • Double check the granularity of DynamoDbEncryptionException.
  • Consider adding builders to the material providers for consistency.

Throttling exception when using the DirectKmsMaterialProvider

Hi,

I am using to DirectKmsMaterialProvider and I sometimes get the following exception when my application has high traffic.

java.util.concurrent.ExecutionException: com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMappingException: com.amazonaws.AmazonServiceException: You have exceeded the rate at which you may call KMS. Reduce the frequency of your calls. (Service: AWSKMS; Status Code: 400; Error Code: ThrottlingException; Request ID: 4d15a2da-441a-11e5-8a71-8d9f87588b5d)

I know I can ask AWS support to increase the KMS request limit on my account, but I think this is not a viable long term solution.

Is there anything that can be done to reduce the number of calls to KMS ? By batching the decrypt request maybe ?

Thank you,
Jonathan

Question: will decrypting still work after KMS keys are rotated.

We'd like to use the automatic key rotation on the KMS keys that are used to encrypt data in out Dynamo tables: https://docs.aws.amazon.com/kms/latest/developerguide/rotate-keys.html#rotate-keys-how-it-works. We've tested that the data can be decrypted if a new KMS key is created and the key alias is pointing to it, however testing when the actual backing key is rotated is not possible since AWS rotates the keys 365 days after the rotation is enabled. Can you please provide the details on how decrypting the data that was saved with the old backing key will work?

Maven Artifact Not Found

Getting this after adding dependency as specified.

"The POM for com.amazonaws:aws-dynamodb-encryption-java:jar:0.0.3-SNAPSHOT is missing, no dependency information available"

Are you sure you uploaded to Maven central repo?

A search by group and artifiact at search.maven.org yields nothing.

Record creation date in Metastore

To make time-based rotation logic easier, add a creation timestamp in Metastore. Ensure that backwards compatibility is maintained. See about building time-based rotation into request logic so consumers get it automatically.

Support for Global Tables

Is there a strategy for using the client-side encryption provided by this library with items that have been replicated to other regions using Global Tables and AWS KMS originated CMKs?

ValidationException: Type mismatch for attribute to update

Hi, I am trying to implement clientside encryption using aws-dynamodb-encryption-java. Saving a document works when I do not specify any @DynamoDBIndexHashKey's. Once I specify the IndexHashKey and IndexRangeKey, I keep getting this exception:
Where am I going wrong? Is there a problem with encrypting globalIndex hash+range key?
Any help is greatly appreciated.

com.amazonaws.services.dynamodbv2.model.AmazonDynamoDBException: Type mismatch for attribute to update (Service: AmazonDynamoDBv2; Status Code: 400; Error Code: ValidationException; Request ID: 770b5f75-860e-4823-8095-737d515db509)
    at com.amazonaws.http.AmazonHttpClient$RequestExecutor.handleErrorResponse(AmazonHttpClient.java:1530)
    at com.amazonaws.http.AmazonHttpClient$RequestExecutor.executeOneRequest(AmazonHttpClient.java:1168)
    at com.amazonaws.http.AmazonHttpClient$RequestExecutor.executeHelper(AmazonHttpClient.java:949)
    at com.amazonaws.http.AmazonHttpClient$RequestExecutor.doExecute(AmazonHttpClient.java:662)
    at com.amazonaws.http.AmazonHttpClient$RequestExecutor.executeWithTimer(AmazonHttpClient.java:636)
    at com.amazonaws.http.AmazonHttpClient$RequestExecutor.execute(AmazonHttpClient.java:619)
    at com.amazonaws.http.AmazonHttpClient$RequestExecutor.access$300(AmazonHttpClient.java:587)
    at com.amazonaws.http.AmazonHttpClient$RequestExecutionBuilderImpl.execute(AmazonHttpClient.java:574)
    at com.amazonaws.http.AmazonHttpClient.execute(AmazonHttpClient.java:446)
    at com.amazonaws.services.dynamodbv2.AmazonDynamoDBClient.doInvoke(AmazonDynamoDBClient.java:1723)
    at com.amazonaws.services.dynamodbv2.AmazonDynamoDBClient.invoke(AmazonDynamoDBClient.java:1699)
    at com.amazonaws.services.dynamodbv2.AmazonDynamoDBClient.putItem(AmazonDynamoDBClient.java:1317)
    at com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper$SaveObjectHandler.doPutItem(DynamoDBMapper.java:882)
    at com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper$1.executeLowLevelRequest(DynamoDBMapper.java:535)
    at com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper$SaveObjectHandler.execute(DynamoDBMapper.java:732)
    at com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper.save(DynamoDBMapper.java:622)
    at com.amazonaws.services.dynamodbv2.datamodeling.AbstractDynamoDBMapper.save(AbstractDynamoDBMapper.java:123)
    at mycode.dynamodb.DynamoDBClientSideEncryption.testEncryption(DynamoDBClientSideEncryption.java:100)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:678)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)


Here is my Book Object

package mycode.dynamodb;

import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBAutoGeneratedKey;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBHashKey;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBIndexHashKey;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBIndexRangeKey;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBTable;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBVersionAttribute;
import com.amazonaws.services.dynamodbv2.datamodeling.encryption.DoNotEncrypt;

@DynamoDBTable(tableName = "test_Books")
public class Book {
    public String id;   
    public void setId(String id) {
        this.id = id;
    }   
    @DynamoDBHashKey
    @DynamoDBAutoGeneratedKey
    public String getId() {
        return id;
    }

    public String title;    
    public void setTitle(String title) {
        this.title = title;
    }   
    @DynamoDBIndexHashKey(globalSecondaryIndexName = "titleIndex")
    public String getTitle() {
        return title;
    }

    public long createdAt;  
    public void setCreatedAt(long date) {
        this.createdAt = date;
    }   
    @DynamoDBIndexRangeKey(globalSecondaryIndexName = "titleIndex") 
    public long getCreatedAt() {
        return createdAt;
    }

    @Override
    public String toString() {
        return "Book [id=" + id + ", title=" + title + ", createdAt=" + createdAt + "]";
    }   

    Long version;   
    @DoNotEncrypt
    @DynamoDBVersionAttribute
    public Long getVersion() {
        return version;
    }   
    public void setVersion(Long version) {
        this.version = version;
    }

}

Here is my test class saving book to DB using client side encryption.

package mycode.dynamodb;

import java.util.Date;
import java.util.List;
import org.apache.commons.lang3.StringUtils;
import org.junit.Before;
import org.junit.Test;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDB;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClient;
import com.amazonaws.services.dynamodbv2.datamodeling.AttributeEncryptor;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapperConfig;
import com.amazonaws.services.dynamodbv2.datamodeling.encryption.DynamoDBEncryptor;
import com.amazonaws.services.dynamodbv2.datamodeling.encryption.providers.DirectKmsMaterialProvider;
import com.amazonaws.services.dynamodbv2.model.CreateTableRequest;
import com.amazonaws.services.dynamodbv2.model.GlobalSecondaryIndex;
import com.amazonaws.services.dynamodbv2.model.ProvisionedThroughput;
import com.amazonaws.services.dynamodbv2.util.TableUtils;
import com.amazonaws.services.dynamodbv2.util.TableUtils.TableNeverTransitionedToStateException;
import com.amazonaws.services.kms.AWSKMS;
import com.amazonaws.services.kms.AWSKMSClient;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class DynamoDBClientSideEncryption {
    private static final AmazonDynamoDB amazonDynamoDB;
    private static final DynamoDBMapper dynamoDBMapper;
    final static AWSKMS kms = new AWSKMSClient();
    // Set up the aws-dynamodb-encryption-java library
    final static DynamoDBEncryptor cryptor =
            DynamoDBEncryptor.getInstance(new DirectKmsMaterialProvider(kms, "alias/myalias"));

    static {
        amazonDynamoDB = new AmazonDynamoDBClient(
                new BasicAWSCredentials(System.getenv("amazon.aws.accesskey"), System.getenv("amazon.aws.secretkey")));
        final String endpoint = System.getenv("amazon.dynamodb.endpoint");
        if (StringUtils.isNotEmpty(endpoint)) {
            amazonDynamoDB.setEndpoint(endpoint);
        }
        dynamoDBMapper = new DynamoDBMapper(amazonDynamoDB, DynamoDBMapperConfig.DEFAULT, new AttributeEncryptor(cryptor));
        log.info("Connected to DynamoDB at " + endpoint);
    }

    @Before
    public void setUp() {
        Long readCapacityUnits = 10L;
        Long writeCapacityUnits = 10L;
        final ProvisionedThroughput provisionedThroughput =
                new ProvisionedThroughput(readCapacityUnits, writeCapacityUnits);
        CreateTableRequest pcTableRequest = dynamoDBMapper.generateCreateTableRequest(Book.class);
        pcTableRequest.setProvisionedThroughput(provisionedThroughput);
        List<GlobalSecondaryIndex> globalSecondaryIndexes = pcTableRequest.getGlobalSecondaryIndexes();
        if (globalSecondaryIndexes != null) {
            for (GlobalSecondaryIndex globalSecondaryIndex : globalSecondaryIndexes) {
                globalSecondaryIndex.setProvisionedThroughput(provisionedThroughput);
            }
        }
        boolean created = TableUtils.createTableIfNotExists(amazonDynamoDB, pcTableRequest);
        if (created) {
            try {
                TableUtils.waitUntilActive(amazonDynamoDB, Book.class.getSimpleName());
            }
            catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    @Test
    public void testEncryption() {
        Book book = new Book();
        book.setTitle("Title8");
        book.setCreatedAt(new Date().getTime());
        dynamoDBMapper.save(book, new DynamoDBMapperConfig(DynamoDBMapperConfig.SaveBehavior.CLOBBER));
    }
}

Enable Encryption and/or Signing Only when Annotated [Feature Request]

Currently the library encrypts and signs every field in all entities by default unless @DoNotEncrypt or @DoNotTouch are applied to fields or types.

The feedback I'd like to provide is that most all projects that I've been a part of aren't willing to accept the overhead of client-side encryption on every field and table. It's usually just a few sensitive fields, where the overhead is justified (or required from a regulatory standpoint). Imagine a project with 50 tables where only one requires client-side encryption. With the current default users need to annotate 49 entities with @DoNotTouch and leave one table without any annotations - the one where we do want to encrypt attributes.

This feature request is to add a way to change the default to not do anything unless one of the following new annotations are found on the entity or field: @Encrypt or @EncryptAndSign.

AWS jar version

Hello,

When I update my pom with your dependency (aws-dynamodb-encryption-java 1.11.0) I am getting an old jar for the aws core jar. Specifically, I am getting this version: aws-java-sdk-core-1.11.15.jar, instead of the 1.11.315 you mentioned. There is something going wrong on my side? Do you have any suggestion?

Thanks in advance,
Tiago Oliveira

Automatically Ignore Global Table state fields [Feature Request]

If the Global Table feature is enabled, AWS automatically adds the following fields to each item: aws:rep:updatetime, aws:rep:updateregion and aws:rep:deleting. According to two AWS support techs we need to manually instruct this library to ignore these fields in the encryption and signing operations.

For those using the AWS Java ObjectMapper, this means mapping these three fields in our entities. Since the replication code that AWS uses to implement the actual replication manages the state of these fields, I'm concerned that dangerous consequences could occur in situations like the following: Someone's application logic reads the entity - including the three fields, then writes the same values back 100ms later, but between these operations, the replication code updates the fields, so the net effect would be to revert the state that the replication code back to it's original state. Concurrent updates aren't limited to the replication code, but also concurrent application requests.

As such it seams only logical that no application code (or the ObjectMapper) should ever read or write any of these three fields, as such it seams that mapping these fields shouldn't be allowed. So if it's actually required by this library, I'd like to request a feature to automatically (or manually flip a flag) to ignore these three fields.

Support Automatic Key Rotation via the Metastore

This depends on #23

We should allow automatic rotation to be configured in the MetaStore such that an attempt to use an overly old key automatically (and silently) triggers creation of a new key. This will maintain the invariant that "No data is encrypted with a key older than $ROTATION_TIME." while not causing needless rotations when no encryption is occurring.

Expose metrics

Capture and report metrics through standard AWS SDK interfaces.

Re-enable Parallel Scan Integration Tests

There are two tests that are disabled in ScanITCase, which work on regular DynamoDB, but sometimes fail on DynamoDBLocal.

We should figure out why they break between regular DynamoDB and DynamoDBLocal. If they can't run on DynamoDBLocal, they should run on regular DynamoDB in a separate test group from travis.

Document how to run examples

This command works for running examples, assuming that the target class has already been compiled.

mvn exec:java -Dexec.mainClass="com.amazonaws.examples.TheExample" -Dexec.arguments="arg1","arg2,"arg3" -Dexec.cleanupDaemonThreads=false -q

A wrapper around this command should be provided to run examples, and how to do it should be documented. The wrapper should depend on a compilation step for the examples.

MostRecentProvider- keystore Version Increment

Hi,
When using MostRecentProvider, when does the materialname version change? Is it always 0?
When dubugging the code, i wasn't able to produce a scenario where the material name version is incremented. What am I doing wrong?

Allow choice of algorithm rather than hard-coding CBC mode

Was annoyed to find that CBC mode encryption is hard-coded in the code in the DynamoDBEncryptor class

private static final String SYMMETRIC_ENCRYPTION_MODE = "/CBC/PKCS5Padding";

This gets appended automatically to the algorithm set in the SecretKey object.

What would be nice is if you find that the algorithm !"AES".equals(encryptionKey.getAlgorithm()), then defer to whatever was set there, e.g. "AES/GCM/NoPadding"

Would then love to see GCM mode properly supported if that's detected.

Or provide a way to override the relevant portions of the initialization to support additional cipher modes.

Replace Base64 Implementation with Java 8's

Today, the library depends on AWS SDK 1's Base64 implementation, which shells out to JAXB. This makes it slow on versions Java 9 or greater.

Replace the current encoder with Java 8's Base64 Encoder, and add compatibility tests.

Scans/queries with projections are not supported

Hi there,
Using this library I have realised, please correct me if I am wrong, that projections are not supported.

How-to Reproduce it
How to reproduce the issue:

/*
YourModelClass has fields:
- hashKey (@DoNotTouch)
- attributeA (@DoNotTouch)
- attributeB 
*/
String PROJECTION = "hashKey, attributeA";
DynamoDBMapper mapper = ...
PaginatedScanList<ConfigurationEntry> paginatedScanList = mapper.scan(
                YourModelClass.class,
                new DynamoDBScanExpression().
                        withProjectionExpression(PROJECTION),
                mapperConfig
        );

Analysis
The scan above fails because:

  • the special attribute named *amzn-ddb-map-desc* is not part of the projection hence is not loaded
  • DynamoDBEncryptor.decryptRecord(...) produces an empty materialDescription (line 238 evaluates to false)
  • DirectKmsMaterialProvider.getDecryptionMaterials(...) throws NPE (line 121) because it tries to wrap a null reference:
ByteBuffer.wrap(Base64.decode(materialDescription.get(ENVELOPE_KEY)))

Workarounds? Hacks?
As a hack I've tried to add those special amz... attributes in my projection, but it fails because those are "reserved" attributes, so there is no way apparently on my side to work around the issue.

I'm not even sure if you can do anything, since the encryption/decryption only happens, respectively, before the standard Dynamo client puts the data to Dynamo, after the data has been loaded from Dynamo.

If only those attributes were not using reserved names though... Would it be a security risk to "expose" them to the end-user for cases like this? After all the key is already secured in KMS or similar.
If the concern then is that an attacker might compromise those attributes well, if the attacker is already there it might as well be able to compromise the items anyway, am I right?

AWS SDK for Java 2.0 compatibility

Problem

The AWS SDK for Java 2.0 will involve a significant change in that library's API and namespaces. We need to determine the right approach to ensuring compatibility with both the 1.0 and 2.0 libraries without incurring too many issues with code duplication.`

Scan query on encrypted column values not working.

I am using this library for Client side encryption for some of the columns in table.
When I query(DynamoDBScanExpression) on encrypted columns it returning me empty result but If I query on non encrypted columns it returns expected result.

Is this the limitation of the library? Or I am doing something wrong.

Create a stable release

We've been using aws-dynamodb-encryption in production for a while now and we'd like to know what's stopping you from releasing a non-snapshot release?

Thanks!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.