Skip to content

Commit c5ba94e

Browse files
Add an example for replicating the behavior of the AWS KMS MKP
1 parent d2c379c commit c5ba94e

File tree

2 files changed

+116
-0
lines changed

2 files changed

+116
-0
lines changed

src/examples/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ We start with AWS KMS examples, then show how to use other wrapping keys.
3939
* [with keyrings](./java/com/amazonaws/crypto/examples/keyring/awskms/DiscoveryDecryptInRegionOnly.java)
4040
* How to decrypt with a preferred region but failover to others
4141
* [with keyrings](./java/com/amazonaws/crypto/examples/keyring/awskms/DiscoveryDecryptWithPreferredRegions.java)
42+
* How to replicate the behavior of an AWS KMS master key provider
43+
* [with keyrings](./java/com/amazonaws/crypto/examples/keyring/awskms/ActLikeAwsKmsMasterKeyProvider.java)
4244
* Using raw wrapping keys
4345
* How to use a raw AES wrapping key
4446
* [with keyrings](./java/com/amazonaws/crypto/examples/keyring/rawaes/RawAes.java)
Lines changed: 114 additions & 0 deletions
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.keyring.awskms;
5+
6+
import com.amazonaws.encryptionsdk.AwsCrypto;
7+
import com.amazonaws.encryptionsdk.AwsCryptoResult;
8+
import com.amazonaws.encryptionsdk.DecryptRequest;
9+
import com.amazonaws.encryptionsdk.EncryptRequest;
10+
import com.amazonaws.encryptionsdk.keyrings.Keyring;
11+
import com.amazonaws.encryptionsdk.keyrings.StandardKeyrings;
12+
import com.amazonaws.encryptionsdk.kms.AwsKmsCmkId;
13+
import com.amazonaws.encryptionsdk.kms.KmsMasterKeyProvider;
14+
15+
import java.util.Arrays;
16+
import java.util.HashMap;
17+
import java.util.Map;
18+
19+
/**
20+
* Before there were keyrings, there were master key providers.
21+
* Master key providers were the original configuration structure
22+
* that we provided for defining how you want to protect your data keys.
23+
* <p>
24+
* The AWS KMS master key provider was the tool that we provided for interacting with AWS KMS.
25+
* Like the AWS KMS keyring,
26+
* the AWS KMS master key provider encrypts with all CMKs that you identify,
27+
* but unlike the AWS KMS keyring,
28+
* the AWS KMS master key provider always attempts to decrypt
29+
* *any* data keys that were encrypted under an AWS KMS CMK.
30+
* We have found that separating these two behaviors
31+
* makes it more clear what behavior to expect,
32+
* so that is what we did with the AWS KMS keyring and the AWS KMS discovery keyring.
33+
* However, as you migrate away from master key providers to keyrings,
34+
* you might need to replicate the behavior of the AWS KMS master key provider.
35+
* <p>
36+
* This example shows how to configure a keyring that behaves like an AWS KMS master key provider.
37+
* <p>
38+
* For more examples of how to use the AWS KMS keyring,
39+
* see the 'keyring/awskms' directory.
40+
*/
41+
public class ActLikeAwsKmsMasterKeyProvider {
42+
43+
/**
44+
* Demonstrate how to create a keyring that behaves like an AWS KMS master key provider.
45+
*
46+
* @param awsKmsCmk The ARN of an AWS KMS CMK that protects data keys
47+
* @param sourcePlaintext Plaintext to encrypt
48+
*/
49+
public static void run(final AwsKmsCmkId awsKmsCmk, final byte[] sourcePlaintext) {
50+
// Instantiate the AWS Encryption SDK.
51+
final AwsCrypto awsEncryptionSdk = new AwsCrypto();
52+
53+
// Prepare your encryption context.
54+
// https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/concepts.html#encryption-context
55+
final Map<String, String> encryptionContext = new HashMap<>();
56+
encryptionContext.put("encryption", "context");
57+
encryptionContext.put("is not", "secret");
58+
encryptionContext.put("but adds", "useful metadata");
59+
encryptionContext.put("that can help you", "be confident that");
60+
encryptionContext.put("the data you are handling", "is what you think it is");
61+
62+
// This is the master key provider whose behavior we want to replicate.
63+
//
64+
// On encrypt, this master key provider only uses the single target AWS KMS CMK.
65+
// However, on decrypt, this master key provider attempts to decrypt
66+
// any data keys that were encrypted under an AWS KMS CMK.
67+
final KmsMasterKeyProvider masterKeyProviderToReplicate = KmsMasterKeyProvider.builder()
68+
.withKeysForEncryption(awsKmsCmk.toString()).build();
69+
70+
// Create a keyring that encrypts and decrypts using a single AWS KMS CMK.
71+
final Keyring singleCmkKeyring = StandardKeyrings.awsKms(awsKmsCmk);
72+
73+
// Create an AWS KMS discovery keyring that will attempt to decrypt
74+
// any data keys that were encrypted under an AWS KMS CMK.
75+
final Keyring discoveryKeyring = StandardKeyrings.awsKmsDiscoveryBuilder().build();
76+
77+
// Combine the single-CMK and discovery keyrings
78+
// to create a keyring that behaves like an AWS KMS master key provider.
79+
final Keyring keyring = StandardKeyrings.multi(singleCmkKeyring, discoveryKeyring);
80+
81+
// Encrypt your plaintext data.
82+
final AwsCryptoResult<byte[]> encryptResult = awsEncryptionSdk.encrypt(
83+
EncryptRequest.builder()
84+
.keyring(keyring)
85+
.encryptionContext(encryptionContext)
86+
.plaintext(sourcePlaintext).build());
87+
final byte[] ciphertext = encryptResult.getResult();
88+
89+
// Demonstrate that the ciphertext and plaintext are different.
90+
assert !Arrays.equals(ciphertext, sourcePlaintext);
91+
92+
// Decrypt your encrypted data using the same keyring you used on encrypt.
93+
//
94+
// You do not need to specify the encryption context on decrypt because
95+
// the header of the encrypted message includes the encryption context.
96+
final AwsCryptoResult<byte[]> decryptResult = awsEncryptionSdk.decrypt(
97+
DecryptRequest.builder()
98+
.keyring(keyring)
99+
.ciphertext(ciphertext).build());
100+
final byte[] decrypted = decryptResult.getResult();
101+
102+
// Demonstrate that the decrypted plaintext is identical to the original plaintext.
103+
assert Arrays.equals(decrypted, sourcePlaintext);
104+
105+
// Verify that the encryption context used in the decrypt operation includes
106+
// the encryption context that you specified when encrypting.
107+
// The AWS Encryption SDK can add pairs, so don't require an exact match.
108+
//
109+
// In production, always use a meaningful encryption context.
110+
encryptionContext.forEach((k, v) -> {
111+
assert v.equals(decryptResult.getEncryptionContext().get(k));
112+
});
113+
}
114+
}

0 commit comments

Comments
 (0)