Skip to content

Commit e04c285

Browse files
Create AwsKmsCmkId type to represent AWS KMS Key Ids
1 parent 5258475 commit e04c285

21 files changed

+374
-257
lines changed

src/examples/java/com/amazonaws/crypto/examples/BasicEncryptionExample.java

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import com.amazonaws.encryptionsdk.EncryptRequest;
2525
import com.amazonaws.encryptionsdk.keyrings.Keyring;
2626
import com.amazonaws.encryptionsdk.keyrings.StandardKeyrings;
27+
import com.amazonaws.encryptionsdk.kms.AwsKmsCmkId;
2728

2829
/**
2930
* <p>
@@ -41,12 +42,10 @@ public class BasicEncryptionExample {
4142
private static final byte[] EXAMPLE_DATA = "Hello World".getBytes(StandardCharsets.UTF_8);
4243

4344
public static void main(final String[] args) {
44-
final String keyArn = args[0];
45-
46-
encryptAndDecrypt(keyArn);
45+
encryptAndDecrypt(AwsKmsCmkId.fromString(args[0]));
4746
}
4847

49-
static void encryptAndDecrypt(final String keyArn) {
48+
static void encryptAndDecrypt(final AwsKmsCmkId keyArn) {
5049
// 1. Instantiate the SDK
5150
final AwsCrypto crypto = new AwsCrypto();
5251

@@ -81,7 +80,7 @@ static void encryptAndDecrypt(final String keyArn) {
8180

8281
// 6. Before verifying the plaintext, inspect the Keyring Trace to verify that the CMK used
8382
// to decrypt the encrypted data key was the CMK in the encryption keyring.
84-
if(!decryptResult.getKeyringTrace().getEntries().get(0).getKeyName().equals(keyArn)) {
83+
if(!decryptResult.getKeyringTrace().getEntries().get(0).getKeyName().equals(keyArn.toString())) {
8584
throw new IllegalStateException("Wrong key ID!");
8685
}
8786

src/examples/java/com/amazonaws/crypto/examples/EscrowedEncryptExample.java

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import com.amazonaws.encryptionsdk.EncryptRequest;
1919
import com.amazonaws.encryptionsdk.keyrings.Keyring;
2020
import com.amazonaws.encryptionsdk.keyrings.StandardKeyrings;
21+
import com.amazonaws.encryptionsdk.kms.AwsKmsCmkId;
2122

2223
import java.nio.charset.StandardCharsets;
2324
import java.security.GeneralSecurityException;
@@ -55,12 +56,10 @@ public class EscrowedEncryptExample {
5556
private static final byte[] EXAMPLE_DATA = "Hello World".getBytes(StandardCharsets.UTF_8);
5657

5758
public static void main(final String[] args) throws GeneralSecurityException {
58-
final String kmsArn = args[0];
59-
60-
escrowEncryptAndDecrypt(kmsArn);
59+
escrowEncryptAndDecrypt(AwsKmsCmkId.fromString(args[0]));
6160
}
6261

63-
static void escrowEncryptAndDecrypt(String kmsArn) throws GeneralSecurityException {
62+
static void escrowEncryptAndDecrypt(AwsKmsCmkId kmsArn) throws GeneralSecurityException {
6463
// This sample generates a new random key for each operation.
6564
// In practice, you would distribute the public key and save the private key in secure storage.
6665
final KeyPair escrowKeyPair = generateEscrowKeyPair();
@@ -79,7 +78,7 @@ static void escrowEncryptAndDecrypt(String kmsArn) throws GeneralSecurityExcepti
7978
assert Arrays.equals(escrowedDecryptedData, EXAMPLE_DATA);
8079
}
8180

82-
private static byte[] standardEncrypt(final String kmsArn, final PublicKey publicEscrowKey) {
81+
private static byte[] standardEncrypt(final AwsKmsCmkId kmsArn, final PublicKey publicEscrowKey) {
8382
// Encrypt with the KMS CMK and the escrowed public key
8483

8584
// 1. Instantiate the SDK
@@ -110,7 +109,7 @@ private static byte[] standardEncrypt(final String kmsArn, final PublicKey publi
110109
.getResult();
111110
}
112111

113-
private static byte[] standardDecrypt(final String kmsArn, final byte[] cipherText) {
112+
private static byte[] standardDecrypt(final AwsKmsCmkId kmsArn, final byte[] cipherText) {
114113
// Decrypt with the KMS CMK
115114

116115
// 1. Instantiate the SDK

src/main/java/com/amazonaws/encryptionsdk/internal/Constants.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,4 +62,9 @@ private Constants() {
6262
public static final long MAX_FRAME_NUMBER = (1L << 32) - 1;
6363

6464
public static final String EC_PUBLIC_KEY_FIELD = "aws-crypto-public-key";
65+
66+
/**
67+
* The provider ID used for the AwsKmsKeyring
68+
*/
69+
public static final String AWS_KMS_PROVIDER_ID = "aws-kms";
6570
}

