Configuring the AWS Encryption SDK - AWS Encryption SDK

Configuring the AWS Encryption SDK

The AWS Encryption SDK is designed to be easy to use. Although the AWS Encryption SDK has several configuration options, the default values are carefully chosen to be practical and secure for most applications. However, you might need to adjust your configuration to improve performance or include a custom feature in your design.

When configuring your implementation, review the AWS Encryption SDK best practices and implement as many as you can.

Select a programming language

The AWS Encryption SDK is available in multiple programming languages. The language implementations are designed to be fully interoperable and to offer the same features, although they might be implemented in different ways. Typically, you use the library that is compatible with your application. However, you might select a programming language for a particular implementation. For example, if you prefer to work with keyrings, you might choose the AWS Encryption SDK for C or the AWS Encryption SDK for JavaScript.

Select wrapping keys

The AWS Encryption SDK generates a unique symmetric data key to encrypt each message. Unless you are using data key caching, you don't need to configure, manage, or use the data keys. The AWS Encryption SDK does it for you.

However, you must select one or more wrapping keys to encrypt each data key. The AWS Encryption SDK supports AES symmetric keys and RSA asymmetric keys in different sizes. It also supports AWS Key Management Service (AWS KMS) symmetric AWS KMS keys. You are responsible for the safety and durability of your wrapping keys, so we recommend that you use an encryption key in a hardware security module or a key infrastructure service, such as AWS KMS.

To specify your wrapping keys for encryption and decryption, you use a keyring (C and JavaScript) or a master key provider (Java and Python). You can specify one wrapping key or multiple wrapping keys of the same or different types. If you use multiple wrapping keys to wrap a data key, each wrapping key will encrypt a copy of the same data key. The encrypted data keys (one per wrapping key) are stored with the encrypted data in the encrypted message that the AWS Encryption SDK returns. To decrypt the data, the AWS Encryption SDK must first use one of your wrapping keys to decrypt an encrypted data key.

To specify an AWS KMS key in a keyring or master key provider, use a supported AWS KMS key identifier. The key identifiers you can use to identify an AWS KMS key in a keyring vary with the operation and the language implementation. For details about the key identifiers for an AWS KMS key, see Key Identifiers in the AWS Key Management Service Developer Guide.

  • When encrypting, you can use a key ARN or alias ARN to identify AWS KMS keys. Some language implementations allow other formats.

  • When decrypting, you must use a key ARN to identify AWS KMS keys. This requirement applies to all language implementations of the AWS Encryption SDK. For details, see Specifying wrapping keys.

If you specify an alias name or alias ARN for a KMS key when encrypting, the AWS Encryption SDK saves the key ARN currently associated with that alias; it does not save the alias. Changes to the alias don't affect the KMS key used to decrypt your data keys.

Use multi-Region AWS KMS keys

You can use AWS Key Management Service (AWS KMS) multi-Region keys as wrapping keys in the AWS Encryption SDK. If you encrypt with a multi-Region key in one AWS Region, you can decrypt using a related multi-Region key in a different AWS Region. Support for multi-Region keys is introduced in version 2.3.x of the AWS Encryption SDK and version 3.0.x of the AWS Encryption CLI.

AWS KMS multi-Region keys are a set of AWS KMS keys in different AWS Regions that have the same key material and key ID. You can use these related keys as though they were the same key in different Regions. Multi-Region keys support common disaster recovery and backup scenarios that require encrypting in one Region and decrypting in a different Region without making a cross-Region call to AWS KMS. For information about multi-Region keys, see Using multi-Region keys in the AWS Key Management Service Developer Guide.

To support multi-Region keys, the AWS Encryption SDK includes AWS KMS multi-Region-aware keyrings and master key providers. The new multi-Region-aware symbol in each programming language supports both single-Region and multi-Region keys.

  • For single-Region keys, the multi-Region-aware symbol behaves just like the single-Region AWS KMS keyring and master key provider. It attempts to decrypt ciphertext only with the single-Region key that encrypted the data.

  • For multi-Region keys, the multi-Region-aware symbol attempts to decrypt ciphertext with the same multi-Region key that encrypted the data or any related multi-Region key.

You can specify multiple wrapping keys in the multi-Region-aware keyrings and master key providers. However, you can specify only one key from each set of related multi-Region keys. If you specify more than one key identifier with the same key ID, the constructor call fails.

You can also use a multi-Region key with the standard, single-Region AWS KMS keyrings and master key providers. However, you must use the same multi-Region key in the same Region to encrypt and decrypt. The single-Region keyrings and master key providers attempt to decrypt ciphertext only with the keys that encrypted the data.

The following examples show how to encrypt and decrypt data using multi-Region keys and the new multi-Region-aware keyrings and master key providers. These examples encrypt data in the us-east-1 Region and decrypt the data in the us-west-2 Region using related multi-Region keys in each Region. Before running these examples, replace the example multi-Region key ARN with a valid value from your AWS account.

C

To encrypt with a multi-Region key, use the Aws::Cryptosdk::KmsMrkAwareSymmetricKeyring::Builder() method to instantiate the keyring. Specify a multi-Region key.

This simple example does not include an encryption context. For an example that uses an encryption context in C, see Encrypting and decrypting strings.

For a complete example, see kms_multi_region_keys.cpp in the AWS Encryption SDK for C repository on GitHub.

