Skip to content

Add master key provider examples #168

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Apr 6, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,26 +28,32 @@ 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
* [with keyrings](./java/com/amazonaws/crypto/examples/keyring/awskms/DiscoveryDecryptWithPreferredRegions.java)
* 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
* [with keyrings](./java/com/amazonaws/crypto/examples/keyring/rawrsa/RawRsaDerEncoded.java)
* 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

Expand Down
Original file line number Diff line number Diff line change
@@ -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.
* <p>
* 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.
* <p>
* This example shows how to configure and use a KMS master key provider to decrypt without provider key IDs.
* <p>
* https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/concepts.html#master-key-provider
* <p>
* For an example of how to use the KMS master key with a single CMK,
* see the {@link SingleCmk} example.
* <p>
* 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<String, String> 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<byte[], KmsMasterKey> 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<byte[], KmsMasterKey> 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));
});
}
}
Original file line number Diff line number Diff line change
@@ -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.
* <p>
* This example shows how to configure and use a KMS master key provider with with CMKs in multiple regions.
* <p>
* https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/concepts.html#master-key-provider
* <p>
* For an example of how to use the KMS master key with a single CMK,
* see the {@link SingleCmk} example.
* <p>
* 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<AwsKmsCmkId> 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<String, String> 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<String> 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<byte[], KmsMasterKey> 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<byte[], KmsMasterKey> decryptResult1 = awsEncryptionSdk.decryptData(
singleCmkMasterKeyThatGenerated,
ciphertext);
final byte[] decrypted1 = decryptResult1.getResult();
final CryptoResult<byte[], KmsMasterKey> 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));
});
}
}
Original file line number Diff line number Diff line change
@@ -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.
* <p>
* This example shows how to configure and use a KMS master key with a single KMS CMK.
* <p>
* https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/concepts.html#master-key-provider
* <p>
* For an example of how to use the KMS master key provider with CMKs in multiple regions,
* see the {@link MultipleRegions} example.
* <p>
* 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<String, String> 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<byte[], KmsMasterKey> 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<byte[], KmsMasterKey> 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));
});
}
}
Loading