src/main/java/com/amazonaws/encryptionsdk/keyrings/AwsKmsKeyring.java

Lines changed: 25 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,10 @@
1616
import com.amazonaws.encryptionsdk.EncryptedDataKey;
1717
import com.amazonaws.encryptionsdk.exception.AwsCryptoException;
1818
import com.amazonaws.encryptionsdk.exception.CannotUnwrapDataKeyException;
19-
import com.amazonaws.encryptionsdk.exception.MalformedArnException;
19+
import com.amazonaws.encryptionsdk.kms.AwsKmsCmkId;
2020
import com.amazonaws.encryptionsdk.kms.DataKeyEncryptionDao;
2121
import com.amazonaws.encryptionsdk.kms.DataKeyEncryptionDao.DecryptDataKeyResult;
2222
import com.amazonaws.encryptionsdk.kms.DataKeyEncryptionDao.GenerateDataKeyResult;
23-
import com.amazonaws.encryptionsdk.kms.KmsUtils;
2423
import com.amazonaws.encryptionsdk.model.DecryptionMaterials;
2524
import com.amazonaws.encryptionsdk.model.EncryptionMaterials;
2625
import com.amazonaws.encryptionsdk.model.KeyBlob;
@@ -31,8 +30,8 @@
3130
import java.util.Set;
3231