/* Initialize a multi-Region keyring */ const char *mrk_us_east_1 = "arn:aws:kms:us-east-1:111122223333:key/mrk-1234abcd12ab34cd56ef1234567890ab"; struct aws_cryptosdk_keyring *mrk_keyring = Aws::Cryptosdk::KmsMrkAwareSymmetricKeyring::Builder().Build(mrk_us_east_1); /* Create a session; release the keyring */ struct aws_cryptosdk_session *session = aws_cryptosdk_session_new_from_keyring_2(aws_default_allocator(), AWS_CRYPTOSDK_ENCRYPT, mrk_keyring); aws_cryptosdk_session_set_commitment_policy(session, COMMITMENT_POLICY_REQUIRE_ENCRYPT_REQUIRE_DECRYPT); aws_cryptosdk_keyring_release(mrk_keyring); /* Encrypt the data * aws_cryptosdk_session_process_full is designed for non-streaming data */ aws_cryptosdk_session_process_full( session, ciphertext, ciphertext_buf_sz, &ciphertext_len, plaintext, plaintext_len)); /* Clean up the session */ aws_cryptosdk_session_destroy(session);
AWS Encryption CLI

This example encrypts the hello.txt file under a multi-Region key in the us-east-1 Region. Because the example specifies a key ARN with a Region element, this example doesn't use the region attribute of the --wrapping-keys parameter.

When the key ID of the wrapping key doesn't specify a Region, you can use the region attribute of the --wrapping-keys to specify the region, such as --wrapping-keys key=$keyID region=us-east-1.

# To run this example, replace the fictitious key ARN with a valid value. $ mrkUSEast1=arn:aws:kms:us-east-1:111122223333:key/mrk-1234abcd12ab34cd56ef1234567890ab $ aws-encryption-cli --encrypt \ --input hello.txt \ --wrapping-keys key=$mrkUSEast1 \ --metadata-output ~/metadata \ --encryption-context purpose=test \ --commitment-policy require-encrypt-require-decrypt \ --output .
Java

To encrypt with a multi-Region key, instantiate an AwsKmsMrkAwareMasterKeyProvider and specify a multi-Region key.

For a complete example, see BasicMultiRegionKeyEncryptionExample.java in the AWS Encryption SDK for Java repository on GitHub.

//Encrypt in us-east-1 Region // Instantiate the client final AwsCrypto crypto = AwsCrypto.builder() .withCommitmentPolicy(CommitmentPolicy.RequireEncryptRequireDecrypt) .build(); // Multi-Region keys have a distinctive key ID that begins with 'mrk' // Specify a multi-Region key in us-east-1 final String mrkUSEast1 = "arn:aws:kms:us-east-1:111122223333:key/mrk-1234abcd12ab34cd56ef1234567890ab"; // Instantiate an AWS KMS master key provider in strict mode for multi-Region keys // Configure it to encrypt with the multi-Region key in us-east-1 final AwsKmsMrkAwareMasterKeyProvider kmsMrkProvider = AwsKmsMrkAwareMasterKeyProvider .builder() .buildStrict(mrkUSEast1); // Create an encryption context final Map<String, String> encryptionContext = Collections.singletonMap("Purpose", "Test"); // Encrypt your plaintext data final CryptoResult<byte[], AwsKmsMrkAwareMasterKey> encryptResult = crypto.encryptData( kmsMrkProvider, encryptionContext, sourcePlaintext); byte[] ciphertext = encryptResult.getResult();
JavaScript Browser

To encrypt with a multi-Region key, use the buildAwsKmsMrkAwareStrictMultiKeyringBrowser() method to create the keyring and specify a multi-Region key.

For a complete example, see kms_multi_region_simple.ts in the AWS Encryption SDK for JavaScript repository on GitHub.

import { buildAwsKmsMrkAwareStrictMultiKeyringBrowser, buildClient, CommitmentPolicy, KMS, } from '@aws-crypto/client-browser' /* Instantiate an AWS Encryption SDK client */ const { encrypt } = buildClient( CommitmentPolicy.REQUIRE_ENCRYPT_REQUIRE_DECRYPT ) declare const credentials: { accessKeyId: string secretAccessKey: string sessionToken: string } /* Instantiate an AWS KMS client * The AWS Encryption SDK for JavaScript gets the Region from the key ARN */ const clientProvider = (region: string) => new KMS({ region, credentials }) /* Specify a multi-Region key in us-east-1 */ const multiRegionUsEastKey = 'arn:aws:kms:us-east-1:111122223333:key/mrk-1234abcd12ab34cd56ef1234567890ab' /* Instantiate the keyring */ const encryptKeyring = buildAwsKmsMrkAwareStrictMultiKeyringBrowser({ generatorKeyId: multiRegionUsEastKey, clientProvider, }) /* Set the encryption context */ const context = { purpose: 'test', } /* Test data to encrypt */ const cleartext = new Uint8Array([1, 2, 3, 4, 5]) /* Encrypt the data */ const { result } = await encrypt(encryptKeyring, cleartext, { encryptionContext: context, })
JavaScript Node.js

To encrypt with a multi-Region key, use the buildAwsKmsMrkAwareStrictMultiKeyringNode() method to create the keyring and specify a multi-Region key.

For a complete example, see kms_multi_region_simple.ts in the AWS Encryption SDK for JavaScript repository on GitHub.

import { buildClient } from '@aws-crypto/client-node' /* Instantiate the AWS Encryption SDK client const { encrypt } = buildClient( CommitmentPolicy.REQUIRE_ENCRYPT_REQUIRE_DECRYPT ) /* Test string to encrypt */ const cleartext = 'asdf' /* Multi-Region keys have a distinctive key ID that begins with 'mrk' * Specify a multi-Region key in us-east-1 */ const multiRegionUsEastKey = 'arn:aws:kms:us-east-1:111122223333:key/mrk-1234abcd12ab34cd56ef1234567890ab' /* Create an AWS KMS keyring */ const mrkEncryptKeyring = buildAwsKmsMrkAwareStrictMultiKeyringNode({ generatorKeyId: multiRegionUsEastKey, }) /* Specify an encryption context */ const context = { purpose: 'test', } /* Create an encryption keyring */ const { result } = await encrypt(mrkEncryptKeyring, cleartext, { encryptionContext: context, })
Python

