Skip to content

Commit

Permalink
feat: AWS SDK v2 support
Browse files Browse the repository at this point in the history
  • Loading branch information
smswz authored Mar 7, 2022
1 parent 0ab1db0 commit 006cdc4
Show file tree
Hide file tree
Showing 39 changed files with 6,102 additions and 105 deletions.
21 changes: 20 additions & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,19 @@
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

<dependencyManagement>
<dependencies>
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>bom</artifactId>
<version>2.17.136</version>
<optional>true</optional>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>

<dependencies>
<dependency>
<groupId>com.amazonaws</groupId>
Expand All @@ -46,6 +59,13 @@
<optional>true</optional>
</dependency>

<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>kms</artifactId>
<version>2.17.136</version>
<optional>true</optional>
</dependency>

<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-ext-jdk15on</artifactId>
Expand Down Expand Up @@ -79,7 +99,6 @@
<scope>test</scope>
</dependency>


<dependency>
<groupId>com.google.code.findbugs</groupId>
<artifactId>jsr305</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@

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.kmssdkv2.KmsMasterKey;
import com.amazonaws.encryptionsdk.kmssdkv2.KmsMasterKeyProvider;
import com.amazonaws.encryptionsdk.CommitmentPolicy;

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
import com.amazonaws.encryptionsdk.AwsCrypto;
import com.amazonaws.encryptionsdk.CommitmentPolicy;
import com.amazonaws.encryptionsdk.CryptoResult;
import com.amazonaws.encryptionsdk.kms.AwsKmsMrkAwareMasterKey;
import com.amazonaws.encryptionsdk.kms.AwsKmsMrkAwareMasterKeyProvider;
import com.amazonaws.encryptionsdk.kmssdkv2.AwsKmsMrkAwareMasterKey;
import com.amazonaws.encryptionsdk.kmssdkv2.AwsKmsMrkAwareMasterKeyProvider;

import java.nio.charset.StandardCharsets;
import java.util.Arrays;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@

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.kmssdkv2.KmsMasterKey;
import com.amazonaws.encryptionsdk.kmssdkv2.KmsMasterKeyProvider;
import com.amazonaws.encryptionsdk.CommitmentPolicy;
import com.amazonaws.encryptionsdk.kms.DiscoveryFilter;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,14 @@
import com.amazonaws.encryptionsdk.CommitmentPolicy;
import com.amazonaws.encryptionsdk.CryptoResult;
import com.amazonaws.encryptionsdk.kms.DiscoveryFilter;
import com.amazonaws.encryptionsdk.kms.AwsKmsMrkAwareMasterKey;
import com.amazonaws.encryptionsdk.kms.AwsKmsMrkAwareMasterKeyProvider;
import com.amazonaws.encryptionsdk.kmssdkv2.AwsKmsMrkAwareMasterKey;
import com.amazonaws.encryptionsdk.kmssdkv2.AwsKmsMrkAwareMasterKeyProvider;

import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Collections;
import java.util.Map;
import software.amazon.awssdk.regions.Region;

