Skip to content

Commit

Permalink
feat: Adds the CachingMostRecentProvider. Deprecates MostRecentProvider.
Browse files Browse the repository at this point in the history
Time-based key re-authorization logic in MostRecentProvider did not re-authorize the use of the key
after key usage permissions were changed at the key provider (for example AWS Key Management
Service). This created the potential for keys to be used in the DynamoDB Encryption Client after
permissions to do so were revoked.

The MostRecentProvider is deprecated. It is removed in 2.0.0. New deployments should use the
CachingMostRecentProvider, and existing deployments should upgrade as soon as possible. See
https://docs.aws.amazon.com/dynamodb-encryption-client/latest/devguide/most-recent-provider.html#mrp-versions
for more details.

This change also addresses interoperability issues between the Python and Java implementations of
the DynamoDB Encryption Client.
  • Loading branch information
lavaleri committed Feb 4, 2021
1 parent 14c6a95 commit 7de5f5a
Show file tree
Hide file tree
Showing 75 changed files with 11,773 additions and 2,809 deletions.
17 changes: 17 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,21 @@
# Changelog
## 1.15.0 -- 2021-02-04
Adds the CachingMostRecentProvider and deprecates MostRecentProvider.

Time-based key reauthorization logic in MostRecentProvider did not re-authorize the use of the key
after key usage permissions were changed at the key provider
(for example AWS Key Management Service).
This created the potential for keys to be used in the DynamoDB Encryption Client after permissions
to do so were revoked.

CachingMostRecentProvider replaces MostRecentProvider and provides a cache entry TTL to reauthorize
the key with the key provider.

MostRecentProvider is now deprecated, and is removed in 2.0.0.
See https://docs.aws.amazon.com/dynamodb-encryption-client/latest/devguide/most-recent-provider.html#mrp-versions for more details.

1.15.0 also fixes interoperability issues between the Python and Java implementations of DynamoDB Encryption Client.