To encrypt with an AWS KMS multi-Region key, use the MRKAwareStrictAwsKmsMasterKeyProvider() method and specify a multi-Region key.

For a complete example, see mrk_aware_kms_provider.py in the AWS Encryption SDK for Python repository on GitHub.

# Instantiate the client client = aws_encryption_sdk.EncryptionSDKClient(commitment_policy=CommitmentPolicy.REQUIRE_ENCRYPT_REQUIRE_DECRYPT) # Specify a multi-Region key in us-east-1 mrk_us_east_1 = "arn:aws:kms:us-east-1:111122223333:key/mrk-1234abcd12ab34cd56ef1234567890ab" # Use the multi-Region method to create the master key provider # in strict mode strict_mrk_key_provider = MRKAwareStrictAwsKmsMasterKeyProvider( key_ids=[mrk_us_east_1] ) # Set the encryption context encryption_context = { "purpose": "test" } # Encrypt your plaintext data ciphertext, encrypt_header = client.encrypt( source=source_plaintext, encryption_context=encryption_context, key_provider=strict_mrk_key_provider )

Next, move your ciphertext to the us-west-2 Region. You don't need to re-encrypt the ciphertext.

To decrypt the ciphertext in strict mode in the us-west-2 Region, instantiate the multi-Region-aware symbol with the key ARN of the related multi-Region key in the us-west-2 Region. If you specify the key ARN of a related multi-Region key in a different Region (including us-east-1, where it was encrypted), the multi-Region-aware symbol will make a cross-Region call for that AWS KMS key.

When decrypting in strict mode, the multi-Region-aware symbol requires a key ARN. It accepts only one key ARN from each set of related multi-Region keys.

Before running these examples, replace the example multi-Region key ARN with a valid value from your AWS account.

C

To decrypt in strict mode with a multi-Region key, use the Aws::Cryptosdk::KmsMrkAwareSymmetricKeyring::Builder() method to instantiate the keyring. Specify the related multi-Region key in the local (us-west-2) Region.

For a complete example, see kms_multi_region_keys.cpp in the AWS Encryption SDK for C repository on GitHub.

/* Initialize a multi-Region keyring */ const char *mrk_us_west_2 = "arn:aws:kms:us-west-2:111122223333:key/mrk-1234abcd12ab34cd56ef1234567890ab"; struct aws_cryptosdk_keyring *mrk_keyring = Aws::Cryptosdk::KmsMrkAwareSymmetricKeyring::Builder().Build(mrk_us_west_2); /* Create a session; release the keyring */ struct aws_cryptosdk_session *session = aws_cryptosdk_session_new_from_keyring_2(aws_default_allocator(), AWS_CRYPTOSDK_ENCRYPT, mrk_keyring); aws_cryptosdk_session_set_commitment_policy(session, COMMITMENT_POLICY_REQUIRE_ENCRYPT_REQUIRE_DECRYPT); aws_cryptosdk_keyring_release(mrk_keyring); /* Decrypt the ciphertext * aws_cryptosdk_session_process_full is designed for non-streaming data */ aws_cryptosdk_session_process_full( session, plaintext, plaintext_buf_sz, &plaintext_len, ciphertext, ciphertext_len)); /* Clean up the session */ aws_cryptosdk_session_destroy(session);
AWS Encryption CLI

To decrypt with the related multi-Region key in the us-west-2 Region, use the key attribute of the --wrapping-keys parameter to specify its key ARN.

# To run this example, replace the fictitious key ARN with a valid value. $ mrkUSWest2=arn:aws:kms:us-west-2:111122223333:key/mrk-1234abcd12ab34cd56ef1234567890ab $ aws-encryption-cli --decrypt \ --input hello.txt.encrypted \ --wrapping-keys key=$mrkUSWest2 \ --commitment-policy require-encrypt-require-decrypt \ --encryption-context purpose=test \ --metadata-output ~/metadata \ --max-encrypted-data-keys 1 \ --buffer \ --output .
Java

To decrypt in strict mode, instantiate an AwsKmsMrkAwareMasterKeyProvider and specify the related multi-Region key in the local (us-west-2) Region.

For a complete example, see BasicMultiRegionKeyEncryptionExample.java in the AWS Encryption SDK for Java repository on GitHub.

// Decrypt in us-west-2 Region // Instantiate the client final AwsCrypto crypto = AwsCrypto.builder() .withCommitmentPolicy(CommitmentPolicy.RequireEncryptRequireDecrypt) .build(); // Related multi-Region keys have the same key ID. Their key ARNs differs only in the Region field. String mrkUSWest2 = "arn:aws:kms:us-west-2:111122223333:key/mrk-1234abcd12ab34cd56ef1234567890ab"; // Use the multi-Region method to create the master key provider // in strict mode AwsKmsMrkAwareMasterKeyProvider kmsMrkProvider = AwsKmsMrkAwareMasterKeyProvider.builder() .buildStrict(mrkUSWest2); // Decrypt your ciphertext CryptoResult<byte[], AwsKmsMrkAwareMasterKey> decryptResult = crypto.decryptData( kmsMrkProvider, ciphertext); byte[] decrypted = decryptResult.getResult();
JavaScript Browser

To decrypt in strict mode, use the buildAwsKmsMrkAwareStrictMultiKeyringBrowser() method to create the keyring and specify the related multi-Region key in the local (us-west-2) Region.

For a complete example, see kms_multi_region_simple.ts in the AWS Encryption SDK for JavaScript repository on GitHub.

