Multi-keyrings - AWS Encryption SDK

Multi-keyrings

You can combine keyrings into a multi-keyring. A multi-keyring is a keyring that consists of one or more individual keyrings of the same or a different type. The effect is like using several keyrings in a series. When you use a multi-keyring to encrypt data, any of the wrapping keys in any of its keyrings can decrypt that data.

When you create a multi-keyring to encrypt data, you designate one of the keyrings as the generator keyring. All other keyrings are known as child keyrings. The generator keyring generates and encrypts the plaintext data key. Then, all of the wrapping keys in all of the child keyrings encrypt the same plaintext data key. The multi-keyring returns the plaintext key and one encrypted data key for each wrapping key in the multi-keyring. If the generator keyring is a KMS keyring, the generator key in the AWS KMS keyring generates and encrypts the plaintext key. Then, all additional AWS KMS keys in the AWS KMS keyring, and all wrapping keys in all child keyrings in the multi-keyring, encrypt the same plaintext key.

If you create a multi-keyring with no generator keyring, you can use it by itself to decrypt data, but not to encrypt. Or, to use a multi-keyring with no genertor keyring in encrypt operations, you can specify it as a child keyring in another multi-keyring. A multi-keyring with no generator keyring cannot be designated as the generator keyring in another multi-keyring.

When decrypting, the AWS Encryption SDK uses the keyrings to try to decrypt one of the encrypted data keys. The keyrings are called in the order that they are specified in the multi-keyring. Processing stops as soon as any key in any keyring can decrypt an encrypted data key.

Beginning in version 1.7.x, when an encrypted data key is encrypted under an AWS Key Management Service (AWS KMS) keyring (or master key provider), the AWS Encryption SDK always passes the key ARN of the AWS KMS key to the KeyId parameter of the AWS KMS Decrypt operation. This is an AWS KMS best practice that assures that you decrypt the encrypted data key with the wrapping key you intend to use.

To see a working example of a multi-keyring, see:

To create a multi-keyring, first instantiate the child keyrings. In this example, we use an AWS KMS keyring and a Raw AES keyring, but you can combine any supported keyrings in a multi-keyring.

C
/* Define an AWS KMS keyring. For details, see string.cpp */ struct aws_cryptosdk_keyring *kms_keyring = Aws::Cryptosdk::KmsKeyring::Builder().Build(example_key); // Define a Raw AES keyring. For details, see raw_aes_keyring.c */ struct aws_cryptosdk_keyring *aes_keyring = aws_cryptosdk_raw_aes_keyring_new( alloc, wrapping_key_namespace, wrapping_key_name, wrapping_key, AWS_CRYPTOSDK_AES256);
C# / .NET
// Define an AWS KMS keyring. For details, see AwsKmsKeyringExample.cs. var kmsKeyring = materialProviders.CreateAwsKmsKeyring(createKmsKeyringInput); // Define a Raw AES keyring. For details, see RawAESKeyringExample.cs. var aesKeyring = materialProviders.CreateRawAesKeyring(createAesKeyringInput);
JavaScript Browser

The following example uses the buildClient function to specify the default commitment policy, REQUIRE_ENCRYPT_REQUIRE_DECRYPT. You can also use the buildClient to limit the number of encrypted data keys in an encrypted message. For more information, see Limiting encrypted data keys.

import { KmsKeyringBrowser, KMS, getClient, RawAesKeyringWebCrypto, RawAesWrappingSuiteIdentifier, MultiKeyringWebCrypto, buildClient, CommitmentPolicy, synchronousRandomValues, } from '@aws-crypto/client-browser' const { encrypt, decrypt } = buildClient( CommitmentPolicy.REQUIRE_ENCRYPT_REQUIRE_DECRYPT ) const clientProvider = getClient(KMS, { credentials }) // Define an AWS KMS keyring. For details, see kms_simple.ts. const kmsKeyring = new KmsKeyringBrowser({ generatorKeyId: exampleKey }) // Define a Raw AES keyring. For details, see aes_simple.ts. const aesKeyring = new RawAesKeyringWebCrypto({ keyName, keyNamespace, wrappingSuite, masterKey })
JavaScript Node.js

The following example uses the buildClient function to specify the default commitment policy, REQUIRE_ENCRYPT_REQUIRE_DECRYPT. You can also use the buildClient to limit the number of encrypted data keys in an encrypted message. For more information, see Limiting encrypted data keys.

