Skip to content

Commit b893a0e

Browse files
Add master key provider examples (#168)
* Add master key provider examples * Updating example intro and adding links in readme * Fixing indentation of comments
1 parent 2d025a8 commit b893a0e

File tree

7 files changed

+657
-0
lines changed

7 files changed

+657
-0
lines changed

src/examples/README.md

+6
Original file line numberDiff line numberDiff line change
@@ -28,26 +28,32 @@ We start with AWS KMS examples, then show how to use other wrapping keys.
2828
* Using AWS Key Management Service (AWS KMS)
2929
* How to use one AWS KMS CMK
3030
* [with keyrings](./java/com/amazonaws/crypto/examples/keyring/awskms/SingleCmk.java)
31+
* [with master key providers](./java/com/amazonaws/crypto/examples/masterkeyprovider/awskms/SingleCmk.java)
3132
* How to use multiple AWS KMS CMKs in different regions
3233
* [with keyrings](./java/com/amazonaws/crypto/examples/keyring/awskms/MultipleRegions.java)
34+
* [with master key providers](./java/com/amazonaws/crypto/examples/masterkeyprovider/awskms/MultipleRegions.java)
3335
* How to decrypt when you don't know the CMK
3436
* [with keyrings](./java/com/amazonaws/crypto/examples/keyring/awskms/DiscoveryDecrypt.java)
37+
* [with master key providers](./java/com/amazonaws/crypto/examples/masterkeyprovider/awskms/DiscoveryDecrypt.java)
3538
* How to decrypt within a region
3639
* [with keyrings](./java/com/amazonaws/crypto/examples/keyring/awskms/DiscoveryDecryptInRegionOnly.java)
3740
* How to decrypt with a preferred region but failover to others
3841
* [with keyrings](./java/com/amazonaws/crypto/examples/keyring/awskms/DiscoveryDecryptWithPreferredRegions.java)
3942
* Using raw wrapping keys
4043
* How to use a raw AES wrapping key
4144
* [with keyrings](./java/com/amazonaws/crypto/examples/keyring/rawaes/RawAes.java)
45+
* [with master key providers](./java/com/amazonaws/crypto/examples/masterkeyprovider/rawaes/RawAes.java)
4246
* How to use a raw RSA wrapping key
4347
* [with keyrings](./java/com/amazonaws/crypto/examples/keyring/rawrsa/RawRsa.java)
48+
* [with master key providers](./java/com/amazonaws/crypto/examples/masterkeyprovider/rawrsa/RawRsa.java)
4449
* How to encrypt with a raw RSA public key wrapping key without access to the private key
4550
* [with keyrings](./java/com/amazonaws/crypto/examples/keyring/rawrsa/PublicPrivateKeySeparate.java)
4651
* How to use a raw RSA wrapping key when the key is DER encoded
4752
* [with keyrings](./java/com/amazonaws/crypto/examples/keyring/rawrsa/RawRsaDerEncoded.java)
4853
* Combining wrapping keys
4954
* How to combine AWS KMS with an offline escrow key
5055
* [with keyrings](./java/com/amazonaws/crypto/examples/keyring/multi/AwsKmsWithEscrow.java)
56+
* [with master key providers](./java/com/amazonaws/crypto/examples/masterkeyprovider/multi/AwsKmsWithEscrow.java)
5157

5258
### Keyrings
5359

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package com.amazonaws.crypto.examples.masterkeyprovider.awskms;
5+
6+
import com.amazonaws.encryptionsdk.AwsCrypto;
7+
import com.amazonaws.encryptionsdk.CryptoResult;
8+
import com.amazonaws.encryptionsdk.kms.AwsKmsCmkId;
9+
import com.amazonaws.encryptionsdk.kms.KmsMasterKey;
10+
import com.amazonaws.encryptionsdk.kms.KmsMasterKeyProvider;
11+
12+
import java.util.Arrays;
13+
import java.util.HashMap;
14+
import java.util.Map;
15+
16+
/**
17+
* This example is intended to serve as reference material for users migrating away from master key providers.
18+
* We recommend using keyrings rather than master key providers.
19+
* For examples using keyrings, see the 'examples/keyring' directory.
20+
* <p>
21+
* The KMS master key provider uses any key IDs that you specify on encrypt,
22+
* but attempts to decrypt *any* data keys that were encrypted under a KMS CMK.
23+
* This means that you do not need to know which CMKs were used to encrypt a message.
24+
* <p>
25+
* This example shows how to configure and use a KMS master key provider to decrypt without provider key IDs.
26+
* <p>
27+
* https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/concepts.html#master-key-provider
28+
* <p>
29+
* For an example of how to use the KMS master key with a single CMK,
30+
* see the {@link SingleCmk} example.
31+
* <p>
32+
* For an example of how to use the KMS master key provider with CMKs in multiple regions,
33+
* see the {@link MultipleRegions} example.
34+
*/
35+
public class DiscoveryDecrypt {
36+
37+
/**
38+
* Demonstrate configuring a KMS master key provider for decryption.
39+
*
40+
* @param awsKmsCmk The ARN of an AWS KMS CMK that protects data keys
41+
* @param sourcePlaintext Plaintext to encrypt
42+
*/
43+
public static void run(final AwsKmsCmkId awsKmsCmk, final byte[] sourcePlaintext) {
44+
// Instantiate the AWS Encryption SDK.
45+
final AwsCrypto awsEncryptionSdk = new AwsCrypto();
46+
47+
// Prepare your encryption context.
48+
// https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/concepts.html#encryption-context
49+
final Map<String, String> encryptionContext = new HashMap<>();
50+
encryptionContext.put("encryption", "context");
51+
encryptionContext.put("is not", "secret");
52+
encryptionContext.put("but adds", "useful metadata");
53+
encryptionContext.put("that can help you", "be confident that");
54+
encryptionContext.put("the data you are handling", "is what you think it is");
55+
56+
// Create the master key that determines how your data keys are protected.
57+
final KmsMasterKeyProvider encryptMasterKeyProvider = KmsMasterKeyProvider.builder()
58+
.withKeysForEncryption(awsKmsCmk.toString()).build();
59+
60+
// Create a KMS master key provider to use on decrypt.
61+
final KmsMasterKeyProvider decryptMasterKeyProvider = KmsMasterKeyProvider.builder().build();
62+
63+
// Encrypt your plaintext data.
64+
final CryptoResult<byte[], KmsMasterKey> encryptResult = awsEncryptionSdk.encryptData(
65+
encryptMasterKeyProvider,
66+
sourcePlaintext,
67+
encryptionContext);
68+
final byte[] ciphertext = encryptResult.getResult();
69+
70+
// Demonstrate that the ciphertext and plaintext are different.
71+
assert !Arrays.equals(ciphertext, sourcePlaintext);
72+
73+
// Decrypt your encrypted data using the KMS master key provider.
74+
//
75+
// You do not need to specify the encryption context on decrypt because
76+
// the header of the encrypted message includes the encryption context.
77+
final CryptoResult<byte[], KmsMasterKey> decryptResult = awsEncryptionSdk.decryptData(
78+
decryptMasterKeyProvider,
79+
ciphertext);
80+
final byte[] decrypted = decryptResult.getResult();
81+
82+
// Demonstrate that the decrypted plaintext is identical to the original plaintext.
83+
assert Arrays.equals(decrypted, sourcePlaintext);
84+
85+
// Verify that the encryption context used in the decrypt operation includes
86+
// the encryption context that you specified when encrypting.
87+
// The AWS Encryption SDK can add pairs, so don't require an exact match.
88+
//
89+
// In production, always use a meaningful encryption context.
90+
encryptionContext.forEach((k, v) -> {
91+
assert v.equals(decryptResult.getEncryptionContext().get(k));
92+
});
93+
}
94+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package com.amazonaws.crypto.examples.masterkeyprovider.awskms;
5+
6+
import com.amazonaws.encryptionsdk.AwsCrypto;
7+
import com.amazonaws.encryptionsdk.CryptoResult;
8+
import com.amazonaws.encryptionsdk.kms.AwsKmsCmkId;
9+
import com.amazonaws.encryptionsdk.kms.KmsMasterKey;
10+
import com.amazonaws.encryptionsdk.kms.KmsMasterKeyProvider;
11+
12+
import java.util.ArrayList;
13+
import java.util.Arrays;
14+
import java.util.HashMap;
15+
import java.util.List;
16+
import java.util.Map;
17+
18+
import static java.util.stream.Collectors.toList;
19+
20+
/**
21+
* This example is intended to serve as reference material for users migrating away from master key providers.
22+
* We recommend using keyrings rather than master key providers.
23+
* For examples using keyrings, see the 'examples/keyring' directory.
24+
* <p>
25+
* This example shows how to configure and use a KMS master key provider with with CMKs in multiple regions.
26+
* <p>
27+
* https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/concepts.html#master-key-provider
28+
* <p>
29+
* For an example of how to use the KMS master key with a single CMK,
30+
* see the {@link SingleCmk} example.
31+
* <p>
32+
* For an example of how to use the KMS master key provider in discovery mode on decrypt,
33+
* see the {@link DiscoveryDecrypt} example.
34+
*/
35+
public class MultipleRegions {
36+
37+
/**
38+
* Demonstrate an encrypt/decrypt cycle using a KMS master key provider with CMKs in multiple regions.
39+
*
40+
* @param awsKmsGeneratorCmk The ARN of an AWS KMS CMK that protects data keys
41+
* @param awsKmsAdditionalCmks Additional ARNs of secondary KMS CMKs
42+
* @param sourcePlaintext Plaintext to encrypt
43+
*/
44+
public static void run(final AwsKmsCmkId awsKmsGeneratorCmk, final List<AwsKmsCmkId> awsKmsAdditionalCmks, final byte[] sourcePlaintext) {
45+
// Instantiate the AWS Encryption SDK.
46+
final AwsCrypto awsEncryptionSdk = new AwsCrypto();
47+
48+
// Prepare your encryption context.
49+
// https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/concepts.html#encryption-context
50+
final Map<String, String> encryptionContext = new HashMap<>();
51+
encryptionContext.put("encryption", "context");
52+
encryptionContext.put("is not", "secret");
53+
encryptionContext.put("but adds", "useful metadata");
54+
encryptionContext.put("that can help you", "be confident that");
55+
encryptionContext.put("the data you are handling", "is what you think it is");
56+
57+
// Create the master key provider that will encrypt your data keys under all requested CMKs.
58+
//
59+
// The KMS master key provider generates the data key using the first key ID in the list.
60+
final List<String> awsKmsCmks = new ArrayList<>();
61+
awsKmsCmks.add(awsKmsGeneratorCmk.toString());
62+
awsKmsCmks.addAll(awsKmsAdditionalCmks.stream().map(AwsKmsCmkId::toString).collect(toList()));
63+
final KmsMasterKeyProvider masterKeyProvider = KmsMasterKeyProvider.builder()
64+
.withKeysForEncryption(awsKmsCmks).build();
65+
66+
// Create master key providers that each only use one of the CMKs.
67+
// We will use these later to demonstrate that any of the CMKs can be used to decrypt the message.
68+
final KmsMasterKeyProvider singleCmkMasterKeyThatGenerated = KmsMasterKeyProvider.builder()
69+
.withKeysForEncryption(awsKmsGeneratorCmk.toString()).build();
70+
final KmsMasterKeyProvider singleCmkMasterKeyThatEncrypted = KmsMasterKeyProvider.builder()
71+
.withKeysForEncryption(awsKmsAdditionalCmks.get(0).toString()).build();
72+
73+
// Encrypt your plaintext data using the master key provider that uses all requests CMKs.
74+
final CryptoResult<byte[], KmsMasterKey> encryptResult = awsEncryptionSdk.encryptData(
75+
masterKeyProvider,
76+
sourcePlaintext,
77+
encryptionContext);
78+
final byte[] ciphertext = encryptResult.getResult();
79+
80+
// Verify that the header contains the expected number of encrypted data keys (EDKs).
81+
// It should contain one EDK for each CMK.
82+
assert encryptResult.getHeaders().getEncryptedKeyBlobCount() == awsKmsAdditionalCmks.size() + 1;
83+
84+
// Demonstrate that the ciphertext and plaintext are different.
85+
assert !Arrays.equals(ciphertext, sourcePlaintext);
86+
87+
// Decrypt your encrypted data separately using the single-CMK master keys.
88+
//
89+
// You do not need to specify the encryption context on decrypt because
90+
// the header of the encrypted message includes the encryption context.
91+
final CryptoResult<byte[], KmsMasterKey> decryptResult1 = awsEncryptionSdk.decryptData(
92+
singleCmkMasterKeyThatGenerated,
93+
ciphertext);
94+
final byte[] decrypted1 = decryptResult1.getResult();
95+
final CryptoResult<byte[], KmsMasterKey> decryptResult2 = awsEncryptionSdk.decryptData(
96+
singleCmkMasterKeyThatEncrypted,
97+
ciphertext);
98+
final byte[] decrypted2 = decryptResult2.getResult();
99+
100+
// Demonstrate that the decrypted plaintext is identical to the original plaintext.
101+
assert Arrays.equals(decrypted1, sourcePlaintext);
102+
assert Arrays.equals(decrypted2, sourcePlaintext);
103+
104+
// Verify that the encryption context used in the decrypt operation includes
105+
// the encryption context that you specified when encrypting.
106+
// The AWS Encryption SDK can add pairs, so don't require an exact match.
107+
//
108+
// In production, always use a meaningful encryption context.
109+
encryptionContext.forEach((k, v) -> {
110+
assert v.equals(decryptResult1.getEncryptionContext().get(k));
111+
assert v.equals(decryptResult2.getEncryptionContext().get(k));
112+
});
113+
}
114+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package com.amazonaws.crypto.examples.masterkeyprovider.awskms;
5+
6+
import com.amazonaws.encryptionsdk.AwsCrypto;
7+
import com.amazonaws.encryptionsdk.CryptoResult;
8+
import com.amazonaws.encryptionsdk.kms.AwsKmsCmkId;
9+
import com.amazonaws.encryptionsdk.kms.KmsMasterKey;
10+
import com.amazonaws.encryptionsdk.kms.KmsMasterKeyProvider;
11+
12+
import java.util.Arrays;
13+
import java.util.HashMap;
14+
import java.util.Map;
15+
16+
/**
17+
* This example is intended to serve as reference material for users migrating away from master key providers.
18+
* We recommend using keyrings rather than master key providers.
19+
* For examples using keyrings, see the 'examples/keyring' directory.
20+
* <p>
21+
* This example shows how to configure and use a KMS master key with a single KMS CMK.
22+
* <p>
23+
* https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/concepts.html#master-key-provider
24+
* <p>
25+
* For an example of how to use the KMS master key provider with CMKs in multiple regions,
26+
* see the {@link MultipleRegions} example.
27+
* <p>
28+
* For an example of how to use the KMS master key provider in discovery mode on decrypt,
29+
* see the {@link DiscoveryDecrypt} example.
30+
*/
31+
public class SingleCmk {
32+
33+
/**
34+
* Demonstrate an encrypt/decrypt cycle using a KMS master key provider with a single CMK.
35+
*
36+
* @param awsKmsCmk The ARN of an AWS KMS CMK that protects data keys
37+
* @param sourcePlaintext Plaintext to encrypt
38+
*/
39+
public static void run(final AwsKmsCmkId awsKmsCmk, final byte[] sourcePlaintext) {
40+
// Instantiate the AWS Encryption SDK.
41+
final AwsCrypto awsEncryptionSdk = new AwsCrypto();
42+
43+
// Prepare your encryption context.
44+
// https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/concepts.html#encryption-context
45+
final Map<String, String> encryptionContext = new HashMap<>();
46+
encryptionContext.put("encryption", "context");
47+
encryptionContext.put("is not", "secret");
48+
encryptionContext.put("but adds", "useful metadata");
49+
encryptionContext.put("that can help you", "be confident that");
50+
encryptionContext.put("the data you are handling", "is what you think it is");
51+
52+
// Create the master key provider that determines how your data keys are protected.
53+
final KmsMasterKeyProvider masterKeyProvider = KmsMasterKeyProvider.builder()
54+
.withKeysForEncryption(awsKmsCmk.toString()).build();
55+
56+
// Encrypt your plaintext data.
57+
final CryptoResult<byte[], KmsMasterKey> encryptResult = awsEncryptionSdk.encryptData(
58+
masterKeyProvider,
59+
sourcePlaintext,
60+
encryptionContext);
61+
final byte[] ciphertext = encryptResult.getResult();
62+
63+
// Demonstrate that the ciphertext and plaintext are different.
64+
assert !Arrays.equals(ciphertext, sourcePlaintext);
65+
66+
// Decrypt your encrypted data using the same master key provider you used on encrypt.
67+
//
68+
// You do not need to specify the encryption context on decrypt because
69+
// the header of the encrypted message includes the encryption context.
70+
final CryptoResult<byte[], KmsMasterKey> decryptResult = awsEncryptionSdk.decryptData(
71+
masterKeyProvider,
72+
ciphertext);
73+
final byte[] decrypted = decryptResult.getResult();
74+
75+
// Demonstrate that the decrypted plaintext is identical to the original plaintext.
76+
assert Arrays.equals(decrypted, sourcePlaintext);
77+
78+
// Verify that the encryption context used in the decrypt operation includes
79+
// the encryption context that you specified when encrypting.
80+
// The AWS Encryption SDK can add pairs, so don't require an exact match.
81+
//
82+
// In production, always use a meaningful encryption context.
83+
encryptionContext.forEach((k, v) -> {
84+
assert v.equals(decryptResult.getEncryptionContext().get(k));
85+
});
86+
}
87+
}

0 commit comments

Comments
 (0)