import { buildAwsKmsMrkAwareStrictMultiKeyringBrowser, buildClient, CommitmentPolicy, KMS, } from '@aws-crypto/client-browser' /* Instantiate an AWS Encryption SDK client */ const { decrypt } = buildClient( CommitmentPolicy.REQUIRE_ENCRYPT_REQUIRE_DECRYPT ) declare const credentials: { accessKeyId: string secretAccessKey: string sessionToken: string } /* Instantiate an AWS KMS client * The AWS Encryption SDK for JavaScript gets the Region from the key ARN */ const clientProvider = (region: string) => new KMS({ region, credentials }) /* Specify a multi-Region key in us-west-2 */ const multiRegionUsWestKey = 'arn:aws:kms:us-west-2:111122223333:key/mrk-1234abcd12ab34cd56ef1234567890ab' /* Instantiate the keyring */ const mrkDecryptKeyring = buildAwsKmsMrkAwareStrictMultiKeyringBrowser({ generatorKeyId: multiRegionUsWestKey, clientProvider, }) /* Decrypt the data */ const { plaintext, messageHeader } = await decrypt(mrkDecryptKeyring, result)
JavaScript Node.js

To decrypt in strict mode, use the buildAwsKmsMrkAwareStrictMultiKeyringNode() method to create the keyring and specify the related multi-Region key in the local (us-west-2) Region.

For a complete example, see kms_multi_region_simple.ts in the AWS Encryption SDK for JavaScript repository on GitHub.

import { buildClient } from '@aws-crypto/client-node' /* Instantiate the client const { decrypt } = buildClient( CommitmentPolicy.REQUIRE_ENCRYPT_REQUIRE_DECRYPT ) /* Multi-Region keys have a distinctive key ID that begins with 'mrk' * Specify a multi-Region key in us-east-1 */ const multiRegionUsWestKey = 'arn:aws:kms:us-west-2:111122223333:key/mrk-1234abcd12ab34cd56ef1234567890ab' /* Create an AWS KMS keyring */ const mrkDecryptKeyring = buildAwsKmsMrkAwareStrictMultiKeyringNode({ generatorKeyId: multiRegionUsWestKey, }) /* Decrypt your ciphertext */ const { plaintext, messageHeader } = await decrypt(decryptKeyring, result)
Python

To decrypt in strict mode, use the MRKAwareStrictAwsKmsMasterKeyProvider() method to create the master key provider. Specify the related multi-Region key in the local (us-west-2) Region.

For a complete example, see mrk_aware_kms_provider.py in the AWS Encryption SDK for Python repository on GitHub.

# Instantiate the client client = aws_encryption_sdk.EncryptionSDKClient(commitment_policy=CommitmentPolicy.REQUIRE_ENCRYPT_REQUIRE_DECRYPT) # Related multi-Region keys have the same key ID. Their key ARNs differs only in the Region field mrk_us_west_2 = "arn:aws:kms:us-west-2:111122223333:key/mrk-1234abcd12ab34cd56ef1234567890ab" # Use the multi-Region method to create the master key provider # in strict mode strict_mrk_key_provider = MRKAwareStrictAwsKmsMasterKeyProvider( key_ids=[mrk_us_west_2] ) # Decrypt your ciphertext plaintext, _ = client.decrypt( source=ciphertext, key_provider=strict_mrk_key_provider )

You can also decrypt in discovery mode with multi-Region keys. When decrypting in discovery mode, you don't specify any AWS KMS keys.

If you encrypted with a multi-Region key, the multi-Region-aware symbol in discovery mode will try to decrypt by using a related multi-Region key in the local Region. If none exists; the call fails. In discovery mode, the AWS Encryption SDK will not attempt a cross-Region call for the multi-Region key used for encryption.

The following example shows how to decrypt with the multi-Region-aware symbol in discovery mode. Because you don't specify an AWS KMS key, the AWS Encryption SDK must get the Region from a different source. When possible, specify the local Region explicitly. Otherwise, the AWS Encryption SDK gets the local Region from the Region configured in the AWS SDK for your programming language.

Before running these examples, replace the example account ID and multi-Region key ARN with valid values from your AWS account.

C

To decrypt in discovery mode with a multi-Region key, use the Aws::Cryptosdk::KmsKeyring::DiscoveryFilter::Builder() method. To specify the local Region, define a ClientConfiguration and specify it in the AWS KMS client.

For a complete example, see kms_multi_region_keys.cpp in the AWS Encryption SDK for C repository on GitHub.

/* Construct a discovery filter for the account and partition. The * filter is optional, but it's a best practice that we recommend. */ const char *account_id = "111122223333"; const char *partition = "aws"; const std::shared_ptr<Aws::Cryptosdk::KmsKeyring::DiscoveryFilter> discovery_filter = Aws::Cryptosdk::KmsKeyring::DiscoveryFilter::Builder(partition).AddAccount(account_id).Build(); /* Create an AWS KMS client in the desired region. */ const char *region = "us-west-2"; Aws::Client::ClientConfiguration client_config; client_config.region = region; const std::shared_ptr<Aws::KMS::KMSClient> kms_client = Aws::MakeShared<Aws::KMS::KMSClient>("AWS_SAMPLE_CODE", client_config); /* Initialize a multi-Region keyring */ const char *mrk_us_west_2 = "arn:aws:kms:us-west-2:111122223333:key/mrk-1234abcd12ab34cd56ef1234567890ab"; struct aws_cryptosdk_keyring *mrk_keyring = Aws::Cryptosdk::KmsMrkAwareSymmetricKeyring::Builder() .WithKmsClient(kms_client) .BuildDiscovery(region, discovery_filter); /* Create a session; release the keyring */ struct aws_cryptosdk_session *session = aws_cryptosdk_session_new_from_keyring_2(aws_default_allocator(), AWS_CRYPTOSDK_DECRYPT, mrk_keyring); aws_cryptosdk_session_set_commitment_policy(session, COMMITMENT_POLICY_REQUIRE_ENCRYPT_REQUIRE_DECRYPT); aws_cryptosdk_keyring_release(mrk_keyring); /* Decrypt the ciphertext * aws_cryptosdk_session_process_full is designed for non-streaming data */ aws_cryptosdk_session_process_full( session, plaintext, plaintext_buf_sz, &plaintext_len, ciphertext, ciphertext_len)); /* Clean up the session */ aws_cryptosdk_session_destroy(session);
AWS Encryption CLI

