From 0b9164a067e72f5260d2480cd486371a804414fb Mon Sep 17 00:00:00 2001 From: Austin Moore Date: Thu, 21 Jul 2016 11:18:29 -0400 Subject: [PATCH 1/6] Add KmsMasterKeyProviderBuilder --- .../kms/KmsMasterKeyProvider.java | 9 +- .../kms/KmsMasterKeyProviderBuilder.java | 128 ++++++++++++++++++ 2 files changed, 135 insertions(+), 2 deletions(-) create mode 100644 src/main/java/com/amazonaws/encryptionsdk/kms/KmsMasterKeyProviderBuilder.java diff --git a/src/main/java/com/amazonaws/encryptionsdk/kms/KmsMasterKeyProvider.java b/src/main/java/com/amazonaws/encryptionsdk/kms/KmsMasterKeyProvider.java index 1abb0a1e8..38cb33ecc 100644 --- a/src/main/java/com/amazonaws/encryptionsdk/kms/KmsMasterKeyProvider.java +++ b/src/main/java/com/amazonaws/encryptionsdk/kms/KmsMasterKeyProvider.java @@ -131,7 +131,12 @@ public KmsMasterKeyProvider(final AWSKMS kms, final Region region, final List(keyIds); } @@ -244,7 +249,7 @@ public Region getRegion() { return region_; } - private static Region getStartingRegion(final String keyArn) { + static Region getStartingRegion(final String keyArn) { final String region = parseRegionfromKeyArn(keyArn); if (region != null) { return Region.getRegion(Regions.fromName(region)); diff --git a/src/main/java/com/amazonaws/encryptionsdk/kms/KmsMasterKeyProviderBuilder.java b/src/main/java/com/amazonaws/encryptionsdk/kms/KmsMasterKeyProviderBuilder.java new file mode 100644 index 000000000..f2f044aec --- /dev/null +++ b/src/main/java/com/amazonaws/encryptionsdk/kms/KmsMasterKeyProviderBuilder.java @@ -0,0 +1,128 @@ +package com.amazonaws.encryptionsdk.kms; + +import com.amazonaws.ClientConfiguration; +import com.amazonaws.auth.AWSCredentialsProvider; +import com.amazonaws.regions.Region; +import com.amazonaws.regions.RegionUtils; +import com.amazonaws.regions.Regions; +import com.amazonaws.services.kms.AWSKMSClient; +import com.amazonaws.services.kms.AWSKMSClientBuilder; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * Used to build a {@link KmsMasterKeyProvider} using {@link AWSKMSClientBuilder}, which will use provider chains to get + * defaults if the properties are not explicitly set. + * + * Default usage will use all the defaults found by AWSKMSClientBuilder. If a region is not found in the configuration + * chain, then {@link Regions#DEFAULT_REGION} is used. + *
+ *     KmsMasterKeyProvider keyProvider = KmsMasterKeyProviderBuilder.defaultProvider();
+ * 
+ * + * Example, specifying a region: + *
+ *     KmsMasterKeyProvider keyProvider = KmsMasterKeyProviderBuilder.standard()
+ *       .withRegion("us-east-1")
+ *       .build();
+ * 
+ */ +public class KmsMasterKeyProviderBuilder { + + private AWSKMSClientBuilder clientBuilder; + private List keyIds; + + /** + * @return a new {@link KmsMasterKeyProviderBuilder} with the defaults set. + */ + public static KmsMasterKeyProviderBuilder standard() { + return new KmsMasterKeyProviderBuilder(); + } + + /** + * @return a KmsMasterKeyProvider using the {@link AWSKMSClientBuilder} defaults, and an empty key ID list. + */ + public static KmsMasterKeyProvider defaultProvider() { + return standard().build(); + } + + private KmsMasterKeyProviderBuilder() { + clientBuilder = AWSKMSClientBuilder.standard(); + } + + /** + * Sets the region to be used by the client. Overrides any previously set region. + */ + public KmsMasterKeyProviderBuilder withRegion(Region region) { + return withRegion(region.getName()); + } + + /** + * Sets the region to be used by the client. Overrides any previously set region. + */ + public KmsMasterKeyProviderBuilder withRegion(String regionName) { + clientBuilder.withRegion(regionName); + return this; + } + + /** + * Sets the client configuration to use. + */ + public KmsMasterKeyProviderBuilder withClientConfiguration(ClientConfiguration clientConfiguration) { + clientBuilder.withClientConfiguration(clientConfiguration); + return this; + } + + /** + * Sets the credentials to use. + */ + public KmsMasterKeyProviderBuilder withCredentials(AWSCredentialsProvider credentialsProvider) { + clientBuilder.withCredentials(credentialsProvider); + return this; + } + + /** + * Sets the region using a keyId. This will override any previously set regions. + */ + public KmsMasterKeyProviderBuilder withKeyId(String keyId) { + withKeyIds(Collections.singletonList(keyId)); + + withRegion(KmsMasterKeyProvider.getStartingRegion(keyId)); + + return this; + } + + /** + * Adds {@code keyIds}, but does not use them to set the region. + */ + public KmsMasterKeyProviderBuilder withKeyIds(List keyIds) { + if (this.keyIds == null) { + this.keyIds = new ArrayList<>(); + } + + this.keyIds.addAll(keyIds); + + return this; + } + + /** + * Builds the {@link KmsMasterKeyProvider} using the information it was built with or {@link AWSKMSClientBuilder}'s + * defaults. + */ + public KmsMasterKeyProvider build() { + keyIds = (keyIds == null) ? Collections.emptyList() : keyIds; + + String clientBuilderRegion = clientBuilder.getRegion(); + + String regionName = (clientBuilderRegion == null) ? Regions.DEFAULT_REGION.getName() + : clientBuilderRegion; + + clientBuilder = clientBuilder.withRegion(regionName); + + return new KmsMasterKeyProvider((AWSKMSClient) clientBuilder.build(), + RegionUtils.getRegion(regionName), + keyIds); + } +} From 4a3ae70caf1d74188da5399549f4c728da2d0e8f Mon Sep 17 00:00:00 2001 From: Austin Moore Date: Thu, 21 Jul 2016 11:19:00 -0400 Subject: [PATCH 2/6] Add example using KmsMasterKeyProviderBuilder --- .../crypto/examples/BuilderExample.java | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 src/examples/java/com/amazonaws/crypto/examples/BuilderExample.java diff --git a/src/examples/java/com/amazonaws/crypto/examples/BuilderExample.java b/src/examples/java/com/amazonaws/crypto/examples/BuilderExample.java new file mode 100644 index 000000000..ea9d3ac70 --- /dev/null +++ b/src/examples/java/com/amazonaws/crypto/examples/BuilderExample.java @@ -0,0 +1,71 @@ +package com.amazonaws.crypto.examples; + +import com.amazonaws.encryptionsdk.AwsCrypto; +import com.amazonaws.encryptionsdk.CryptoResult; +import com.amazonaws.encryptionsdk.kms.KmsMasterKey; +import com.amazonaws.encryptionsdk.kms.KmsMasterKeyProvider; +import com.amazonaws.encryptionsdk.kms.KmsMasterKeyProviderBuilder; + +import java.util.Collections; +import java.util.Map; + +/** + *

+ * Encrypts and then decrypts a string under a KMS key + * + *

+ * Arguments: + *

    + *
  1. KMS Key Arn + *
  2. String to encrypt + *
+ */ +public class BuilderExample { + + private static String keyArn; + private static String data; + + public static void main(final String[] args) { + keyArn = args[0]; + data = args[1]; + + // Instantiate the SDK + final AwsCrypto crypto = new AwsCrypto(); + + // Set up the KmsMasterKeyProvider using the defaults provided by the KmsMasterKeyProviderBuilder + final KmsMasterKeyProvider prov = KmsMasterKeyProviderBuilder.standard() + .withKeyId(keyArn) + .build(); + + // Encrypt the data + // + // Most encrypted data should have associated encryption context + // to protect integrity. Here, we'll just use a placeholder value. + // + // For more information see: + // blogs.aws.amazon.com/security/post/Tx2LZ6WBJJANTNW/How-to-Protect-the-Integrity-of-Your-Encrypted-Data-by-Using-AWS-Key-Management + final Map context = Collections.singletonMap("Example", "String"); + + final String ciphertext = crypto.encryptString(prov, data, context).getResult(); + System.out.println("Ciphertext: " + ciphertext); + + // Decrypt the data + final CryptoResult decryptResult = crypto.decryptString(prov, ciphertext); + // We need to check the encryption context (and ideally key) to ensure that + // this was the ciphertext we expected + if (!decryptResult.getMasterKeyIds().get(0).equals(keyArn)) { + throw new IllegalStateException("Wrong key id!"); + } + + // The SDK may add information to the encryption context, so we check to ensure + // that all of our values are present + for (final Map.Entry e : context.entrySet()) { + if (!e.getValue().equals(decryptResult.getEncryptionContext().get(e.getKey()))) { + throw new IllegalStateException("Wrong Encryption Context!"); + } + } + + // Now that we know we have the correct data, we can output it. + System.out.println("Decrypted: " + decryptResult.getResult()); + } +} From 801cab5dff3c00eb235972c513b996b6e69430fa Mon Sep 17 00:00:00 2001 From: Austin Moore Date: Thu, 21 Jul 2016 11:36:26 -0400 Subject: [PATCH 3/6] Add a warning to some setters that they may not work if created with the builder --- .../com/amazonaws/encryptionsdk/kms/KmsMasterKeyProvider.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/com/amazonaws/encryptionsdk/kms/KmsMasterKeyProvider.java b/src/main/java/com/amazonaws/encryptionsdk/kms/KmsMasterKeyProvider.java index 38cb33ecc..632f5d478 100644 --- a/src/main/java/com/amazonaws/encryptionsdk/kms/KmsMasterKeyProvider.java +++ b/src/main/java/com/amazonaws/encryptionsdk/kms/KmsMasterKeyProvider.java @@ -220,6 +220,8 @@ public void addGrantToken(final String grantToken) { * Configures this provider to use a custom endpoint. Sets the underlying {@link Region} object * to {@code null}, and instructs the internal KMS client to use the specified {@code endPoint} * and {@code regionName}. + * + * Note: This method will not work if this object was created by {@link KmsMasterKeyProviderBuilder}. */ public void setCustomEndpoint(final String regionName, final String endPoint) { if (kms_ instanceof AWSKMSClient) { @@ -236,6 +238,8 @@ public void setCustomEndpoint(final String regionName, final String endPoint) { * Set the AWS region of the AWS KMS service for access to the master key. This method simply * calls the same method of the underlying {@link AWSKMSClient} * + * Note: This method will not work if this object was created by {@link KmsMasterKeyProviderBuilder}. + * * @param region * string containing the region. */ From d58e32c54c1d7d740b45322143daae2674be468f Mon Sep 17 00:00:00 2001 From: Austin Moore Date: Thu, 21 Jul 2016 17:42:34 -0400 Subject: [PATCH 4/6] Extend KmsMasterKeyProviderBuilder from AwsClientBuilder --- .../kms/KmsMasterKeyProviderBuilder.java | 81 +++++++++---------- 1 file changed, 39 insertions(+), 42 deletions(-) diff --git a/src/main/java/com/amazonaws/encryptionsdk/kms/KmsMasterKeyProviderBuilder.java b/src/main/java/com/amazonaws/encryptionsdk/kms/KmsMasterKeyProviderBuilder.java index f2f044aec..6fba23b79 100644 --- a/src/main/java/com/amazonaws/encryptionsdk/kms/KmsMasterKeyProviderBuilder.java +++ b/src/main/java/com/amazonaws/encryptionsdk/kms/KmsMasterKeyProviderBuilder.java @@ -1,7 +1,10 @@ package com.amazonaws.encryptionsdk.kms; -import com.amazonaws.ClientConfiguration; -import com.amazonaws.auth.AWSCredentialsProvider; +import com.amazonaws.ClientConfigurationFactory; +import com.amazonaws.client.AwsSyncClientParams; +import com.amazonaws.client.builder.AwsClientBuilder; +import com.amazonaws.regions.AwsRegionProvider; +import com.amazonaws.regions.DefaultAwsRegionProviderChain; import com.amazonaws.regions.Region; import com.amazonaws.regions.RegionUtils; import com.amazonaws.regions.Regions; @@ -13,11 +16,10 @@ import java.util.List; /** - * Used to build a {@link KmsMasterKeyProvider} using {@link AWSKMSClientBuilder}, which will use provider chains to get - * defaults if the properties are not explicitly set. + * Used to build a {@link KmsMasterKeyProvider} which will use the defaults found in the relevant provider chains. * - * Default usage will use all the defaults found by AWSKMSClientBuilder. If a region is not found in the configuration - * chain, then {@link Regions#DEFAULT_REGION} is used. + * If a region is not defined and no region can be found in the region provider chain, then + * {@link Regions#DEFAULT_REGION} is used. *
  *     KmsMasterKeyProvider keyProvider = KmsMasterKeyProviderBuilder.defaultProvider();
  * 
@@ -29,9 +31,8 @@ * .build(); * */ -public class KmsMasterKeyProviderBuilder { +public class KmsMasterKeyProviderBuilder extends AwsClientBuilder { - private AWSKMSClientBuilder clientBuilder; private List keyIds; /** @@ -49,7 +50,7 @@ public static KmsMasterKeyProvider defaultProvider() { } private KmsMasterKeyProviderBuilder() { - clientBuilder = AWSKMSClientBuilder.standard(); + super(new ClientConfigurationFactory()); } /** @@ -59,30 +60,6 @@ public KmsMasterKeyProviderBuilder withRegion(Region region) { return withRegion(region.getName()); } - /** - * Sets the region to be used by the client. Overrides any previously set region. - */ - public KmsMasterKeyProviderBuilder withRegion(String regionName) { - clientBuilder.withRegion(regionName); - return this; - } - - /** - * Sets the client configuration to use. - */ - public KmsMasterKeyProviderBuilder withClientConfiguration(ClientConfiguration clientConfiguration) { - clientBuilder.withClientConfiguration(clientConfiguration); - return this; - } - - /** - * Sets the credentials to use. - */ - public KmsMasterKeyProviderBuilder withCredentials(AWSCredentialsProvider credentialsProvider) { - clientBuilder.withCredentials(credentialsProvider); - return this; - } - /** * Sets the region using a keyId. This will override any previously set regions. */ @@ -108,21 +85,41 @@ public KmsMasterKeyProviderBuilder withKeyIds(List keyIds) { } /** - * Builds the {@link KmsMasterKeyProvider} using the information it was built with or {@link AWSKMSClientBuilder}'s - * defaults. + * Builds a {@link KmsMasterKeyProvider} using the information it was built with, or with defaults where necessary. */ + @Override public KmsMasterKeyProvider build() { - keyIds = (keyIds == null) ? Collections.emptyList() : keyIds; + return build(getSyncClientParams()); + } - String clientBuilderRegion = clientBuilder.getRegion(); + private KmsMasterKeyProvider build(AwsSyncClientParams clientParams) { + keyIds = (keyIds == null) ? Collections.emptyList() : keyIds; - String regionName = (clientBuilderRegion == null) ? Regions.DEFAULT_REGION.getName() - : clientBuilderRegion; + AWSKMSClient client = new AWSKMSClient(clientParams.getCredentialsProvider(), + clientParams.getClientConfiguration(), + clientParams.getRequestMetricCollector()); - clientBuilder = clientBuilder.withRegion(regionName); + Region region = determineRegion(); - return new KmsMasterKeyProvider((AWSKMSClient) clientBuilder.build(), - RegionUtils.getRegion(regionName), + return new KmsMasterKeyProvider(client, + region, keyIds); } + + private Region determineRegion() { + Region region = RegionUtils.getRegion(this.getRegion()); + + final AwsRegionProvider regionProvider = new DefaultAwsRegionProviderChain(); + + if (region != null) { + return region; + } else { + final String regionName = regionProvider.getRegion(); + if (regionName != null) { + return Region.getRegion(Regions.fromName(regionName)); + } else { + return Region.getRegion(Regions.DEFAULT_REGION); + } + } + } } From bebe70de58632f2c87f373dc9f8fc3eb3eab6fba Mon Sep 17 00:00:00 2001 From: Austin Moore Date: Wed, 20 Sep 2017 17:31:44 -0400 Subject: [PATCH 5/6] Add a static builder method on KmsMasterKeyProvider --- .../com/amazonaws/encryptionsdk/kms/KmsMasterKeyProvider.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/com/amazonaws/encryptionsdk/kms/KmsMasterKeyProvider.java b/src/main/java/com/amazonaws/encryptionsdk/kms/KmsMasterKeyProvider.java index 632f5d478..974eba91d 100644 --- a/src/main/java/com/amazonaws/encryptionsdk/kms/KmsMasterKeyProvider.java +++ b/src/main/java/com/amazonaws/encryptionsdk/kms/KmsMasterKeyProvider.java @@ -140,6 +140,10 @@ public KmsMasterKeyProvider(final AWSKMS kms, final Region region, final List(keyIds); } + public static KmsMasterKeyProviderBuilder builder() { + return KmsMasterKeyProviderBuilder.standard(); + } + /** * Returns "aws-kms" */ From 40f8624fd73aaaa7365678a4b14507186cf57ca4 Mon Sep 17 00:00:00 2001 From: Austin Moore Date: Wed, 20 Sep 2017 17:40:36 -0400 Subject: [PATCH 6/6] Change withRegion to withDefaultRegion --- .../encryptionsdk/kms/KmsMasterKeyProviderBuilder.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/amazonaws/encryptionsdk/kms/KmsMasterKeyProviderBuilder.java b/src/main/java/com/amazonaws/encryptionsdk/kms/KmsMasterKeyProviderBuilder.java index 6fba23b79..b6e16ad1f 100644 --- a/src/main/java/com/amazonaws/encryptionsdk/kms/KmsMasterKeyProviderBuilder.java +++ b/src/main/java/com/amazonaws/encryptionsdk/kms/KmsMasterKeyProviderBuilder.java @@ -27,7 +27,7 @@ * Example, specifying a region: *
  *     KmsMasterKeyProvider keyProvider = KmsMasterKeyProviderBuilder.standard()
- *       .withRegion("us-east-1")
+ *       .withDefaultRegion("us-east-1")
  *       .build();
  * 
*/ @@ -54,9 +54,9 @@ private KmsMasterKeyProviderBuilder() { } /** - * Sets the region to be used by the client. Overrides any previously set region. + * Sets the default region to be used by the client. Overrides any previously set region. */ - public KmsMasterKeyProviderBuilder withRegion(Region region) { + public KmsMasterKeyProviderBuilder withDefaultRegion(Region region) { return withRegion(region.getName()); } @@ -66,7 +66,7 @@ public KmsMasterKeyProviderBuilder withRegion(Region region) { public KmsMasterKeyProviderBuilder withKeyId(String keyId) { withKeyIds(Collections.singletonList(keyId)); - withRegion(KmsMasterKeyProvider.getStartingRegion(keyId)); + withDefaultRegion(KmsMasterKeyProvider.getStartingRegion(keyId)); return this; }