import { MultiKeyringNode, KmsKeyringNode, RawAesKeyringNode, RawAesWrappingSuiteIdentifier, buildClient, CommitmentPolicy, } from '@aws-crypto/client-node' const { encrypt, decrypt } = buildClient( CommitmentPolicy.REQUIRE_ENCRYPT_REQUIRE_DECRYPT ) // Define an AWS KMS keyring. For details, see kms_simple.ts. const kmsKeyring = new KmsKeyringNode({ generatorKeyId: exampleKey }) // Define a Raw AES keyring. For details, see raw_aes_keyring_node.ts. const aesKeyring = new RawAesKeyringNode({ keyName, keyNamespace, wrappingSuite, unencryptedMasterKey })
Java
// Define the raw AES keyring. final MaterialProviders matProv = MaterialProviders.builder() .MaterialProvidersConfig(MaterialProvidersConfig.builder().build()) .build(); final CreateRawAesKeyringInput createRawAesKeyringInput = CreateRawAesKeyringInput.builder() .keyName("AES_256_012") .keyNamespace("HSM_01") .wrappingKey(AESWrappingKey) .wrappingAlg(AesWrappingAlg.ALG_AES256_GCM_IV12_TAG16) .build(); IKeyring rawAesKeyring = matProv.CreateRawAesKeyring(createRawAesKeyringInput); // Define the AWS KMS keyring. final CreateAwsKmsMrkMultiKeyringInput createAwsKmsMrkMultiKeyringInput = CreateAwsKmsMrkMultiKeyringInput.builder() .generator(kmsKeyArn) .build(); IKeyring awsKmsMrkMultiKeyring = matProv.CreateAwsKmsMrkMultiKeyring(createAwsKmsMrkMultiKeyringInput);
Python

The following example instantiates the AWS Encryption SDK client with the default commitment policy, REQUIRE_ENCRYPT_REQUIRE_DECRYPT.

# Create the AWS KMS keyring kms_client = boto3.client('kms', region_name="us-west-2") mat_prov: AwsCryptographicMaterialProviders = AwsCryptographicMaterialProviders( config=MaterialProvidersConfig() ) kms_keyring_input: CreateAwsKmsKeyringInput = CreateAwsKmsKeyringInput( generator=arn:aws:kms:us-west-2:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab, kms_client=kms_client ) kms_keyring: IKeyring = mat_prov.create_aws_kms_keyring( input=kms_keyring_input ) # Create Raw AES keyring key_name_space = "HSM_01" key_name = "AES_256_012" raw_aes_keyring_input: CreateRawAesKeyringInput = CreateRawAesKeyringInput( key_namespace=key_name_space, key_name=key_name, wrapping_key=AESWrappingKey, wrapping_alg=AesWrappingAlg.ALG_AES256_GCM_IV12_TAG16 ) raw_aes_keyring: IKeyring = mat_prov.create_raw_aes_keyring( input=raw_aes_keyring_input )

Next, create the multi-keyring and specify its generator keyring, if any. In this example, we create a multi-keyring in which the AWS KMS keyring is the generator keyring and the AES keyring is the child keyring.

C

In the multi-keyring constructor in C, you specify only its generator keyring.

struct aws_cryptosdk_keyring *multi_keyring = aws_cryptosdk_multi_keyring_new(alloc, kms_keyring);

To add a child keyring to your multi-keyring, use the aws_cryptosdk_multi_keyring_add_child method. You need to call the method once for each child keyring that you add.

// Add the Raw AES keyring (C only) aws_cryptosdk_multi_keyring_add_child(multi_keyring, aes_keyring);
C# / .NET

The .NET CreateMultiKeyringInput constructor lets you define a generator keyring and child keyrings. The resulting CreateMultiKeyringInput object is immutable.

var createMultiKeyringInput = new CreateMultiKeyringInput { Generator = kmsKeyring, ChildKeyrings = new List<IKeyring>() {aesKeyring} }; var multiKeyring = materialProviders.CreateMultiKeyring(createMultiKeyringInput);
JavaScript Browser

JavaScript multi-keyrings are immutable. The JavaScript multi-keyring constructor lets you specify the generator keyring and multiple child keyrings.

const clientProvider = getClient(KMS, { credentials }) const multiKeyring = new MultiKeyringWebCrypto(generator: kmsKeyring, children: [aesKeyring]);
JavaScript Node.js

JavaScript multi-keyrings are immutable. The JavaScript multi-keyring constructor lets you specify the generator keyring and multiple child keyrings.

const multiKeyring = new MultiKeyringNode(generator: kmsKeyring, children: [aesKeyring]);
Java

The Java CreateMultiKeyringInput constructor lets you define a generator keyring and child keyrings. The resulting createMultiKeyringInput object is immutable.

final CreateMultiKeyringInput createMultiKeyringInput = CreateMultiKeyringInput.builder() .generator(awsKmsMrkMultiKeyring) .childKeyrings(Collections.singletonList(rawAesKeyring)) .build(); IKeyring multiKeyring = matProv.CreateMultiKeyring(createMultiKeyringInput);
Python
multi_keyring_input: CreateMultiKeyringInput = CreateMultiKeyringInput( generator=kms_keyring, child_keyrings=[raw_aes_keyring] ) multi_keyring: IKeyring = mat_prov.create_multi_keyring( input=multi_keyring_input )

Now, you can use the multi-keyring to encrypt and decrypt data.