To decrypt in discovery mode, use the discovery attribute of the --wrapping-keys parameter. The discovery-account and discovery-partition attributes create a discovery filter that is optional, but recommended.

To specify the Region, this command includes the region attribute of the --wrapping-keys parameter.

$ aws-encryption-cli --decrypt \ --input hello.txt.encrypted \ --wrapping-keys discovery=true \ discovery-account=111122223333 \ discovery-partition=aws \ region=us-west-2 \ --commitment-policy require-encrypt-require-decrypt \ --encryption-context purpose=test \ --metadata-output ~/metadata \ --max-encrypted-data-keys 1 \ --buffer \ --output .
Java

To specify the local Region, use the builder().withDiscoveryMrkRegion parameter. Otherwise, the AWS Encryption SDK gets the local Region from the Region configured in the AWS SDK for Java.

For a complete example, see DiscoveryMultiRegionKeyEncryptionExample.java in the AWS Encryption SDK for Java repository on GitHub.

// Decrypt in discovery mode in us-west-2 Region // Instantiate the client final AwsCrypto crypto = AwsCrypto.builder() .withCommitmentPolicy(CommitmentPolicy.RequireEncryptRequireDecrypt) .build(); DiscoveryFilter discoveryFilter = new DiscoveryFilter("aws", 111122223333); AwsKmsMrkAwareMasterKeyProvider mrkDiscoveryProvider = AwsKmsMrkAwareMasterKeyProvider .builder() .withDiscoveryMrkRegion("us-west-2") .buildDiscovery(discoveryFilter); // Decrypt your ciphertext final CryptoResult<byte[], AwsKmsMrkAwareMasterKey> decryptResult = crypto .decryptData(mrkDiscoveryProvider, ciphertext);
JavaScript Browser

To decrypt in discovery mode with a symmetric multi-Region key, use the AwsKmsMrkAwareSymmetricDiscoveryKeyringBrowser() method.

For a complete example, see kms_multi_region_discovery.ts in the AWS Encryption SDK for JavaScript repository on GitHub.

import { AwsKmsMrkAwareSymmetricDiscoveryKeyringBrowser, buildClient, CommitmentPolicy, KMS, } from '@aws-crypto/client-browser' /* Instantiate an AWS Encryption SDK client */ const { decrypt } = buildClient( CommitmentPolicy.REQUIRE_ENCRYPT_REQUIRE_DECRYPT ) declare const credentials: { accessKeyId: string secretAccessKey: string sessionToken: string } /* Instantiate the KMS client with an explicit Region */ const client = new KMS({ region: 'us-west-2', credentials }) /* Create a discovery filter */ const discoveryFilter = { partition: 'aws', accountIDs: ['111122223333'] } /* Create an AWS KMS discovery keyring */ const mrkDiscoveryKeyring = new AwsKmsMrkAwareSymmetricDiscoveryKeyringBrowser({ client, discoveryFilter, }) /* Decrypt the data */ const { plaintext, messageHeader } = await decrypt(mrkDiscoveryKeyring, ciphertext)
JavaScript Node.js

To decrypt in discovery mode with a symmetric multi-Region key, use the AwsKmsMrkAwareSymmetricDiscoveryKeyringNode() method.

For a complete example, see kms_multi_region_discovery.ts in the AWS Encryption SDK for JavaScript repository on GitHub.

import { AwsKmsMrkAwareSymmetricDiscoveryKeyringNode, buildClient, CommitmentPolicy, KMS, } from '@aws-crypto/client-node' /* Instantiate the Encryption SDK client const { decrypt } = buildClient( CommitmentPolicy.REQUIRE_ENCRYPT_REQUIRE_DECRYPT ) /* Instantiate the KMS client with an explicit Region */ const client = new KMS({ region: 'us-west-2' }) /* Create a discovery filter */ const discoveryFilter = { partition: 'aws', accountIDs: ['111122223333'] } /* Create an AWS KMS discovery keyring */ const mrkDiscoveryKeyring = new AwsKmsMrkAwareSymmetricDiscoveryKeyringNode({ client, discoveryFilter, }) /* Decrypt your ciphertext */ const { plaintext, messageHeader } = await decrypt(mrkDiscoveryKeyring, result)
Python

To decrypt in discovery mode with a multi-Region key, use the MRKAwareDiscoveryAwsKmsMasterKeyProvider() method.

For a complete example, see mrk_aware_kms_provider.py in the AWS Encryption SDK for Python repository on GitHub.

# Instantiate the client client = aws_encryption_sdk.EncryptionSDKClient(commitment_policy=CommitmentPolicy.REQUIRE_ENCRYPT_REQUIRE_DECRYPT) # Create the discovery filter and specify the region decrypt_kwargs = dict( discovery_filter=DiscoveryFilter(account_ids="111122223333", partition="aws"), discovery_region="us-west-2", ) # Use the multi-Region method to create the master key provider # in discovery mode mrk_discovery_key_provider = MRKAwareDiscoveryAwsKmsMasterKeyProvider(**decrypt_kwargs) # Decrypt your ciphertext plaintext, _ = client.decrypt( source=ciphertext, key_provider=mrk_discovery_key_provider )

Choosing an algorithm suite

