diff --git a/src/examples/README.md b/src/examples/README.md
index b6e778219..19201887b 100644
--- a/src/examples/README.md
+++ b/src/examples/README.md
@@ -28,10 +28,13 @@ We start with AWS KMS examples, then show how to use other wrapping keys.
* Using AWS Key Management Service (AWS KMS)
* How to use one AWS KMS CMK
* [with keyrings](./java/com/amazonaws/crypto/examples/keyring/awskms/SingleCmk.java)
+ * [with master key providers](./java/com/amazonaws/crypto/examples/masterkeyprovider/awskms/SingleCmk.java)
* How to use multiple AWS KMS CMKs in different regions
* [with keyrings](./java/com/amazonaws/crypto/examples/keyring/awskms/MultipleRegions.java)
+ * [with master key providers](./java/com/amazonaws/crypto/examples/masterkeyprovider/awskms/MultipleRegions.java)
* How to decrypt when you don't know the CMK
* [with keyrings](./java/com/amazonaws/crypto/examples/keyring/awskms/DiscoveryDecrypt.java)
+ * [with master key providers](./java/com/amazonaws/crypto/examples/masterkeyprovider/awskms/DiscoveryDecrypt.java)
* How to decrypt within a region
* [with keyrings](./java/com/amazonaws/crypto/examples/keyring/awskms/DiscoveryDecryptInRegionOnly.java)
* How to decrypt with a preferred region but failover to others
@@ -39,8 +42,10 @@ We start with AWS KMS examples, then show how to use other wrapping keys.
* Using raw wrapping keys
* How to use a raw AES wrapping key
* [with keyrings](./java/com/amazonaws/crypto/examples/keyring/rawaes/RawAes.java)
+ * [with master key providers](./java/com/amazonaws/crypto/examples/masterkeyprovider/rawaes/RawAes.java)
* How to use a raw RSA wrapping key
* [with keyrings](./java/com/amazonaws/crypto/examples/keyring/rawrsa/RawRsa.java)
+ * [with master key providers](./java/com/amazonaws/crypto/examples/masterkeyprovider/rawrsa/RawRsa.java)
* How to encrypt with a raw RSA public key wrapping key without access to the private key
* [with keyrings](./java/com/amazonaws/crypto/examples/keyring/rawrsa/PublicPrivateKeySeparate.java)
* How to use a raw RSA wrapping key when the key is DER encoded
@@ -48,6 +53,7 @@ We start with AWS KMS examples, then show how to use other wrapping keys.
* Combining wrapping keys
* How to combine AWS KMS with an offline escrow key
* [with keyrings](./java/com/amazonaws/crypto/examples/keyring/multi/AwsKmsWithEscrow.java)
+ * [with master key providers](./java/com/amazonaws/crypto/examples/masterkeyprovider/multi/AwsKmsWithEscrow.java)
### Keyrings
diff --git a/src/examples/java/com/amazonaws/crypto/examples/masterkeyprovider/awskms/DiscoveryDecrypt.java b/src/examples/java/com/amazonaws/crypto/examples/masterkeyprovider/awskms/DiscoveryDecrypt.java
new file mode 100644
index 000000000..e16095224
--- /dev/null
+++ b/src/examples/java/com/amazonaws/crypto/examples/masterkeyprovider/awskms/DiscoveryDecrypt.java
@@ -0,0 +1,94 @@
+// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+package com.amazonaws.crypto.examples.masterkeyprovider.awskms;
+
+import com.amazonaws.encryptionsdk.AwsCrypto;
+import com.amazonaws.encryptionsdk.CryptoResult;
+import com.amazonaws.encryptionsdk.kms.AwsKmsCmkId;
+import com.amazonaws.encryptionsdk.kms.KmsMasterKey;
+import com.amazonaws.encryptionsdk.kms.KmsMasterKeyProvider;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * This example is intended to serve as reference material for users migrating away from master key providers.
+ * We recommend using keyrings rather than master key providers.
+ * For examples using keyrings, see the 'examples/keyring' directory.
+ *
+ * The KMS master key provider uses any key IDs that you specify on encrypt,
+ * but attempts to decrypt *any* data keys that were encrypted under a KMS CMK.
+ * This means that you do not need to know which CMKs were used to encrypt a message.
+ *
+ * This example shows how to configure and use a KMS master key provider to decrypt without provider key IDs.
+ *
+ * https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/concepts.html#master-key-provider
+ *
+ * For an example of how to use the KMS master key with a single CMK,
+ * see the {@link SingleCmk} example.
+ *
+ * For an example of how to use the KMS master key provider with CMKs in multiple regions,
+ * see the {@link MultipleRegions} example.
+ */
+public class DiscoveryDecrypt {
+
+ /**
+ * Demonstrate configuring a KMS master key provider for decryption.
+ *
+ * @param awsKmsCmk The ARN of an AWS KMS CMK that protects data keys
+ * @param sourcePlaintext Plaintext to encrypt
+ */
+ public static void run(final AwsKmsCmkId awsKmsCmk, final byte[] sourcePlaintext) {
+ // Instantiate the AWS Encryption SDK.
+ final AwsCrypto awsEncryptionSdk = new AwsCrypto();
+
+ // Prepare your encryption context.
+ // https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/concepts.html#encryption-context
+ final Map encryptionContext = new HashMap<>();
+ encryptionContext.put("encryption", "context");
+ encryptionContext.put("is not", "secret");
+ encryptionContext.put("but adds", "useful metadata");
+ encryptionContext.put("that can help you", "be confident that");
+ encryptionContext.put("the data you are handling", "is what you think it is");
+
+ // Create the master key that determines how your data keys are protected.
+ final KmsMasterKeyProvider encryptMasterKeyProvider = KmsMasterKeyProvider.builder()
+ .withKeysForEncryption(awsKmsCmk.toString()).build();
+
+ // Create a KMS master key provider to use on decrypt.
+ final KmsMasterKeyProvider decryptMasterKeyProvider = KmsMasterKeyProvider.builder().build();
+
+ // Encrypt your plaintext data.
+ final CryptoResult encryptResult = awsEncryptionSdk.encryptData(
+ encryptMasterKeyProvider,
+ sourcePlaintext,
+ encryptionContext);
+ final byte[] ciphertext = encryptResult.getResult();
+
+ // Demonstrate that the ciphertext and plaintext are different.
+ assert !Arrays.equals(ciphertext, sourcePlaintext);
+
+ // Decrypt your encrypted data using the KMS master key provider.
+ //
+ // You do not need to specify the encryption context on decrypt because
+ // the header of the encrypted message includes the encryption context.
+ final CryptoResult decryptResult = awsEncryptionSdk.decryptData(
+ decryptMasterKeyProvider,
+ ciphertext);
+ final byte[] decrypted = decryptResult.getResult();
+
+ // Demonstrate that the decrypted plaintext is identical to the original plaintext.
+ assert Arrays.equals(decrypted, sourcePlaintext);
+
+ // Verify that the encryption context used in the decrypt operation includes
+ // the encryption context that you specified when encrypting.
+ // The AWS Encryption SDK can add pairs, so don't require an exact match.
+ //
+ // In production, always use a meaningful encryption context.
+ encryptionContext.forEach((k, v) -> {
+ assert v.equals(decryptResult.getEncryptionContext().get(k));
+ });
+ }
+}
diff --git a/src/examples/java/com/amazonaws/crypto/examples/masterkeyprovider/awskms/MultipleRegions.java b/src/examples/java/com/amazonaws/crypto/examples/masterkeyprovider/awskms/MultipleRegions.java
new file mode 100644
index 000000000..e5cb68349
--- /dev/null
+++ b/src/examples/java/com/amazonaws/crypto/examples/masterkeyprovider/awskms/MultipleRegions.java
@@ -0,0 +1,114 @@
+// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+package com.amazonaws.crypto.examples.masterkeyprovider.awskms;
+
+import com.amazonaws.encryptionsdk.AwsCrypto;
+import com.amazonaws.encryptionsdk.CryptoResult;
+import com.amazonaws.encryptionsdk.kms.AwsKmsCmkId;
+import com.amazonaws.encryptionsdk.kms.KmsMasterKey;
+import com.amazonaws.encryptionsdk.kms.KmsMasterKeyProvider;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static java.util.stream.Collectors.toList;
+
+/**
+ * This example is intended to serve as reference material for users migrating away from master key providers.
+ * We recommend using keyrings rather than master key providers.
+ * For examples using keyrings, see the 'examples/keyring' directory.
+ *
+ * This example shows how to configure and use a KMS master key provider with with CMKs in multiple regions.
+ *
+ * https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/concepts.html#master-key-provider
+ *
+ * For an example of how to use the KMS master key with a single CMK,
+ * see the {@link SingleCmk} example.
+ *
+ * For an example of how to use the KMS master key provider in discovery mode on decrypt,
+ * see the {@link DiscoveryDecrypt} example.
+ */
+public class MultipleRegions {
+
+ /**
+ * Demonstrate an encrypt/decrypt cycle using a KMS master key provider with CMKs in multiple regions.
+ *
+ * @param awsKmsGeneratorCmk The ARN of an AWS KMS CMK that protects data keys
+ * @param awsKmsAdditionalCmks Additional ARNs of secondary KMS CMKs
+ * @param sourcePlaintext Plaintext to encrypt
+ */
+ public static void run(final AwsKmsCmkId awsKmsGeneratorCmk, final List awsKmsAdditionalCmks, final byte[] sourcePlaintext) {
+ // Instantiate the AWS Encryption SDK.
+ final AwsCrypto awsEncryptionSdk = new AwsCrypto();
+
+ // Prepare your encryption context.
+ // https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/concepts.html#encryption-context
+ final Map encryptionContext = new HashMap<>();
+ encryptionContext.put("encryption", "context");
+ encryptionContext.put("is not", "secret");
+ encryptionContext.put("but adds", "useful metadata");
+ encryptionContext.put("that can help you", "be confident that");
+ encryptionContext.put("the data you are handling", "is what you think it is");
+
+ // Create the master key provider that will encrypt your data keys under all requested CMKs.
+ //
+ // The KMS master key provider generates the data key using the first key ID in the list.
+ final List awsKmsCmks = new ArrayList<>();
+ awsKmsCmks.add(awsKmsGeneratorCmk.toString());
+ awsKmsCmks.addAll(awsKmsAdditionalCmks.stream().map(AwsKmsCmkId::toString).collect(toList()));
+ final KmsMasterKeyProvider masterKeyProvider = KmsMasterKeyProvider.builder()
+ .withKeysForEncryption(awsKmsCmks).build();
+
+ // Create master key providers that each only use one of the CMKs.
+ // We will use these later to demonstrate that any of the CMKs can be used to decrypt the message.
+ final KmsMasterKeyProvider singleCmkMasterKeyThatGenerated = KmsMasterKeyProvider.builder()
+ .withKeysForEncryption(awsKmsGeneratorCmk.toString()).build();
+ final KmsMasterKeyProvider singleCmkMasterKeyThatEncrypted = KmsMasterKeyProvider.builder()
+ .withKeysForEncryption(awsKmsAdditionalCmks.get(0).toString()).build();
+
+ // Encrypt your plaintext data using the master key provider that uses all requests CMKs.
+ final CryptoResult encryptResult = awsEncryptionSdk.encryptData(
+ masterKeyProvider,
+ sourcePlaintext,
+ encryptionContext);
+ final byte[] ciphertext = encryptResult.getResult();
+
+ // Verify that the header contains the expected number of encrypted data keys (EDKs).
+ // It should contain one EDK for each CMK.
+ assert encryptResult.getHeaders().getEncryptedKeyBlobCount() == awsKmsAdditionalCmks.size() + 1;
+
+ // Demonstrate that the ciphertext and plaintext are different.
+ assert !Arrays.equals(ciphertext, sourcePlaintext);
+
+ // Decrypt your encrypted data separately using the single-CMK master keys.
+ //
+ // You do not need to specify the encryption context on decrypt because
+ // the header of the encrypted message includes the encryption context.
+ final CryptoResult decryptResult1 = awsEncryptionSdk.decryptData(
+ singleCmkMasterKeyThatGenerated,
+ ciphertext);
+ final byte[] decrypted1 = decryptResult1.getResult();
+ final CryptoResult decryptResult2 = awsEncryptionSdk.decryptData(
+ singleCmkMasterKeyThatEncrypted,
+ ciphertext);
+ final byte[] decrypted2 = decryptResult2.getResult();
+
+ // Demonstrate that the decrypted plaintext is identical to the original plaintext.
+ assert Arrays.equals(decrypted1, sourcePlaintext);
+ assert Arrays.equals(decrypted2, sourcePlaintext);
+
+ // Verify that the encryption context used in the decrypt operation includes
+ // the encryption context that you specified when encrypting.
+ // The AWS Encryption SDK can add pairs, so don't require an exact match.
+ //
+ // In production, always use a meaningful encryption context.
+ encryptionContext.forEach((k, v) -> {
+ assert v.equals(decryptResult1.getEncryptionContext().get(k));
+ assert v.equals(decryptResult2.getEncryptionContext().get(k));
+ });
+ }
+}
diff --git a/src/examples/java/com/amazonaws/crypto/examples/masterkeyprovider/awskms/SingleCmk.java b/src/examples/java/com/amazonaws/crypto/examples/masterkeyprovider/awskms/SingleCmk.java
new file mode 100644
index 000000000..2ce88f7fd
--- /dev/null
+++ b/src/examples/java/com/amazonaws/crypto/examples/masterkeyprovider/awskms/SingleCmk.java
@@ -0,0 +1,87 @@
+// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+package com.amazonaws.crypto.examples.masterkeyprovider.awskms;
+
+import com.amazonaws.encryptionsdk.AwsCrypto;
+import com.amazonaws.encryptionsdk.CryptoResult;
+import com.amazonaws.encryptionsdk.kms.AwsKmsCmkId;
+import com.amazonaws.encryptionsdk.kms.KmsMasterKey;
+import com.amazonaws.encryptionsdk.kms.KmsMasterKeyProvider;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * This example is intended to serve as reference material for users migrating away from master key providers.
+ * We recommend using keyrings rather than master key providers.
+ * For examples using keyrings, see the 'examples/keyring' directory.
+ *
+ * This example shows how to configure and use a KMS master key with a single KMS CMK.
+ *
+ * https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/concepts.html#master-key-provider
+ *
+ * For an example of how to use the KMS master key provider with CMKs in multiple regions,
+ * see the {@link MultipleRegions} example.
+ *
+ * For an example of how to use the KMS master key provider in discovery mode on decrypt,
+ * see the {@link DiscoveryDecrypt} example.
+ */
+public class SingleCmk {
+
+ /**
+ * Demonstrate an encrypt/decrypt cycle using a KMS master key provider with a single CMK.
+ *
+ * @param awsKmsCmk The ARN of an AWS KMS CMK that protects data keys
+ * @param sourcePlaintext Plaintext to encrypt
+ */
+ public static void run(final AwsKmsCmkId awsKmsCmk, final byte[] sourcePlaintext) {
+ // Instantiate the AWS Encryption SDK.
+ final AwsCrypto awsEncryptionSdk = new AwsCrypto();
+
+ // Prepare your encryption context.
+ // https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/concepts.html#encryption-context
+ final Map encryptionContext = new HashMap<>();
+ encryptionContext.put("encryption", "context");
+ encryptionContext.put("is not", "secret");
+ encryptionContext.put("but adds", "useful metadata");
+ encryptionContext.put("that can help you", "be confident that");
+ encryptionContext.put("the data you are handling", "is what you think it is");
+
+ // Create the master key provider that determines how your data keys are protected.
+ final KmsMasterKeyProvider masterKeyProvider = KmsMasterKeyProvider.builder()
+ .withKeysForEncryption(awsKmsCmk.toString()).build();
+
+ // Encrypt your plaintext data.
+ final CryptoResult encryptResult = awsEncryptionSdk.encryptData(
+ masterKeyProvider,
+ sourcePlaintext,
+ encryptionContext);
+ final byte[] ciphertext = encryptResult.getResult();
+
+ // Demonstrate that the ciphertext and plaintext are different.
+ assert !Arrays.equals(ciphertext, sourcePlaintext);
+
+ // Decrypt your encrypted data using the same master key provider you used on encrypt.
+ //
+ // You do not need to specify the encryption context on decrypt because
+ // the header of the encrypted message includes the encryption context.
+ final CryptoResult decryptResult = awsEncryptionSdk.decryptData(
+ masterKeyProvider,
+ ciphertext);
+ final byte[] decrypted = decryptResult.getResult();
+
+ // Demonstrate that the decrypted plaintext is identical to the original plaintext.
+ assert Arrays.equals(decrypted, sourcePlaintext);
+
+ // Verify that the encryption context used in the decrypt operation includes
+ // the encryption context that you specified when encrypting.
+ // The AWS Encryption SDK can add pairs, so don't require an exact match.
+ //
+ // In production, always use a meaningful encryption context.
+ encryptionContext.forEach((k, v) -> {
+ assert v.equals(decryptResult.getEncryptionContext().get(k));
+ });
+ }
+}
diff --git a/src/examples/java/com/amazonaws/crypto/examples/masterkeyprovider/multi/AwsKmsWithEscrow.java b/src/examples/java/com/amazonaws/crypto/examples/masterkeyprovider/multi/AwsKmsWithEscrow.java
new file mode 100644
index 000000000..425f8cff6
--- /dev/null
+++ b/src/examples/java/com/amazonaws/crypto/examples/masterkeyprovider/multi/AwsKmsWithEscrow.java
@@ -0,0 +1,154 @@
+// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+package com.amazonaws.crypto.examples.masterkeyprovider.multi;
+
+import com.amazonaws.encryptionsdk.AwsCrypto;
+import com.amazonaws.encryptionsdk.CryptoResult;
+import com.amazonaws.encryptionsdk.MasterKeyProvider;
+import com.amazonaws.encryptionsdk.jce.JceMasterKey;
+import com.amazonaws.encryptionsdk.kms.AwsKmsCmkId;
+import com.amazonaws.encryptionsdk.kms.KmsMasterKey;
+import com.amazonaws.encryptionsdk.kms.KmsMasterKeyProvider;
+import com.amazonaws.encryptionsdk.multi.MultipleProviderFactory;
+
+import java.security.GeneralSecurityException;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * This example is intended to serve as reference material for users migrating away from master key providers.
+ * We recommend using keyrings rather than master key providers.
+ * For examples using keyrings, see the 'examples/keyring' directory.
+ *
+ * One use-case that we have seen customers need is
+ * the ability to enjoy the benefits of AWS KMS during normal operation
+ * but retain the ability to decrypt encrypted messages without access to AWS KMS.
+ * This example shows how you can achieve this
+ * by combining a KMS master key with a raw RSA master key.
+ *
+ * https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/concepts.html#master-key-provider
+ *
+ * For more examples of how to use the KMS master key provider, see the
+ * 'masterkeyprovider/awskms' examples'
+ *
+ * For more examples of how to use the raw RSA master key, see the
+ * see the 'masterkeyprovider/rawrsa' examples.
+ *
+ * In this example we generate a RSA keypair
+ * but in practice you would want to keep your private key in an HSM
+ * or other key management system.
+ *
+ * In this example, we use the one-step encrypt and decrypt APIs.
+ */
+public class AwsKmsWithEscrow {
+
+ /**
+ * Demonstrate configuring a master key provider to use an AWS KMS CMK and a RSA wrapping key.
+ *
+ * @param awsKmsCmk The ARN of an AWS KMS CMK that protects data keys
+ * @param sourcePlaintext Plaintext to encrypt
+ */
+ public static void run(final AwsKmsCmkId awsKmsCmk, final byte[] sourcePlaintext) throws GeneralSecurityException {
+ // Instantiate the AWS Encryption SDK.
+ final AwsCrypto awsEncryptionSdk = new AwsCrypto();
+
+ // Prepare your encryption context.
+ // https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/concepts.html#encryption-context
+ final Map encryptionContext = new HashMap<>();
+ encryptionContext.put("encryption", "context");
+ encryptionContext.put("is not", "secret");
+ encryptionContext.put("but adds", "useful metadata");
+ encryptionContext.put("that can help you", "be confident that");
+ encryptionContext.put("the data you are handling", "is what you think it is");
+
+ // Generate an RSA key pair to use with your master key.
+ // In practice, you should get this key from a secure key management system such as an HSM.
+ final KeyPairGenerator kg = KeyPairGenerator.getInstance("RSA");
+ // The National Institute of Standards and Technology (NIST) recommends a minimum of 2048-bit keys for RSA.
+ // https://www.nist.gov/publications/transitioning-use-cryptographic-algorithms-and-key-lengths
+ kg.initialize(4096);
+ final KeyPair keyPair = kg.generateKeyPair();
+
+ // Create the encrypt master key that only has access to the public key.
+ final JceMasterKey escrowEncryptMasterKey = JceMasterKey.getInstance(
+ keyPair.getPublic(),
+ null, // Private key is null
+ // The provider ID and key ID are defined by you
+ // and are used by the raw RSA master key
+ // to determine whether it should attempt to decrypt
+ // an encrypted data key.
+ "some managed raw keys", // provider corresponds to key namespace for keyrings
+ "my RSA wrapping key", // key ID corresponds to key name for keyrings
+ // The padding scheme tells the raw RSA master key
+ // how to use your wrapping key to encrypt data keys.
+ //
+ // We recommend using OAEP_SHA256_MGF1.
+ // You should not use PKCS1 unless you require it for backwards compatibility.
+ "RSA/ECB/OAEPWithSHA-256AndMGF1Padding");
+
+ // Create the decrypt master key that has access to the private key.
+ final JceMasterKey escrowDecryptMasterKey = JceMasterKey.getInstance(
+ null, // Public key is null
+ keyPair.getPrivate(),
+ // The key namespace and key name MUST match the encrypt master key.
+ "some managed raw keys", // provider corresponds to key namespace for keyrings
+ "my RSA wrapping key", // key ID corresponds to key name for keyrings
+ // The wrapping algorithm MUST match the encrypt master key.
+ "RSA/ECB/OAEPWithSHA-256AndMGF1Padding");
+
+
+ // Create the KMS master key that you will use for decryption during normal operations.
+ final KmsMasterKeyProvider kmsMasterKeyProvider = KmsMasterKeyProvider.builder()
+ .withKeysForEncryption(awsKmsCmk.toString()).build();
+
+ // Combine the KMS and escrow providers into a single master key provider.
+ final MasterKeyProvider> masterKeyProvider = MultipleProviderFactory.buildMultiProvider(
+ kmsMasterKeyProvider, escrowEncryptMasterKey);
+
+ // Encrypt your plaintext data using the combined master keys.
+ final CryptoResult encryptResult = awsEncryptionSdk.encryptData(
+ masterKeyProvider,
+ sourcePlaintext,
+ encryptionContext);
+ final byte[] ciphertext = encryptResult.getResult();
+
+ // Verify that the header contains the expected number of encrypted data keys (EDKs).
+ // It should contain one EDK for KMS and one for the escrow key.
+ assert encryptResult.getHeaders().getEncryptedKeyBlobCount() == 2;
+
+ // Demonstrate that the ciphertext and plaintext are different.
+ assert !Arrays.equals(ciphertext, sourcePlaintext);
+
+ // Decrypt your encrypted data separately using the KMS master key provider
+ // and the escrow decrypt master key.
+ //
+ // You do not need to specify the encryption context on decrypt because
+ // the header of the encrypted message includes the encryption context.
+ final CryptoResult decryptedKmsResult = awsEncryptionSdk.decryptData(
+ kmsMasterKeyProvider,
+ ciphertext);
+ final byte[] decryptedKms = decryptedKmsResult.getResult();
+ final CryptoResult decryptedEscrowResult = awsEncryptionSdk.decryptData(
+ escrowDecryptMasterKey,
+ ciphertext);
+ final byte[] decryptedEscrow = decryptedKmsResult.getResult();
+
+ // Demonstrate that the decrypted plaintext is identical to the original plaintext.
+ assert Arrays.equals(decryptedKms, sourcePlaintext);
+ assert Arrays.equals(decryptedEscrow, sourcePlaintext);
+
+ // Verify that the encryption context used in the decrypt operation includes
+ // the encryption context that you specified when encrypting.
+ // The AWS Encryption SDK can add pairs, so don't require an exact match.
+ //
+ // In production, always use a meaningful encryption context.
+ encryptionContext.forEach((k, v) -> {
+ assert v.equals(decryptedKmsResult.getEncryptionContext().get(k));
+ assert v.equals(decryptedEscrowResult.getEncryptionContext().get(k));
+ });
+ }
+}
diff --git a/src/examples/java/com/amazonaws/crypto/examples/masterkeyprovider/rawaes/RawAes.java b/src/examples/java/com/amazonaws/crypto/examples/masterkeyprovider/rawaes/RawAes.java
new file mode 100644
index 000000000..89a8d90cc
--- /dev/null
+++ b/src/examples/java/com/amazonaws/crypto/examples/masterkeyprovider/rawaes/RawAes.java
@@ -0,0 +1,98 @@
+// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+package com.amazonaws.crypto.examples.masterkeyprovider.rawaes;
+
+import com.amazonaws.encryptionsdk.AwsCrypto;
+import com.amazonaws.encryptionsdk.CryptoResult;
+import com.amazonaws.encryptionsdk.jce.JceMasterKey;
+
+import javax.crypto.SecretKey;
+import javax.crypto.spec.SecretKeySpec;
+import java.security.SecureRandom;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * This example is intended to serve as reference material for users migrating away from master key providers.
+ * We recommend using keyrings rather than master key providers.
+ * For examples using keyrings, see the 'examples/keyring' directory.
+ *
+ * This examples shows how to configure and use a raw AES master key.
+ *
+ * https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/concepts.html#master-key-provider
+ *
+ * In this example, we use the one-step encrypt and decrypt APIs.
+ */
+public class RawAes {
+
+ /**
+ * Demonstrate an encrypt/decrypt cycle using a raw AES master key.
+ *
+ * @param sourcePlaintext Plaintext to encrypt
+ */
+ public static void run(final byte[] sourcePlaintext) {
+ // Instantiate the AWS Encryption SDK.
+ final AwsCrypto awsEncryptionSdk = new AwsCrypto();
+
+ // Prepare your encryption context.
+ // https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/concepts.html#encryption-context
+ final Map encryptionContext = new HashMap<>();
+ encryptionContext.put("encryption", "context");
+ encryptionContext.put("is not", "secret");
+ encryptionContext.put("but adds", "useful metadata");
+ encryptionContext.put("that can help you", "be confident that");
+ encryptionContext.put("the data you are handling", "is what you think it is");
+
+ // Generate an AES key to use with your master key.
+ //
+ // In practice, you should get this key from a secure key management system such as an HSM.
+ SecureRandom rnd = new SecureRandom();
+ byte[] rawKey = new byte[32]; // 256 bits
+ rnd.nextBytes(rawKey);
+ SecretKey key = new SecretKeySpec(rawKey, "AES");
+
+ // Create the master key that determines how your data keys are protected.
+ final JceMasterKey masterKey = JceMasterKey.getInstance(
+ // The key namespace and key name are defined by you
+ // and are used by the raw AES master key
+ // to determine whether it should attempt to decrypt
+ // an encrypted data key.
+ key,
+ "some managed raw keys", // provider corresponds to key namespace for keyrings
+ "my AES wrapping key", // key ID corresponds to key name for keyrings
+ "AES/GCM/NOPADDING"); // the AES JceMasterKey only supports AES/GCM/NOPADDING
+
+ // Encrypt your plaintext data.
+ final CryptoResult encryptResult = awsEncryptionSdk.encryptData(
+ masterKey,
+ sourcePlaintext,
+ encryptionContext);
+ final byte[] ciphertext = encryptResult.getResult();
+
+ // Demonstrate that the ciphertext and plaintext are different.
+ assert !Arrays.equals(ciphertext, sourcePlaintext);
+
+ // Decrypt your encrypted data using the same master key you used on encrypt.
+ //
+ // You do not need to specify the encryption context on decrypt because
+ // the header of the encrypted message includes the encryption context.
+ final CryptoResult decryptResult = awsEncryptionSdk.decryptData(
+ masterKey,
+ ciphertext);
+ final byte[] decrypted = decryptResult.getResult();
+
+ // Demonstrate that the decrypted plaintext is identical to the original plaintext.
+ assert Arrays.equals(decrypted, sourcePlaintext);
+
+ // Verify that the encryption context used in the decrypt operation includes
+ // the encryption context that you specified when encrypting.
+ // The AWS Encryption SDK can add pairs, so don't require an exact match.
+ //
+ // In production, always use a meaningful encryption context.
+ encryptionContext.forEach((k, v) -> {
+ assert v.equals(decryptResult.getEncryptionContext().get(k));
+ });
+ }
+}
diff --git a/src/examples/java/com/amazonaws/crypto/examples/masterkeyprovider/rawrsa/RawRsa.java b/src/examples/java/com/amazonaws/crypto/examples/masterkeyprovider/rawrsa/RawRsa.java
new file mode 100644
index 000000000..ff1d972f0
--- /dev/null
+++ b/src/examples/java/com/amazonaws/crypto/examples/masterkeyprovider/rawrsa/RawRsa.java
@@ -0,0 +1,104 @@
+// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+package com.amazonaws.crypto.examples.masterkeyprovider.rawrsa;
+
+import com.amazonaws.encryptionsdk.AwsCrypto;
+import com.amazonaws.encryptionsdk.CryptoResult;
+import com.amazonaws.encryptionsdk.jce.JceMasterKey;
+
+import java.security.GeneralSecurityException;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * This example is intended to serve as reference material for users migrating away from master key providers.
+ * We recommend using keyrings rather than master key providers.
+ * For examples using keyrings, see the 'examples/keyring' directory.
+ *
+ * This examples shows how to configure and use a raw RSA master key using a pre-loaded RSA key pair.
+ *
+ * https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/concepts.html#master-key-provider
+ *
+ * In this example, we use the one-step encrypt and decrypt APIs.
+ */
+public class RawRsa {
+
+ /**
+ * Demonstrate an encrypt/decrypt cycle using a raw RSA master key.
+ *
+ * @param sourcePlaintext Plaintext to encrypt
+ */
+ public static void run(final byte[] sourcePlaintext) throws GeneralSecurityException {
+ // Instantiate the AWS Encryption SDK.
+ final AwsCrypto awsEncryptionSdk = new AwsCrypto();
+
+ // Prepare your encryption context.
+ // https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/concepts.html#encryption-context
+ final Map encryptionContext = new HashMap<>();
+ encryptionContext.put("encryption", "context");
+ encryptionContext.put("is not", "secret");
+ encryptionContext.put("but adds", "useful metadata");
+ encryptionContext.put("that can help you", "be confident that");
+ encryptionContext.put("the data you are handling", "is what you think it is");
+
+ // Generate an RSA key pair to use with your master key.
+ // In practice, you should get this key from a secure key management system such as an HSM.
+ final KeyPairGenerator kg = KeyPairGenerator.getInstance("RSA");
+ // The National Institute of Standards and Technology (NIST) recommends a minimum of 2048-bit keys for RSA.
+ // https://www.nist.gov/publications/transitioning-use-cryptographic-algorithms-and-key-lengths
+ kg.initialize(4096);
+ final KeyPair keyPair = kg.generateKeyPair();
+
+ // Create the master key that determines how your data keys are protected.
+ final JceMasterKey masterKey = JceMasterKey.getInstance(
+ keyPair.getPublic(),
+ keyPair.getPrivate(),
+ // The provider ID and key ID are defined by you
+ // and are used by the raw RSA master key
+ // to determine whether it should attempt to decrypt
+ // an encrypted data key.
+ "some managed raw keys", // provider corresponds to key namespace for keyrings
+ "my RSA wrapping key", // key ID corresponds to key name for keyrings
+ // The padding scheme tells the raw RSA master key
+ // how to use your wrapping key to encrypt data keys.
+ //
+ // We recommend using OAEP_SHA256_MGF1.
+ // You should not use PKCS1 unless you require it for backwards compatibility.
+ "RSA/ECB/OAEPWithSHA-256AndMGF1Padding");
+
+ // Encrypt your plaintext data.
+ final CryptoResult encryptResult = awsEncryptionSdk.encryptData(
+ masterKey,
+ sourcePlaintext,
+ encryptionContext);
+ final byte[] ciphertext = encryptResult.getResult();
+
+ // Demonstrate that the ciphertext and plaintext are different.
+ assert !Arrays.equals(ciphertext, sourcePlaintext);
+
+ // Decrypt your encrypted data using the same master key you used on encrypt.
+ //
+ // You do not need to specify the encryption context on decrypt because
+ // the header of the encrypted message includes the encryption context.
+ final CryptoResult decryptResult = awsEncryptionSdk.decryptData(
+ masterKey,
+ ciphertext);
+ final byte[] decrypted = decryptResult.getResult();
+
+ // Demonstrate that the decrypted plaintext is identical to the original plaintext.
+ assert Arrays.equals(decrypted, sourcePlaintext);
+
+ // Verify that the encryption context used in the decrypt operation includes
+ // the encryption context that you specified when encrypting.
+ // The AWS Encryption SDK can add pairs, so don't require an exact match.
+ //
+ // In production, always use a meaningful encryption context.
+ encryptionContext.forEach((k, v) -> {
+ assert v.equals(decryptResult.getEncryptionContext().get(k));
+ });
+ }
+}