/**
* <p>
Expand All @@ -39,7 +40,7 @@ public static void main(final String[] args) {
final String keyName = args[0];
final String partition = args[1];
final String accountId = args[2];
final String discoveryMrkRegion = args[3];
final Region discoveryMrkRegion = Region.of(args[3]);

encryptAndDecrypt(keyName, partition, accountId, discoveryMrkRegion);
}
Expand All @@ -48,7 +49,7 @@ static void encryptAndDecrypt(
final String keyName,
final String partition,
final String accountId,
final String discoveryMrkRegion
final Region discoveryMrkRegion
) {
// 1. Instantiate the SDK
// This builds the AwsCrypto client with
Expand Down Expand Up @@ -113,7 +114,7 @@ static void encryptAndDecrypt(
// it is limited to the Region configured for the AWS SDK.
final AwsKmsMrkAwareMasterKeyProvider decryptingKeyProvider = AwsKmsMrkAwareMasterKeyProvider
.builder()
.withDiscoveryMrkRegion(discoveryMrkRegion)
.discoveryMrkRegion(discoveryMrkRegion)
.buildDiscovery(discoveryFilter);

// 7. Decrypt the data
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
import com.amazonaws.encryptionsdk.CryptoOutputStream;
import com.amazonaws.encryptionsdk.MasterKeyProvider;
import com.amazonaws.encryptionsdk.jce.JceMasterKey;
import com.amazonaws.encryptionsdk.kms.KmsMasterKeyProvider;
import com.amazonaws.encryptionsdk.kmssdkv2.KmsMasterKeyProvider;
import com.amazonaws.encryptionsdk.multi.MultipleProviderFactory;
import com.amazonaws.encryptionsdk.CommitmentPolicy;
import com.amazonaws.util.IOUtils;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@

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.kmssdkv2.KmsMasterKey;
import com.amazonaws.encryptionsdk.kmssdkv2.KmsMasterKeyProvider;
import com.amazonaws.encryptionsdk.CommitmentPolicy;

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@
import com.amazonaws.encryptionsdk.AwsCrypto;
import com.amazonaws.encryptionsdk.CryptoResult;
import com.amazonaws.encryptionsdk.exception.AwsCryptoException;
import com.amazonaws.encryptionsdk.kms.KmsMasterKey;
import com.amazonaws.encryptionsdk.kms.KmsMasterKeyProvider;
import com.amazonaws.encryptionsdk.kmssdkv2.KmsMasterKey;
import com.amazonaws.encryptionsdk.kmssdkv2.KmsMasterKeyProvider;
import com.amazonaws.encryptionsdk.CommitmentPolicy;
import com.amazonaws.encryptionsdk.kms.DiscoveryFilter;
import com.amazonaws.services.kms.AWSKMSClientBuilder;
import com.amazonaws.services.kms.AWSKMS;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.kms.KmsClient;

/**
* <p>
Expand All @@ -43,12 +43,12 @@ public static void main(final String[] args) {
final String keyName = args[0];
final String partition = args[1];
final String accountId = args[2];
final String region = args[3];
final Region region = Region.of(args[3]);

encryptAndDecrypt(keyName, partition, accountId, region);
}

static void encryptAndDecrypt(final String keyName, final String partition, final String accountId, final String region) {
static void encryptAndDecrypt(final String keyName, final String partition, final String accountId, final Region region) {
// Instantiate the SDK.
// This builds the AwsCrypto client with the RequireEncryptRequireDecrypt commitment policy,
// which enforces that this client only encrypts using committing algorithm suites and enforces
Expand All @@ -60,7 +60,7 @@ static void encryptAndDecrypt(final String keyName, final String partition, fina
.build();

// 2. Instantiate the AWS KMS client for the desired region
final AWSKMS kmsClient = AWSKMSClientBuilder.standard().withRegion(region).build();
final KmsClient kmsClient = KmsClient.builder().region(region).build();

// 3. Instantiate an AWS KMS master key provider for encryption.
//
Expand Down Expand Up @@ -101,14 +101,14 @@ static void encryptAndDecrypt(final String keyName, final String partition, fina
// This example also configures the AWS KMS master key provider with a Discovery Filter to limit
// the attempted AWS KMS CMKs to a particular partition and account.
final KmsMasterKeyProvider decryptingKeyProvider = KmsMasterKeyProvider.builder()
.withCustomClientFactory(cmkRegion -> {
.customRegionalClientSupplier(cmkRegion -> {
if(cmkRegion.equals(region)) {
// return the previously built AWS KMS client so that we do
// not create a new client on every decrypt call.
return kmsClient;
}

throw new AwsCryptoException("Only " + region + " is supported");
throw new AwsCryptoException("Only " + region.id() + " is supported");
})
.buildDiscovery(discoveryFilter);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@
import com.amazonaws.encryptionsdk.AwsCrypto;
import com.amazonaws.encryptionsdk.CommitmentPolicy;
import com.amazonaws.encryptionsdk.CryptoResult;
import com.amazonaws.encryptionsdk.kms.KmsMasterKey;
import com.amazonaws.encryptionsdk.kms.KmsMasterKeyProvider;
import com.amazonaws.encryptionsdk.kmssdkv2.KmsMasterKey;
import com.amazonaws.encryptionsdk.kmssdkv2.KmsMasterKeyProvider;

/**
* <p>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@
import com.amazonaws.encryptionsdk.AwsCrypto;
import com.amazonaws.encryptionsdk.CryptoAlgorithm;
import com.amazonaws.encryptionsdk.CryptoResult;
import com.amazonaws.encryptionsdk.kms.KmsMasterKey;
import com.amazonaws.encryptionsdk.kms.KmsMasterKeyProvider;
import com.amazonaws.encryptionsdk.kmssdkv2.KmsMasterKey;
import com.amazonaws.encryptionsdk.kmssdkv2.KmsMasterKeyProvider;

/**
* <p>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,8 @@
import com.amazonaws.encryptionsdk.caching.CachingCryptoMaterialsManager;
import com.amazonaws.encryptionsdk.caching.CryptoMaterialsCache;
import com.amazonaws.encryptionsdk.caching.LocalCryptoMaterialsCache;
import com.amazonaws.encryptionsdk.kms.KmsMasterKey;
import com.amazonaws.encryptionsdk.kms.KmsMasterKeyProvider;
import com.amazonaws.encryptionsdk.CommitmentPolicy;
import com.amazonaws.encryptionsdk.kmssdkv2.KmsMasterKey;
import com.amazonaws.encryptionsdk.kmssdkv2.KmsMasterKeyProvider;

/**
* <p>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,29 @@ public class VersionInfo {
* Loads the version of the library
*/
public static String loadUserAgent() {
return USER_AGENT_PREFIX + versionNumber();
}