The AWS Encryption SDK supports several symmetric and asymmetric encryption algorithms for encrypting your data keys under the wrapping keys you specify. However, when it uses those data keys to encrypt your data, the AWS Encryption SDK defaults to a recommended algorithm suite that uses the AES-GCM algorithm with key derivation, digital signatures, and key commitment. Although the default algorithm suite is likely to be suitable for most applications, you can choose an alternate algorithm suite. For example, some trust models would be satisfied by an algorithm suite without digital signatures. For information about the algorithm suites that the AWS Encryption SDK supports, see Supported algorithm suites in the AWS Encryption SDK.

The following examples show you how to select an alternate algorithm suite when encrypting. These examples select a recommended AES-GCM algorithm suite with key derivation and key commitment, but without digital signatures. When you encrypt with an algorithm suite that does not include digital signatures, use the unsigned-only decryption mode when decrypting. This mode, which fails if it encounters a signed ciphertext, is most useful when streaming decryption.

C

To specify an alternate algorithm suite in the AWS Encryption SDK for C, you must create a CMM explicitly. Then use the aws_cryptosdk_default_cmm_set_alg_id with the CMM and the selected algorithm suite.

/* Construct an AWS KMS keyring */ struct aws_cryptosdk_keyring *kms_keyring = Aws::Cryptosdk::KmsKeyring::Builder().Build(key_arn); /* To set an alternate algorithm suite, create an cryptographic materials manager (CMM) explicitly */ struct aws_cryptosdk_cmm *cmm = aws_cryptosdk_default_cmm_new(aws_default_allocator(), kms_keyring); aws_cryptosdk_keyring_release(kms_keyring); /* Specify the algorithm suite for the CMM */ aws_cryptosdk_default_cmm_set_alg_id(cmm, ALG_AES256_GCM_HKDF_SHA512_COMMIT_KEY); /* Construct the session with the CMM, then release the CMM reference */ struct aws_cryptosdk_session *session = aws_cryptosdk_session_new_from_cmm_2(alloc, AWS_CRYPTOSDK_ENCRYPT, cmm); aws_cryptosdk_cmm_release(cmm); /* Encrypt the data Use aws_cryptosdk_session_process_full with non-streaming data */ if (AWS_OP_SUCCESS != aws_cryptosdk_session_process_full( session, ciphertext, ciphertext_buf_sz, &ciphertext_len, plaintext, plaintext_len)) { aws_cryptosdk_session_destroy(session); return AWS_OP_ERR; }

When decrypting data that was encrypted without digital signatures, use AWS_CRYPTOSDK_DECRYPT_UNSIGNED. This causes the decrypt to fail if it encounters signed ciphertext.

/* Construct an AWS KMS keyring */ struct aws_cryptosdk_keyring *kms_keyring = Aws::Cryptosdk::KmsKeyring::Builder().Build(key_arn); /* Create a session for decrypting with the AWS KMS keyring Then release the keyring reference */ struct aws_cryptosdk_session *session = aws_cryptosdk_session_new_from_keyring_2(alloc, AWS_CRYPTOSDK_DECRYPT_UNSIGNED, kms_keyring); aws_cryptosdk_keyring_release(kms_keyring); if (!session) { return AWS_OP_ERR; } /* Limit encrypted data keys */ aws_cryptosdk_session_set_max_encrypted_data_keys(session, 1); /* Decrypt Use aws_cryptosdk_session_process_full with non-streaming data */ if (AWS_OP_SUCCESS != aws_cryptosdk_session_process_full( session, plaintext, plaintext_buf_sz, &plaintext_len, ciphertext, ciphertext_len)) { aws_cryptosdk_session_destroy(session); return AWS_OP_ERR; }
AWS Encryption CLI

When encrypting the hello.txt file, this example uses the --algorithm parameter to specify an algorithm suite without digital signatures.

\\ To run this example, replace the fictitious key ARN with a valid value. $ keyArn=arn:aws:kms:us-west-2:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab $ aws-encryption-cli --encrypt \ --input hello.txt \ --wrapping-keys key=$keyArn \ --algorithm AES_256_GCM_HKDF_SHA512_COMMIT_KEY \ --metadata-output ~/metadata \ --encryption-context purpose=test \ --commitment-policy require-encrypt-require-decrypt \ --output hello.txt.encrypted \ --decode

When decrypting, this example uses the --decrypt-unsigned parameter. This parameter is recommended to ensure that you are decrypting unsigned ciphertext, especially with the CLI, which is always streaming input and output.

\\ To run this example, replace the fictitious key ARN with a valid value. $ keyArn=arn:aws:kms:us-west-2:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab $ aws-encryption-cli --decrypt-unsigned \ --input hello.txt.encrypted \ --wrapping-keys key=$keyArn \ --max-encrypted-data-keys 1 \ --commitment-policy require-encrypt-require-decrypt \ --encryption-context purpose=test \ --metadata-output ~/metadata \ --output .
Java

To specify an alternate algorithm suite, use the AwsCrypto.builder().withEncryptionAlgorithm() method. This example specifies an alternate algorithm suite without digital signatures.

// Instantiate the client AwsCrypto crypto = AwsCrypto.builder() .withCommitmentPolicy(CommitmentPolicy.RequireEncryptRequireDecrypt) .withEncryptionAlgorithm(CryptoAlgorithm.ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEY) .build(); String awsKmsKey = "arn:aws:kms:us-west-2:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab"; // Create a master key provider in strict mode KmsMasterKeyProvider masterKeyProvider = KmsMasterKeyProvider.builder() .buildStrict(awsKmsKey); // Create an encryption context to identify this ciphertext Map<String, String> encryptionContext = Collections.singletonMap("Example", "FileStreaming"); // Encrypt your plaintext data CryptoResult<byte[], KmsMasterKey> encryptResult = crypto.encryptData( masterKeyProvider, sourcePlaintext, encryptionContext); byte[] ciphertext = encryptResult.getResult();