## 1.14.1 -- 2019-10-14
Fixes `com.amazonaws:aws-dynamodb-encryption-java` so that it may be consumed
in mavenCentral.
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ You can download the [latest snapshot release][download] or pick it up from Mave
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-dynamodb-encryption-java</artifactId>
<version>1.14.1</version>
<version>1.15.0</version>
</dependency>
```

Expand Down Expand Up @@ -177,4 +177,4 @@ For signing, the user specified signing key can be either symmetric or asymmetri
[materialprovider]: sdk1/src/main/java/com/amazonaws/services/dynamodbv2/datamodeling/encryption/providers/EncryptionMaterialsProvider.java
[privatekey]: http://docs.oracle.com/javase/7/docs/api/java/security/PrivateKey.html
[secretkey]: http://docs.oracle.com/javase/7/docs/api/javax/crypto/SecretKey.html
[download]: https://github.com/aws/aws-dynamodb-encryption-java/releases/tag/1.13.0
[download]: https://github.com/aws/aws-dynamodb-encryption-java/releases
19 changes: 0 additions & 19 deletions common/pom.xml

This file was deleted.

39 changes: 0 additions & 39 deletions ddej-build-tools/pom.xml

This file was deleted.

136 changes: 132 additions & 4 deletions examples/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -8,24 +8,152 @@
<parent>
<groupId>software.amazon.cryptools</groupId>
<artifactId>dynamodbencryptionclient-pom</artifactId>
<version>0.1.0-SNAPSHOT</version>
<version>1.15.0</version>
</parent>

<artifactId>dynamodbencryptionclient-sdk1examples</artifactId>
<packaging>jar</packaging>
<version>0.1.0-SNAPSHOT</version>
<version>1.15.0</version>
<name>aws-dynamodb-encryption-java :: SDK1 Examples</name>
<description>Examples for AWS DynamoDB Encryption Client for AWS Java SDK v1</description>

<properties>
<sqlite4java.version>1.0.392</sqlite4java.version>
<maven-failsafe-plugin.version>3.0.0-M3</maven-failsafe-plugin.version>
<maven-surefire-plugin.version>3.0.0-M3</maven-surefire-plugin.version>
</properties>

<dependencies>
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-dynamodb-encryption-java</artifactId>
<version>1.13.0</version>
<version>1.15.0</version>
</dependency>

<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>6.10</version>
<scope>test</scope>
</dependency>

<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>DynamoDBLocal</artifactId>
<version>1.10.5.1</version>
<scope>test</scope>
</dependency>

<dependency>
<groupId>com.almworks.sqlite4java</groupId>
<artifactId>sqlite4java</artifactId>
<version>${sqlite4java.version}</version>
<scope>test</scope>
</dependency>

<dependency>
<groupId>com.almworks.sqlite4java</groupId>
<artifactId>libsqlite4java-osx</artifactId>
<version>${sqlite4java.version}</version>
<type>dylib</type>
<scope>test</scope>
</dependency>

<dependency>
<groupId>com.almworks.sqlite4java</groupId>
<artifactId>sqlite4java-win32-x64</artifactId>
<version>${sqlite4java.version}</version>
<type>dll</type>
<scope>test</scope>
</dependency>

<dependency>
<groupId>com.almworks.sqlite4java</groupId>
<artifactId>libsqlite4java-linux-amd64</artifactId>
<type>so</type>
<version>${sqlite4java.version}</version>
<scope>test</scope>
</dependency>
</dependencies>

<!--Custom repository:-->
<repositories>
<repository>
<id>dynamodb-local</id>
<name>DynamoDB Local Release Repository</name>
<url>https://s3-us-west-2.amazonaws.com/dynamodb-local/release</url>
</repository>
</repositories>

<build>
<sourceDirectory>.</sourceDirectory>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>3.1.1</version>
<executions>
<execution>
<id>copy</id>
<phase>test-compile</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<includeScope>test</includeScope>
<includeTypes>so,dll,dylib</includeTypes>
<outputDirectory>${project.build.directory}/test-lib</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>${maven-surefire-plugin.version}</version>
<configuration>
<useSystemClassLoader>false</useSystemClassLoader>
<systemProperties>
<property>
<name>sqlite4java.library.path</name>
<value>${project.build.directory}/test-lib</value>
</property>
</systemProperties>
</configuration>
</plugin>

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>${maven-failsafe-plugin.version}</version>
<configuration>
<useSystemClassLoader>false</useSystemClassLoader>
<systemProperties>
<property>
<name>sqlite4java.library.path</name>
<value>${project.build.directory}/test-lib</value>
</property>
</systemProperties>
</configuration>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
Expand Up @@ -34,29 +34,33 @@
* For ease of the example, we create new random ones every time.
*/
public class AsymmetricEncryptedItem {

private static final String STRING_FIELD_NAME = "example";
private static final String BINARY_FIELD_NAME = "and some binary";
private static final String NUMBER_FIELD_NAME = "some numbers";
private static final String IGNORED_FIELD_NAME = "leave me";

public static void main(String[] args) throws GeneralSecurityException {
final String tableName = args[0];
final KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
keyGen.initialize(2048);
// You should never use the same key for encryption and signing
final KeyPair wrappingKeys = keyGen.generateKeyPair();
final KeyPair signingKeys = keyGen.generateKeyPair();

encryptRecord(tableName, wrappingKeys, signingKeys);
}

private static void encryptRecord(String tableName, KeyPair wrappingKeys, KeyPair signingKeys) throws GeneralSecurityException {
public static void encryptRecord(String tableName, KeyPair wrappingKeys, KeyPair signingKeys) throws GeneralSecurityException {
// Sample record to be encrypted
final String partitionKeyName = "partition_attribute";
final String sortKeyName = "sort_attribute";
final Map<String, AttributeValue> record = new HashMap<>();
record.put(partitionKeyName, new AttributeValue().withS("is this"));
record.put(sortKeyName, new AttributeValue().withN("55"));
record.put("example", new AttributeValue().withS("data"));
record.put("some numbers", new AttributeValue().withN("99"));
record.put("and some binary", new AttributeValue().withB(ByteBuffer.wrap(new byte[]{0x00, 0x01, 0x02})));
record.put("leave me", new AttributeValue().withS("alone")); // We want to ignore this attribute
record.put(STRING_FIELD_NAME, new AttributeValue().withS("data"));
record.put(NUMBER_FIELD_NAME, new AttributeValue().withN("99"));
record.put(BINARY_FIELD_NAME, new AttributeValue().withB(ByteBuffer.wrap(new byte[]{0x00, 0x01, 0x02})));
record.put(IGNORED_FIELD_NAME, new AttributeValue().withS("alone")); // We want to ignore this attribute

// Set up our configuration and clients. All of this is thread-safe and can be reused across calls.
// Provider Configuration
Expand All @@ -82,7 +86,7 @@ private static void encryptRecord(String tableName, KeyPair wrappingKeys, KeyPai
// Partition and sort keys must not be encrypted but should be signed
actions.put(attributeName, signOnly);
break;
case "leave me":
case IGNORED_FIELD_NAME:
// For this example, we are neither signing nor encrypting this field
break;
default:
Expand All @@ -96,6 +100,12 @@ private static void encryptRecord(String tableName, KeyPair wrappingKeys, KeyPai
// Encrypt the plaintext record directly
final Map<String, AttributeValue> encrypted_record = encryptor.encryptRecord(record, actions, encryptionContext);

// Encrypted record fields change as expected
assert encrypted_record.get(STRING_FIELD_NAME).getB() != null; // the encrypted string is stored as bytes
assert encrypted_record.get(NUMBER_FIELD_NAME).getB() != null; // the encrypted number is stored as bytes
assert !record.get(BINARY_FIELD_NAME).getB().equals(encrypted_record.get(BINARY_FIELD_NAME).getB()); // the encrypted bytes have updated
assert record.get(IGNORED_FIELD_NAME).getS().equals(encrypted_record.get(IGNORED_FIELD_NAME).getS()); // ignored field is left as is

// We could now put the encrypted item to DynamoDB just as we would any other item.
// We're skipping it to to keep the example simpler.

Expand All @@ -105,5 +115,10 @@ private static void encryptRecord(String tableName, KeyPair wrappingKeys, KeyPai
// Decryption is identical. We'll pretend that we retrieved the record from DynamoDB.
final Map<String, AttributeValue> decrypted_record = encryptor.decryptRecord(encrypted_record, actions, encryptionContext);
System.out.println("Decrypted Record: " + decrypted_record);
}

// The decrypted fields match the original fields before encryption
assert record.get(STRING_FIELD_NAME).getS().equals(decrypted_record.get(STRING_FIELD_NAME).getS());
assert record.get(NUMBER_FIELD_NAME).getN().equals(decrypted_record.get(NUMBER_FIELD_NAME).getN());
assert record.get(BINARY_FIELD_NAME).getB().equals(decrypted_record.get(BINARY_FIELD_NAME).getB());
}
}
Loading

0 comments on commit 7de5f5a

Please sign in to comment.