3332
import static com.amazonaws.encryptionsdk.EncryptedDataKey.PROVIDER_ENCODING;
34-
import static com.amazonaws.encryptionsdk.kms.KmsUtils.KMS_PROVIDER_ID;
35-
import static com.amazonaws.encryptionsdk.kms.KmsUtils.isArnWellFormed;
33+
import static com.amazonaws.encryptionsdk.internal.Constants.AWS_KMS_PROVIDER_ID;
34+
import static com.amazonaws.encryptionsdk.kms.AwsKmsCmkId.isKeyIdWellFormed;
3635
import static java.util.Collections.emptyList;
3736
import static java.util.Collections.unmodifiableList;
3837
import static java.util.Objects.requireNonNull;
@@ -44,28 +43,19 @@
4443
class AwsKmsKeyring implements Keyring {
4544

4645
private final DataKeyEncryptionDao dataKeyEncryptionDao;
47-
private final List<String> keyIds;
48-
private final String generatorKeyId;
46+
private final List<AwsKmsCmkId> keyIds;
47+
private final AwsKmsCmkId generatorKeyId;
4948
private final boolean isDiscovery;
5049

51-
AwsKmsKeyring(DataKeyEncryptionDao dataKeyEncryptionDao, List<String> keyIds, String generatorKeyId) {
50+
AwsKmsKeyring(DataKeyEncryptionDao dataKeyEncryptionDao, List<AwsKmsCmkId> keyIds, AwsKmsCmkId generatorKeyId) {
5251
requireNonNull(dataKeyEncryptionDao, "dataKeyEncryptionDao is required");
5352
this.dataKeyEncryptionDao = dataKeyEncryptionDao;
5453
this.keyIds = keyIds == null ? emptyList() : unmodifiableList(new ArrayList<>(keyIds));
5554
this.generatorKeyId = generatorKeyId;
5655
this.isDiscovery = this.generatorKeyId == null && this.keyIds.isEmpty();
5756

58-
if (!this.keyIds.stream().allMatch(KmsUtils::isArnWellFormed)) {
59-
throw new MalformedArnException("keyIds must contain only CMK aliases and well formed ARNs");
60-
}
61-
62-
if (generatorKeyId != null) {
63-
if (!isArnWellFormed(generatorKeyId)) {
64-
throw new MalformedArnException("generatorKeyId must be either a CMK alias or a well formed ARN");
65-
}
66-
if (this.keyIds.contains(generatorKeyId)) {
67-
throw new IllegalArgumentException("KeyIds should not contain the generatorKeyId");
68-
}
57+
if (this.keyIds.contains(generatorKeyId)) {
58+
throw new IllegalArgumentException("KeyIds should not contain the generatorKeyId");
6959
}
7060
}
7161

@@ -86,7 +76,7 @@ public EncryptionMaterials onEncrypt(EncryptionMaterials encryptionMaterials) {
8676
throw new AwsCryptoException("Encryption materials must contain either a plaintext data key or a generator");
8777
}
8878

89-
final List<String> keyIdsToEncrypt = new ArrayList<>(keyIds);
79+
final List<AwsKmsCmkId> keyIdsToEncrypt = new ArrayList<>(keyIds);
9080

9181
// If the input encryption materials do not contain a plaintext data key and a generator is defined onEncrypt
9282
// MUST attempt to generate a new plaintext data key and encrypt that data key by calling KMS GenerateDataKey.
@@ -100,7 +90,7 @@ public EncryptionMaterials onEncrypt(EncryptionMaterials encryptionMaterials) {
10090

10191
// Given a plaintext data key in the encryption materials, OnEncrypt MUST attempt
10292
// to encrypt the plaintext data key using each CMK specified in it's key IDs list.
103-
for (String keyId : keyIdsToEncrypt) {
93+
for (AwsKmsCmkId keyId : keyIdsToEncrypt) {
10494
resultMaterials = encryptDataKey(keyId, resultMaterials);
10595
}
10696

@@ -113,17 +103,20 @@ private EncryptionMaterials generateDataKey(final EncryptionMaterials encryption
113103

114104
return encryptionMaterials
115105
.withCleartextDataKey(result.getPlaintextDataKey(),
116-
new KeyringTraceEntry(KMS_PROVIDER_ID, generatorKeyId, KeyringTraceFlag.GENERATED_DATA_KEY))
106+
new KeyringTraceEntry(AWS_KMS_PROVIDER_ID, generatorKeyId.toString(),
107+
KeyringTraceFlag.GENERATED_DATA_KEY))
117108
.withEncryptedDataKey(new KeyBlob(result.getEncryptedDataKey()),
118-
new KeyringTraceEntry(KMS_PROVIDER_ID, generatorKeyId, KeyringTraceFlag.ENCRYPTED_DATA_KEY, KeyringTraceFlag.SIGNED_ENCRYPTION_CONTEXT));
109+
new KeyringTraceEntry(AWS_KMS_PROVIDER_ID, generatorKeyId.toString(),
110+
KeyringTraceFlag.ENCRYPTED_DATA_KEY, KeyringTraceFlag.SIGNED_ENCRYPTION_CONTEXT));
119111
}
120112

121-
private EncryptionMaterials encryptDataKey(final String keyId, final EncryptionMaterials encryptionMaterials) {
113+
private EncryptionMaterials encryptDataKey(final AwsKmsCmkId keyId, final EncryptionMaterials encryptionMaterials) {
122114
final EncryptedDataKey encryptedDataKey = dataKeyEncryptionDao.encryptDataKey(keyId,
123115
encryptionMaterials.getCleartextDataKey(), encryptionMaterials.getEncryptionContext());
124116

125117
return encryptionMaterials.withEncryptedDataKey(new KeyBlob(encryptedDataKey),
126-
new KeyringTraceEntry(KMS_PROVIDER_ID, keyId, KeyringTraceFlag.ENCRYPTED_DATA_KEY, KeyringTraceFlag.SIGNED_ENCRYPTION_CONTEXT));
118+
new KeyringTraceEntry(AWS_KMS_PROVIDER_ID, keyId.toString(),
119+
KeyringTraceFlag.ENCRYPTED_DATA_KEY, KeyringTraceFlag.SIGNED_ENCRYPTION_CONTEXT));
127120
}
128121

129122
@Override
@@ -135,7 +128,7 @@ public DecryptionMaterials onDecrypt(DecryptionMaterials decryptionMaterials, Li
135128
return decryptionMaterials;
136129
}
137130

138-
final Set<String> configuredKeyIds = new HashSet<>(keyIds);
131+
final Set<AwsKmsCmkId> configuredKeyIds = new HashSet<>(keyIds);
139132

140133
if (generatorKeyId != null) {
141134
configuredKeyIds.add(generatorKeyId);
@@ -148,7 +141,7 @@ public DecryptionMaterials onDecrypt(DecryptionMaterials decryptionMaterials, Li
148141
decryptionMaterials.getAlgorithm(), decryptionMaterials.getEncryptionContext());
149142

150143
return decryptionMaterials.withCleartextDataKey(result.getPlaintextDataKey(),
151-
new KeyringTraceEntry(KMS_PROVIDER_ID, result.getKeyArn(),
144+
new KeyringTraceEntry(AWS_KMS_PROVIDER_ID, result.getKeyArn(),
152145
KeyringTraceFlag.DECRYPTED_DATA_KEY, KeyringTraceFlag.VERIFIED_ENCRYPTION_CONTEXT));
153146
} catch (CannotUnwrapDataKeyException e) {
154147
continue;
@@ -159,14 +152,14 @@ public DecryptionMaterials onDecrypt(DecryptionMaterials decryptionMaterials, Li
159152
return decryptionMaterials;
160153
}
161154

162-
private boolean okToDecrypt(EncryptedDataKey encryptedDataKey, Set<String> configuredKeyIds) {
155+
private boolean okToDecrypt(EncryptedDataKey encryptedDataKey, Set<AwsKmsCmkId> configuredKeyIds) {
163156
// Only attempt to decrypt keys provided by KMS
164-
if (!encryptedDataKey.getProviderId().equals(KMS_PROVIDER_ID)) {
157+
if (!encryptedDataKey.getProviderId().equals(AWS_KMS_PROVIDER_ID)) {
165158
return false;
166159
}
167160

168-
// If the key ARN cannot be parsed, skip it
169-
if(!isArnWellFormed(new String(encryptedDataKey.getProviderInformation(), PROVIDER_ENCODING)))
161+
// If the key ID cannot be parsed, skip it
162+
if(!isKeyIdWellFormed(new String(encryptedDataKey.getProviderInformation(), PROVIDER_ENCODING)))
170163
{
171164
return false;
172165
}
@@ -180,6 +173,7 @@ private boolean okToDecrypt(EncryptedDataKey encryptedDataKey, Set<String> confi
180173
// OnDecrypt MUST attempt to decrypt each input encrypted data key in the input
181174
// encrypted data key list where the key provider info has a value equal to one
182175
// of the ARNs in this keyring's key IDs or the generator
183-
return configuredKeyIds.contains(new String(encryptedDataKey.getProviderInformation(), PROVIDER_ENCODING));
176+
return configuredKeyIds.contains(
177+
AwsKmsCmkId.fromString(new String(encryptedDataKey.getProviderInformation(), PROVIDER_ENCODING)));
184178
}
185179
}

src/main/java/com/amazonaws/encryptionsdk/keyrings/AwsKmsKeyringBuilder.java

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,16 @@
1414
package com.amazonaws.encryptionsdk.keyrings;
1515

1616
import com.amazonaws.encryptionsdk.kms.AwsKmsClientSupplier;
17+
import com.amazonaws.encryptionsdk.kms.AwsKmsCmkId;
1718
import com.amazonaws.encryptionsdk.kms.DataKeyEncryptionDao;
1819

1920
import java.util.List;
2021

2122
public class AwsKmsKeyringBuilder {
2223
private AwsKmsClientSupplier awsKmsClientSupplier;
2324
private List<String> grantTokens;
24-
private List<String> keyIds;
25-
private String generatorKeyId;
25+
private List<AwsKmsCmkId> keyIds;
26+
private AwsKmsCmkId generatorKeyId;
2627

2728
AwsKmsKeyringBuilder() {
2829
// Use StandardKeyrings.awsKms() to instantiate
@@ -53,25 +54,28 @@ public AwsKmsKeyringBuilder grantTokens(List<String> grantTokens) {
5354
}
5455

5556
/**
56-
* A list of strings identifying AWS KMS CMKs used for encrypting and decrypting data keys
57-
* in ARN, CMK Alias, or ARN Alias format.
57+
* A list of {@link AwsKmsCmkId}s in ARN, CMK Alias, or ARN Alias format identifying AWS KMS CMKs
58+
* used for encrypting and decrypting data keys.
5859
*
5960
* @param keyIds The list of AWS KMS CMKs
6061
* @return The AwsKmsKeyringBuilder, for method chaining
6162
*/
62-
public AwsKmsKeyringBuilder keyIds(List<String> keyIds) {
63+
public AwsKmsKeyringBuilder keyIds(List<AwsKmsCmkId> keyIds) {
6364
this.keyIds = keyIds;
6465
return this;
6566
}
6667

6768
/**
68-
* A string that identifies a AWS KMS CMK responsible for generating a data key,
69-
* as well as encrypting and decrypting data keys in ARN, CMK Alias, or ARN Alias format.
69+
* An {@link AwsKmsCmkId} in ARN, CMK Alias, or ARN Alias format that identifies a
70+
* AWS KMS CMK responsible for generating a data key, as well as encrypting and
71+
* decrypting data keys .
7072
*
71-
* @param generatorKeyId The generator AWS KMS CMK
73+
* @param generatorKeyId An {@link AwsKmsCmkId} in ARN, CMK Alias, or ARN Alias format that identifies a
74+
* AWS KMS CMK responsible for generating a data key, as well as encrypting and
75+
* decrypting data keys.
7276
* @return The AwsKmsKeyringBuilder, for method chaining
7377
*/
74-
public AwsKmsKeyringBuilder generatorKeyId(String generatorKeyId) {
78+
public AwsKmsKeyringBuilder generatorKeyId(AwsKmsCmkId generatorKeyId) {
7579
this.generatorKeyId = generatorKeyId;
7680
return this;
7781
}

src/main/java/com/amazonaws/encryptionsdk/keyrings/StandardKeyrings.java

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313

1414
package com.amazonaws.encryptionsdk.keyrings;
1515

16+
import com.amazonaws.encryptionsdk.kms.AwsKmsCmkId;
17+
1618
import java.util.Arrays;
1719
import java.util.List;
1820

@@ -50,11 +52,12 @@ public static RawRsaKeyringBuilder rawRsa() {
5052
* encrypt, and decrypt data keys using the supplied AWS KMS defined Customer Master Key (CMK).
5153
* Use {@link #awsKms()} for more advanced configuration using a {@link AwsKmsKeyringBuilder}/
5254
*
53-
* @param generatorKeyId A string that identifies a AWS KMS CMK responsible for generating a data key,
54-
* as well as encrypting and decrypting data keys in ARN, CMK Alias, or ARN Alias format.
55+
* @param generatorKeyId An {@link AwsKmsCmkId} in ARN, CMK Alias, ARN Alias or Key Id format that identifies a
56+
* AWS KMS CMK responsible for generating a data key, as well as encrypting and
57+
* decrypting data keys .
5558
* @return The {@code Keyring}
5659
*/
57-
public static Keyring awsKms(String generatorKeyId) {
60+
public static Keyring awsKms(AwsKmsCmkId generatorKeyId) {
5861
return new AwsKmsKeyringBuilder()
5962
.generatorKeyId(generatorKeyId)
6063
.build();

src/main/java/com/amazonaws/encryptionsdk/kms/AwsKmsClientSupplier.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
package com.amazonaws.encryptionsdk.kms;
1515

1616
import com.amazonaws.ClientConfiguration;
17+
import com.amazonaws.arn.Arn;
1718
import com.amazonaws.auth.AWSCredentialsProvider;
1819
import com.amazonaws.encryptionsdk.exception.UnsupportedRegionException;
1920
import com.amazonaws.services.kms.AWSKMS;
@@ -59,6 +60,25 @@ static Builder builder() {
5960
return new Builder(AWSKMSClientBuilder.standard());
6061
}
6162

63+
/**
64+
* Parses region from the given key id (if possible) and passes that region to the
65+
* given clientSupplier to produce an {@code AWSKMS} client.
66+
*
67+
* @param keyId The Amazon Resource Name, Key Alias, Alias ARN or KeyId
68+
* @param clientSupplier The client supplier
69+
* @return AWSKMS The client
70+
*/
71+
static AWSKMS getClientByKeyId(AwsKmsCmkId keyId, AwsKmsClientSupplier clientSupplier) {
72+
requireNonNull(keyId, "keyId is required");
73+
requireNonNull(clientSupplier, "clientSupplier is required");
74+
75+
if(keyId.isArn()) {
76+
return clientSupplier.getClient(Arn.fromString(keyId.toString()).getRegion());
77+
}
78+
79+
return clientSupplier.getClient(null);
80+
}
81+
6282
/**
6383
* Builder to construct an AwsKmsClientSupplier given various
6484
* optional settings.

0 commit comments

Comments
 (0)