/**
* This returns the API name compatible with the AWS SDK v2
*
* @return the name of the library with a tag indicating intended for AWS SDK v2
*/
public static String apiName() {
return USER_AGENT_PREFIX.substring(0, USER_AGENT_PREFIX.length() - 1);
}

/*
* String representation of the library version e.g. 2.3.3
*/
public static String versionNumber() {
try {
final Properties properties = new Properties();
final ClassLoader loader = VersionInfo.class.getClassLoader();
properties.load(loader.getResourceAsStream("project.properties"));
return USER_AGENT_PREFIX + properties.getProperty("version");
return properties.getProperty("version");
} catch (final IOException ex) {
return USER_AGENT_PREFIX + UNKNOWN_VERSION;
return UNKNOWN_VERSION;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,6 @@ private AwsKmsMrkAwareMasterKey(
"AwsKmsMrkAwareMasterKey must be configured with an AWS KMS client.");
}

/* Precondition: A provider is required. */
if (provider == null) {
throw new IllegalArgumentException(
"AwsKmsMrkAwareMasterKey must be configured with a source provider.");
Expand Down Expand Up @@ -177,7 +176,6 @@ public DataKey<AwsKmsMrkAwareMasterKey> generateDataKey(
// # The response's "KeyId"
// # MUST be valid.
final String gdkResultKeyId = gdkResult.getKeyId();
/* Exceptional Postcondition: Must have an AWS KMS ARN from AWS KMS generateDataKey. */
if (parseInfoFromKeyArn(gdkResultKeyId) == null) {
throw new IllegalStateException("Received an empty or invalid keyId from KMS");
}
Expand Down Expand Up @@ -212,7 +210,6 @@ public DataKey<AwsKmsMrkAwareMasterKey> encryptDataKey(
final Map<String, String> encryptionContext,
final DataKey<?> dataKey) {
final SecretKey key = dataKey.getKey();
/* Precondition: The key format MUST be RAW. */
if (!key.getFormat().equals("RAW")) {
throw new IllegalArgumentException("Only RAW encoded keys are supported");
}
Expand All @@ -237,7 +234,6 @@ public DataKey<AwsKmsMrkAwareMasterKey> encryptDataKey(
final String encryptResultKeyId = encryptResult.getKeyId();
// = compliance/framework/aws-kms/aws-kms-mrk-aware-master-key.txt#2.11
// # The AWS KMS Encrypt response MUST contain a valid "KeyId".
/* Postcondition: Must have an AWS KMS ARN from AWS KMS encrypt. */
if (parseInfoFromKeyArn(encryptResultKeyId) == null) {
throw new IllegalStateException("Received an empty or invalid keyId from KMS");
}
Expand Down Expand Up @@ -326,7 +322,6 @@ public DataKey<AwsKmsMrkAwareMasterKey> decryptDataKey(
// = compliance/framework/aws-kms/aws-kms-mrk-aware-master-key.txt#2.9
// # The output MUST be the same as the Master Key Decrypt Data Key
// # (../master-key-interface.md#decrypt-data-key) interface.
/* Exceptional Postcondition: Master key was unable to decrypt. */
.orElseThrow(() -> buildCannotDecryptDksException(exceptions));
}

Expand Down Expand Up @@ -358,7 +353,6 @@ static DataKey<AwsKmsMrkAwareMasterKey> decryptSingleEncryptedDataKey(
.withKeyId(awsKmsIdentifier)));

final String decryptResultKeyId = decryptResult.getKeyId();
/* Exceptional Postcondition: Must have a CMK ARN from AWS KMS to match. */
if (decryptResultKeyId == null) {
throw new IllegalStateException("Received an empty keyId from KMS");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,6 @@ static KmsMasterKeyProvider.RegionalClientSupplier clientFactory(
: AWSKMSClientBuilder.standard();

return region -> {
/* Check for early return (Postcondition): If a client already exists, use that. */
if (clientCache.containsKey(region)) {
return clientCache.get(region);
}
Expand Down Expand Up @@ -381,10 +380,6 @@ private AwsKmsMrkAwareMasterKeyProvider(
// # kms-mrk-are-unique.md#Implementation) and the function MUST return
// # success.
assertMrksAreUnique(keyIds);
/* Precondition: A region is required to contact AWS KMS.
* This is an edge case because the default region will be the same as the SDK default,
* but it is still possible.
*/
if (!isDiscovery
&& defaultRegion == null
&& keyIds.stream()
Expand Down Expand Up @@ -447,16 +442,6 @@ static void assertMrksAreUnique(List<String> keyIdentifiers) {
// # arn.md#identifying-an-aws-kms-multi-region-key) this function MUST
// # exit successfully.
//
/* Postcondition: Filter out duplicate resources that are not multi-region keys.
* I expect only have duplicates of specific multi-region keys.
* In JSON something like
* {
* "mrk-edb7fe6942894d32ac46dbb1c922d574" : [
* "arn:aws:kms:us-west-2:111122223333:key/mrk-edb7fe6942894d32ac46dbb1c922d574",
* "arn:aws:kms:us-east-2:111122223333:key/mrk-edb7fe6942894d32ac46dbb1c922d574"
* ]
* }
*/
.filter(maybeMrk -> isMRK(maybeMrk.getKey()))
/* Flatten the duplicate identifiers into a single list. */
.flatMap(mrkEntry -> mrkEntry.getValue().stream())
Expand All @@ -481,35 +466,12 @@ static void assertMrksAreUnique(List<String> keyIdentifiers) {
*/
static String getResourceForResourceTypeKey(String identifier) {
final AwsKmsCmkArnInfo info = parseInfoFromKeyArn(identifier);
/* Check for early return (Postcondition): Non-ARNs may be raw resources.
* Raw aliases ('alias/my-key')
* or key ids ('mrk-edb7fe6942894d32ac46dbb1c922d574').
*/
if (info == null) return identifier;

/* Check for early return (Postcondition): Return the identifier for non-key resource types.
* I only care about duplicate multi-region *keys*.
* Any other resource type
* should get filtered out.
* I return the entire identifier
* on the off chance that
* a customer has created
* an alias with a name `mrk-*`.
* This way such an alias
* can never accidentally
* collided with an existing multi-region key
* or a duplicate alias.
*/
if (!info.getResourceType().equals("key")) {
return identifier;
}

/* Postcondition: Return the key id.
* This will be used
* to find different regional replicas of
* the same multi-region key
* because the key id for replicas is always the same.
*/
return info.getResource();
}

Expand Down Expand Up @@ -559,10 +521,6 @@ public AwsKmsMrkAwareMasterKey getMasterKey(final String providerId, final Strin
// = compliance/framework/aws-kms/aws-kms-mrk-aware-master-key-provider.txt#2.7
// # In discovery mode, the requested
// # AWS KMS key identifier MUST be a well formed AWS KMS ARN.
/* Precondition: Discovery mode requires requestedKeyArn be an ARN.
* This function is called on the encrypt path.
* It _may_ be the case that a raw key id, for example, was configured.
*/
if (isDiscovery_ && requestedKeyArnInfo == null) {
throw new NoSuchMasterKeyException(
"Cannot use AWS KMS identifiers " + "when in discovery mode.");
Expand Down
Loading

0 comments on commit 006cdc4

Please sign in to comment.