When streaming data for decryption, use the createUnsignedMessageDecryptingStream() method to ensure that all ciphertext that you're decrypting is unsigned.

// Decrypt the encrypted message // Instantiate the client AwsCrypto crypto = AwsCrypto.builder() .withCommitmentPolicy(CommitmentPolicy.RequireEncryptRequireDecrypt) .withMaxEncryptedDataKeys(1) .build(); // Create a master key provider in strict mode String awsKmsKey = "arn:aws:kms:us-west-2:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab"; KmsMasterKeyProvider masterKeyProvider = KmsMasterKeyProvider.builder() .buildStrict(awsKmsKey); // Decrypt the encrypted message FileInputStream in = new FileInputStream(srcFile + ".encrypted"); CryptoInputStream<KmsMasterKey> decryptingStream = crypto.createUnsignedMessageDecryptingStream(masterKeyProvider, in); // Return the plaintext data // Write the plaintext data to disk FileOutputStream out = new FileOutputStream(srcFile + ".decrypted"); IOUtils.copy(decryptingStream, out); decryptingStream.close();
JavaScript Browser

To specify an alternate algorithm suite, use the suiteId parameter with an AlgorithmSuiteIdentifier enum value.

// Instantiate the client const { encrypt } = buildClient( CommitmentPolicy.REQUIRE_ENCRYPT_REQUIRE_DECRYPT ) // Specify a KMS key const generatorKeyId = "arn:aws:kms:us-west-2:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab"; // Create a keyring with the KMS key const keyring = new KmsKeyringBrowser({ generatorKeyId }) // Encrypt your plaintext data const { result } = await encrypt(keyring, cleartext, { suiteId: AlgorithmSuiteIdentifier.ALG_AES256_GCM_IV12_TAG16_HKDF_SHA512_COMMIT_KEY, encryptionContext: context, })

When decrypting, use the standard decrypt method. AWS Encryption SDK for JavaScript in the browser doesn't have a decrypt-unsigned mode because the browser doesn't support streaming.

// Decrypt the encrypted message // Instantiate the client const { decrypt } = buildClient( CommitmentPolicy.REQUIRE_ENCRYPT_REQUIRE_DECRYPT ) // Create a keyring with the same KMS key used to encrypt const generatorKeyId = "arn:aws:kms:us-west-2:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab"; const keyring = new KmsKeyringBrowser({ generatorKeyId }) // Decrypt the encrypted message const { plaintext, messageHeader } = await decrypt(keyring, ciphertextMessage)
JavaScript Node.js

To specify an alternate algorithm suite, use the suiteId parameter with an AlgorithmSuiteIdentifier enum value.

// Instantiate the client const { encrypt } = buildClient( CommitmentPolicy.REQUIRE_ENCRYPT_REQUIRE_DECRYPT ) // Specify a KMS key const generatorKeyId = "arn:aws:kms:us-west-2:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab"; // Create a keyring with the KMS key const keyring = new KmsKeyringNode({ generatorKeyId }) // Encrypt your plaintext data const { result } = await encrypt(keyring, cleartext, { suiteId: AlgorithmSuiteIdentifier.ALG_AES256_GCM_IV12_TAG16_HKDF_SHA512_COMMIT_KEY, encryptionContext: context, })

When decrypting data that was encrypted without digital signatures, use decryptUnsignedMessageStream. This method fails if it encounters signed ciphertext.

// Decrypt the encrypted message // Instantiate the client const { decryptUnsignedMessageStream } = buildClient( CommitmentPolicy.REQUIRE_ENCRYPT_REQUIRE_DECRYPT ) // Create a keyring with the same KMS key used to encrypt const generatorKeyId = "arn:aws:kms:us-west-2:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab"; const keyring = new KmsKeyringNode({ generatorKeyId }) // Decrypt the encrypted message const outputStream = createReadStream(filename) .pipe(decryptUnsignedMessageStream(keyring))
Python

To specify an alternate encryption algorithm, use the algorithm parameter with an Algorithm enum value.

# Instantiate a client client = aws_encryption_sdk.EncryptionSDKClient(commitment_policy=CommitmentPolicy.REQUIRE_ENCRYPT_REQUIRE_DECRYPT, max_encrypted_data_keys=1) # Create a master key provider in strict mode aws_kms_key = "arn:aws:kms:us-west-2:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab" aws_kms_strict_master_key_provider = StrictAwsKmsMasterKeyProvider( key_ids=[aws_kms_key] ) # Encrypt the plaintext using an alternate algorithm suite ciphertext, encrypted_message_header = client.encrypt( algorithm=Algorithm.AES_256_GCM_HKDF_SHA512_COMMIT_KEY, source=source_plaintext, key_provider=kms_key_provider )

When decrypting messages that were encrypted without digital signatures, use the decrypt-unsigned streaming mode, especially when decrypting while streaming.

# Decrypt the ciphertext # Instantiate the client client = aws_encryption_sdk.EncryptionSDKClient(commitment_policy=CommitmentPolicy.REQUIRE_ENCRYPT_REQUIRE_DECRYPT, max_encrypted_data_keys=1) # Create a master key provider in strict mode aws_kms_key = "arn:aws:kms:us-west-2:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab" aws_kms_strict_master_key_provider = StrictAwsKmsMasterKeyProvider( key_ids=[aws_kms_key] ) # Decrypt with decrypt-unsigned with open(ciphertext_filename, "rb") as ciphertext, open(cycled_plaintext_filename, "wb") as plaintext: with client.stream(mode="decrypt-unsigned", source=ciphertext, key_provider=master_key_provider) as decryptor: for chunk in decryptor: plaintext.write(chunk) # Verify that the encryption context assert all( pair in decryptor.header.encryption_context.items() for pair in encryptor.header.encryption_context.items() ) return ciphertext_filename, cycled_plaintext_filename

