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.