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.
Selecting 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.
Selecting 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 encryption
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, Python, AWS Encryption CLI). 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. For details about the key identifiers for an AWS KMS key, see Key Identifiers in the AWS Key Management Service Developer Guide.
-
When encrypting with the AWS Encryption SDK for Java, AWS Encryption SDK for JavaScript, AWS Encryption SDK for Python, or the
AWS Encryption CLI, you can use any valid key identifier (key ID, key ARN, alias name,
or alias ARN) for a KMS key. When encrypting with the AWS Encryption SDK for C, you can
only use a key ID or key ARN.
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.
-
When decrypting in strict mode (where you specify particular wrapping keys),
you must use a key ARN to identify AWS KMS keys. This requirement applies to
all language implementations of the AWS Encryption SDK.
When you encrypt with an AWS KMS keyring, the AWS Encryption SDK stores the key ARN of
the AWS KMS key in the metadata of the encrypted data key. When decrypting in
strict mode, the AWS Encryption SDK verifies that the same key ARN appears in the
keyring (or master key provider) before it attempts to use the wrapping key to decrypt the
encrypted data key. If you use a different key identifier, the AWS Encryption SDK will
not recognize or use the AWS KMS key, even if the identifiers refer to the
same key.
To specify a raw AES key or a raw RSA key pair as a wrapping key in a
keyring, you must specify a namespace and a name. In a master key provider, the Provider
ID
is the equivalent of the namespace and the Key ID
is the
equivalent of the name. When decrypting, you must use the exact same namespace and name
for each raw wrapping key as you used when encrypting. If you use a different namespace
or name, the AWS Encryption SDK will not recognize or use the wrapping key, even if the key
material is the same.
Using 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 with the related multi-Region
replica key in the Region you specify.
In the multi-Region-aware keyrings and master key providers that take more than one KMS key, you
can specify multiple single-Region and multi-Region keys. However, you can specify only
one key from each set of related multi-Region replica 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 replica 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.
/* Encrypt with a multi-Region KMS key in us-east-1 */
/* Load error strings for debugging */
aws_cryptosdk_load_error_strings();
/* 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_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);
- C# / .NET
-
To encrypt with a multi-Region key in the US East (N. Virginia) (us-east-1)
Region, instantiate a CreateAwsKmsMrkKeyringInput
object with a
key identifier for the multi-Region key and an AWS KMS client for the
specified Region. Then use the CreateAwsKmsMrkKeyring()
method
to create the keyring.
The CreateAwsKmsMrkKeyring()
method creates a keyring with
exactly one multi-Region key. To encrypt with multiple wrapping keys,
including a multi-Region key, use the
CreateAwsKmsMrkMultiKeyring()
method.
For a complete example, see AwsKmsMrkKeyringExample.cs in the AWS Encryption SDK for .NET repository on
GitHub.
//Encrypt with a multi-Region KMS key in us-east-1 Region
// Instantiate the AWS Encryption SDK and material providers
var encryptionSdk = AwsEncryptionSdkFactory.CreateDefaultAwsEncryptionSdk();
var materialProviders =
AwsCryptographicMaterialProvidersFactory.CreateDefaultAwsCryptographicMaterialProviders();
// Multi-Region keys have a distinctive key ID that begins with 'mrk'
// Specify a multi-Region key in us-east-1
string mrkUSEast1 = "arn:aws:kms:us-east-1:111122223333:key/mrk-1234abcd12ab34cd56ef1234567890ab";
// Create the keyring
// You can specify the Region or get the Region from the key ARN
var createMrkEncryptKeyringInput = new CreateAwsKmsMrkKeyringInput
{
KmsClient = new AmazonKeyManagementServiceClient(RegionEndpoint.USEast1),
KmsKeyId = mrkUSEast1
};
var mrkEncryptKeyring = materialProviders.CreateAwsKmsMrkKeyring(createMrkEncryptKeyringInput);
// Define the encryption context
var encryptionContext = new Dictionary<string, string>()
{
{"purpose", "test"}
};
// Encrypt your plaintext data.
var encryptInput = new EncryptInput
{
Plaintext = plaintext,
Keyring = mrkEncryptKeyring,
EncryptionContext = encryptionContext
};
var encryptOutput = encryptionSdk.Encrypt(encryptInput);
- 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
.
# Encrypt with a multi-Region KMS key in us-east-1 Region
# 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 \
--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 with a multi-Region KMS key 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.
/* Encrypt with a multi-Region KMS key in us-east-1 Region */
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.
//Encrypt with a multi-Region KMS key in us-east-1 Region
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.
* Encrypt with a multi-Region KMS key in us-east-1 Region
# 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.
/* Decrypt with a related multi-Region KMS key in us-west-2 Region */
/* Load error strings for debugging */
aws_cryptosdk_load_error_strings();
/* 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);
- C# / .NET
-
To decrypt in strict mode with a single multi-Region key, use the same
constructors and methods that you used to assemble the input and create the
keyring for encrypting. Instantiate a
CreateAwsKmsMrkKeyringInput
object with the key ARN of a
related multi-Region key and an AWS KMS client for the US West (Oregon)
(us-west-2) Region. Then use the CreateAwsKmsMrkKeyring()
method to create a multi-Region keyring with one multi-Region
KMS key.
For a complete example, see AwsKmsMrkKeyringExample.cs in the AWS Encryption SDK for .NET repository on
GitHub.
// Decrypt with a related multi-Region KMS key in us-west-2 Region
// Instantiate the AWS Encryption SDK and material providers
var encryptionSdk = AwsEncryptionSdkFactory.CreateDefaultAwsEncryptionSdk();
var materialProviders =
AwsCryptographicMaterialProvidersFactory.CreateDefaultAwsCryptographicMaterialProviders();
// Specify the key ARN of the multi-Region key in us-west-2
string mrkUSWest2 = "arn:aws:kms:us-west-2:111122223333:key/mrk-1234abcd12ab34cd56ef1234567890ab";
// Instantiate the keyring input
// You can specify the Region or get the Region from the key ARN
var createMrkDecryptKeyringInput = new CreateAwsKmsMrkKeyringInput
{
KmsClient = new AmazonKeyManagementServiceClient(RegionEndpoint.USWest2),
KmsKeyId = mrkUSWest2
};
// Create the multi-Region keyring
var mrkDecryptKeyring = materialProviders.CreateAwsKmsMrkKeyring(createMrkDecryptKeyringInput);
// Decrypt the ciphertext
var decryptInput = new DecryptInput
{
Ciphertext = ciphertext,
Keyring = mrkDecryptKeyring
};
var decryptOutput = encryptionSdk.Decrypt(decryptInput);
- 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.
# Decrypt with a related multi-Region KMS key in us-west-2 Region
# 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 with a related multi-Region KMS key 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.
/* Decrypt with a related multi-Region KMS key in us-west-2 Region */
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.
/* Decrypt with a related multi-Region KMS key in us-west-2 Region */
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-west-2
*/
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.
# Decrypt with a related multi-Region KMS key in us-west-2 Region
# 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 AWS KMS
multi-Region keys. When decrypting in discovery mode, you don't specify any
AWS KMS keys. (For information about single-Region AWS KMS discovery keyrings, see
Using an AWS KMS discovery keyring.)
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.
If you use a multi-Region-aware symbol in discovery mode to encrypt data, the encrypt operation
fails.
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::KmsMrkAwareSymmetricKeyring::Builder()
method to build the keyring, and the
Aws::Cryptosdk::KmsKeyring::DiscoveryFilter::Builder()
method to build the discovery filter. 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.
/* Decrypt in discovery mode with a multi-Region KMS key */
/* Load error strings for debugging */
aws_cryptosdk_load_error_strings();
/* 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);
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_keyring_release(mrk_keyring);
commitment_policy=CommitmentPolicy.REQUIRE_ENCRYPT_REQUIRE_DECRYPT
/* 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);
- C# / .NET
-
To create a multi-Region-aware discovery keyring in the AWS Encryption SDK for .NET,
instantiate a CreateAwsKmsMrkDiscoveryKeyringInput
object that
takes an AWS KMS client for a particular AWS Region, and an optional
discovery filter that limits KMS keys to a particular AWS partition and
account. Then call the CreateAwsKmsMrkDiscoveryKeyring()
method
with the input object. For a complete example, see AwsKmsMrkDiscoveryKeyringExample.cs in the AWS Encryption SDK for .NET
repository on GitHub.
To create a multi-Region-aware discovery keyring for more than one
AWS Region, use the CreateAwsKmsMrkDiscoveryMultiKeyring()
method to create a multi-keyring, or use
CreateAwsKmsMrkDiscoveryKeyring()
to create several
multi-Region-aware discovery keyrings and then use the
CreateMultiKeyring()
method to combine them in a
multi-keyring.
For an example, see AwsKmsMrkDiscoveryMultiKeyringExample.cs.
// Decrypt in discovery mode with a multi-Region KMS key
// Instantiate the AWS Encryption SDK and material providers
var encryptionSdk = AwsEncryptionSdkFactory.CreateDefaultAwsEncryptionSdk();
var materialProviders =
AwsCryptographicMaterialProvidersFactory.CreateDefaultAwsCryptographicMaterialProviders();
List<string> account = new List<string> { "111122223333
" };
// Instantiate the discovery filter
DiscoveryFilter mrkDiscoveryFilter = new DiscoveryFilter()
{
AccountIds = account,
Partition = "aws"
}
// Create the keyring
var createMrkDiscoveryKeyringInput = new CreateAwsKmsMrkDiscoveryKeyringInput
{
KmsClient = new AmazonKeyManagementServiceClient(RegionEndpoint.USWest2),
DiscoveryFilter = mrkDiscoveryFilter
};
var mrkDiscoveryKeyring = materialProviders.CreateAwsKmsMrkDiscoveryKeyring(createMrkDiscoveryKeyringInput);
// Decrypt the ciphertext
var decryptInput = new DecryptInput
{
Ciphertext = ciphertext,
Keyring = mrkDiscoveryKeyring
};
var decryptOutput = encryptionSdk.Decrypt(decryptInput);
- 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.
# Decrypt in discovery mode with a multi-Region KMS key
$ aws-encryption-cli --decrypt \
--input hello.txt.encrypted \
--wrapping-keys discovery=true \
discovery-account=111122223333 \
discovery-partition=aws \
region=us-west-2 \
--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 DiscoveryMultiRegionDecryptionExample.java in the
AWS Encryption SDK for Java repository on GitHub.
// Decrypt in discovery mode with a multi-Region KMS key
// Instantiate the client
final AwsCrypto crypto = AwsCrypto.builder()
.withCommitmentPolicy(CommitmentPolicy.RequireEncryptRequireDecrypt)
.build();
DiscoveryFilter discoveryFilter = new DiscoveryFilter("aws", 111122223333);
AwsKmsMrkAwareMasterKeyProvider mrkDiscoveryProvider = AwsKmsMrkAwareMasterKeyProvider
.builder()
.withDiscoveryMrkRegion(Region.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.
/* Decrypt in discovery mode with a multi-Region KMS key */
import {
AwsKmsMrkAwareSymmetricDiscoveryKeyringBrowser,
buildClient,
CommitmentPolicy,
KMS,
} from '@aws-crypto/client-browser'
/* Instantiate an AWS Encryption SDK client */
const { decrypt } = buildClient()
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.
/* Decrypt in discovery mode with a multi-Region KMS key */
import {
AwsKmsMrkAwareSymmetricDiscoveryKeyringNode,
buildClient,
CommitmentPolicy,
KMS,
} from '@aws-crypto/client-node'
/* Instantiate the Encryption SDK client
const { decrypt } = buildClient()
/* 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.
# Decrypt in discovery mode with a multi-Region KMS key
# Instantiate the client
client = aws_encryption_sdk.EncryptionSDKClient()
# 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.
/* Specify an algorithm suite without signing */
/* Load error strings for debugging */
aws_cryptosdk_load_error_strings();
/* 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.
/* Decrypt unsigned streaming data */
/* Load error strings for debugging */
aws_cryptosdk_load_error_strings();
/* 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;
}
- C# / .NET
-
To specify an alternate algorithm suite in the AWS Encryption SDK for .NET, specify the
AlgorithmSuiteId
property of an EncryptInput object. The AWS Encryption SDK for .NET includes constants that you can use to identify your preferred algorithm
suite.
The AWS Encryption SDK for .NET doesn't have a method to detect signed ciphertext when
streaming decryption because this library doesn't support streaming
data.
// Specify an algorithm suite without signing
// Instantiate the AWS Encryption SDK and material providers
var encryptionSdk = AwsEncryptionSdkFactory.CreateDefaultAwsEncryptionSdk();
var materialProviders =
AwsCryptographicMaterialProvidersFactory.CreateDefaultAwsCryptographicMaterialProviders();
// Create the keyring
var keyringInput = new CreateAwsKmsKeyringInput
{
KmsClient = new AmazonKeyManagementServiceClient(),
KmsKeyId = keyArn
};
var keyring = materialProviders.CreateAwsKmsKeyring(keyringInput);
// Encrypt your plaintext data
var encryptInput = new EncryptInput
{
Plaintext = plaintext,
Keyring = keyring,
AlgorithmSuiteId = AlgorithmSuiteId.ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEY
};
var encryptOutput = encryptionSdk.Encrypt(encryptInput);
- AWS Encryption CLI
-
When encrypting the hello.txt
file, this example uses the
--algorithm
parameter to specify an algorithm suite without
digital signatures.
# Specify an algorithm suite without signing
# 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.
# Decrypt unsigned streaming data
# 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.
// Specify an algorithm suite without signing
// 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 unsigned streaming data
// 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.
// Specify an algorithm suite without signing
// 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 unsigned streaming data
// 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.
// Specify an algorithm suite without signing
// 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 unsigned streaming data
// 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.
# Specify an algorithm suite without signing
# 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 unsigned streaming data
# 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
Limiting 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
-
/* Load error strings for debugging */
aws_cryptosdk_load_error_strings();
/* 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);
- C# / .NET
-
To limit encrypted data keys in the AWS Encryption SDK for .NET, instantiate a client
for the AWS Encryption SDK for .NET and set its optional
MaxEncryptedDataKeys
parameter to the desired value. Then,
call the Decrypt()
method on the configured AWS Encryption SDK
instance.
// Decrypt with limited data keys
// Instantiate the material providers
var materialProviders =
AwsCryptographicMaterialProvidersFactory.CreateDefaultAwsCryptographicMaterialProviders();
// Configure the commitment policy on the AWS Encryption SDK instance
var config = new AwsEncryptionSdkConfig
{
MaxEncryptedDataKeys = 3
};
var encryptionSdk = AwsEncryptionSdkFactory.CreateAwsEncryptionSdk(config);
// Create the keyring
string keyArn = "arn:aws:kms:us-west-2:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab
";
var createKeyringInput = new CreateAwsKmsKeyringInput
{
KmsClient = new AmazonKeyManagementServiceClient(),
KmsKeyId = keyArn
};
var decryptKeyring = materialProviders.CreateAwsKmsKeyring(createKeyringInput);
// Decrypt the ciphertext
var decryptInput = new DecryptInput
{
Ciphertext = ciphertext,
Keyring = decryptKeyring
};
var decryptOutput = encryptionSdk.Decrypt(decryptInput);
- 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)
Creating a discovery filter
When decrypting data encrypted with KMS keys, it's a best practice to decrypt in
strict mode, that is, to limit the wrapping keys used to only
those that you specify. However, if necessary, you can also decrypt in
discovery mode, where you don't specify any wrapping keys. In
this mode, AWS KMS can decrypt the encrypted data key using the KMS key that encrypted
it, regardless of who owns or has access to that KMS key.
If you must decrypt in discovery mode, we recommend that you always use a
discovery filter, which limits the KMS keys that can be used
to those in a specified AWS account and partition. The discovery filter is optional, but it's a best
practice.
Use the following table to determine the partition value for your discovery
filter.
Region |
Partition |
AWS Regions |
aws |
China Regions |
aws-cn |
AWS GovCloud (US) Regions |
aws-us-gov |
The examples in this section show how to create a discovery filter. Before using the
code, replace the example values with valid values for the AWS account and
partition.
- C
-
For a complete examples, see kms_discovery.cpp in the AWS Encryption SDK for C.
/* Create a discovery filter for an AWS account and partition */
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();
- C# / .NET
-
For a complete example, see DiscoveryFilterExample.cs in the AWS Encryption SDK for .NET.
// Create a discovery filter for an AWS account and partition
List<string> account = new List<string> { "111122223333
" };
DiscoveryFilter exampleDiscoveryFilter = new DiscoveryFilter()
{
AccountIds = account,
Partition = "aws
"
}
- AWS Encryption CLI
-
# Decrypt in discovery mode with a discovery filter
$ aws-encryption-cli --decrypt \
--input hello.txt.encrypted \
--wrapping-keys discovery=true \
discovery-account=111122223333
\
discovery-partition=aws
\
--encryption-context purpose=test \
--metadata-output ~/metadata \
--max-encrypted-data-keys 1 \
--buffer \
--output .
- Java
-
For a complete example, see DiscoveryDecryptionExample.java in the AWS Encryption SDK for Java.
// Create a discovery filter for an AWS account and partition
DiscoveryFilter discoveryFilter = new DiscoveryFilter("aws
", 111122223333
);
- JavaScript (Node and Browser)
-
For complete examples, see kms_filtered_discovery.ts (Node.js) and kms_multi_region_discovery.ts (Browser) in the
AWS Encryption SDK for JavaScript.
/* Create a discovery filter for an AWS account and partition */
const discoveryFilter = {
accountIDs: ['111122223333
'],
partition: 'aws
',
}
- Python
-
For a complete example, see discovery_kms_provider.py in the AWS Encryption SDK for Python.
# Create the discovery filter and specify the region
decrypt_kwargs = dict(
discovery_filter=DiscoveryFilter(account_ids="111122223333
", partition="aws
"),
discovery_region="us-west-2
",
)
Setting a commitment policy
A commitment
policy is a configuration setting that determines whether your
application encrypts and decrypts with key
commitment. Encrypting and decrypting with key commitment is an AWS Encryption SDK best practice.
Setting and adjusting your commitment policy is a critical step in migrating from versions 1.7.x and earlier of the
AWS Encryption SDK to version 2.0.x and later. This progression is explained in detail in the
migration topic.
The default commitment policy value in the latest versions of the AWS Encryption SDK
(beginning in version 2.0.x), RequireEncryptRequireDecrypt
, is ideal for
most situations. However, if you need to decrypt ciphertext that was encrypted without
key commitment, you might need to change your commitment policy to
RequireEncryptAllowDecrypt
. For examples of how to set a commitment
policy in each programming language, see Setting your commitment policy.
Working 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. (The AWS Encryption SDK for .NET does not support streaming.)
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.
Caching 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.