Limit encrypted data keys

You can limit the number of encrypted data keys in an encrypted message. This best practice feature can help you detect a misconfigured keyring when encrypting or a malicious ciphertext when decrypting. It also prevents unnecessary, expensive, and potentially exhaustive calls to your key infrastructure. Limiting encrypted data keys is most valuable when you are decrypting messages from an untrusted source.

Although most encrypted messages have one encrypted data key for each wrapping key used in the encryption, an encrypted message can contain up to 65,535 encrypted data keys. A malicious actor might construct an encrypted message with thousands of encrypted data keys, none of which can be decrypted. As a result, the AWS Encryption SDK would attempt to decrypt each encrypted data key until it exhausted the encrypted data keys in the message.

To limit encrypted data keys, use the MaxEncryptedDataKeys parameter. This parameter is available for all supported programming languages beginning in versions 1.9.x and 2.2.x of the AWS Encryption SDK. It is optional and valid when encrypting and decrypting. The following examples decrypt data that was encrypted under three different wrapping keys. The MaxEncryptedDataKeys value is set to 3.

C
/* Construct an AWS KMS keyring */ struct aws_cryptosdk_keyring *kms_keyring = Aws::Cryptosdk::KmsKeyring::Builder().Build(key_arn1, { key_arn2, key_arn3 }); /* Create a session */ struct aws_cryptosdk_session *session = aws_cryptosdk_session_new_from_keyring_2(alloc, AWS_CRYPTOSDK_DECRYPT, kms_keyring); aws_cryptosdk_keyring_release(kms_keyring); /* Limit encrypted data keys */ aws_cryptosdk_session_set_max_encrypted_data_keys(session, 3); /* Decrypt */ size_t ciphertext_consumed_output; aws_cryptosdk_session_process(session, plaintext_output, plaintext_buf_sz_output, &plaintext_len_output, ciphertext_input, ciphertext_len_input, &ciphertext_consumed_output); assert(aws_cryptosdk_session_is_done(session)); assert(ciphertext_consumed == ciphertext_len);
AWS Encryption CLI
# Decrypt with limited encrypted data keys $ aws-encryption-cli --decrypt \ --input hello.txt.encrypted \ --wrapping-keys key=$key_arn1 key=$key_arn2 key=$key_arn3 \ --buffer \ --max-encrypted-data-keys 3 \ --encryption-context purpose=test \ --metadata-output ~/metadata \ --output .
Java
// Construct a client with limited encrypted data keys final AwsCrypto crypto = AwsCrypto.builder() .withMaxEncryptedDataKeys(3) .build(); // Create an AWS KMS master key provider final KmsMasterKeyProvider keyProvider = KmsMasterKeyProvider.builder() .buildStrict(keyArn1, keyArn2, keyArn3); // Decrypt final CryptoResult<byte[], KmsMasterKey> decryptResult = crypto.decryptData(keyProvider, ciphertext)
JavaScript Browser
// Construct a client with limited encrypted data keys const { encrypt, decrypt } = buildClient({ maxEncryptedDataKeys: 3 }) declare const credentials: { accessKeyId: string secretAccessKey: string sessionToken: string } const clientProvider = getClient(KMS, { credentials: { accessKeyId, secretAccessKey, sessionToken } }) // Create an AWS KMS keyring const keyring = new KmsKeyringBrowser({ clientProvider, keyIds: [keyArn1, keyArn2, keyArn3], }) // Decrypt const { plaintext, messageHeader } = await decrypt(keyring, ciphertext)
JavaScript Node.js
// Construct a client with limited encrypted data keys const { encrypt, decrypt } = buildClient({ maxEncryptedDataKeys: 3 }) // Create an AWS KMS keyring const keyring = new KmsKeyringBrowser({ keyIds: [keyArn1, keyArn2, keyArn3], }) // Decrypt const { plaintext, messageHeader } = await decrypt(keyring, ciphertext)
Python
# Instantiate a client with limited encrypted data keys client = aws_encryption_sdk.EncryptionSDKClient(max_encrypted_data_keys=3) # Create an AWS KMS master key provider master_key_provider = aws_encryption_sdk.StrictAwsKmsMasterKeyProvider( key_ids=[key_arn1, key_arn2, key_arn3]) # Decrypt plaintext, header = client.decrypt(source=ciphertext, key_provider=master_key_provider)

Work with streaming data

When you stream data for decryption, be aware that the AWS Encryption SDK returns decrypted plaintext after the integrity checks are complete, but before the digital signature is verified. To ensure that you don't return or use plaintext until the signature is verified, we recommend that you buffer the streamed plaintext until the entire decryption process is complete.

This issue arises only when you are streaming ciphertext for decryption, and only when you are using an algorithm suite, such as the default algorithm suite, that includes digital signatures.

To make the buffering easier, some AWS Encryption SDK language implementations, such as AWS Encryption SDK for JavaScript in Node.js, include a buffering feature as part of the decrypt method. The AWS Encryption CLI, which always streams input and output introduced a --buffer parameter in versions 1.9.x and 2.2.x. In other language implementations, you can use existing buffering features.

If you are using an algorithm suite without digital signatures, be sure to use the decrypt-unsigned feature in each language implementation. This feature decrypts ciphertext but fails if it encounters signed ciphertext. For details, see Choosing an algorithm suite.

Cache data keys

In general, reusing data keys is discouraged, but the AWS Encryption SDK offers a data key caching option that provides limited reuse of data keys. Data key caching can improve the performance of some applications and reduce calls to your key infrastructure. Before using data key caching in production, adjust the security thresholds, and test to make sure that the benefits outweigh the disadvantages of reusing data keys.