-
Notifications
You must be signed in to change notification settings - Fork 84
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* docs: add CMM examples * docs: add CMM examples to readme * docs: apply suggestions from code review Co-Authored-By: Wesley Rosenblum <55108558+WesleyRosenblum@users.noreply.github.com> * docs: fix and refine examples docs * chore: remove redundant example * docs: clarify "filtering CMM" references in examples comments * chore: autoformat * docs: refactor algorithm restricting example focus * docs: revise framing of encryption context example and KMS references * docs: apply suggestions from code review Co-Authored-By: Wesley Rosenblum <55108558+WesleyRosenblum@users.noreply.github.com> Co-authored-by: Wesley Rosenblum <55108558+WesleyRosenblum@users.noreply.github.com>
- Loading branch information
1 parent
5ac45bf
commit cd2a171
Showing
8 changed files
with
416 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. | ||
# SPDX-License-Identifier: Apache-2.0 | ||
""" | ||
Cryptographic materials manager examples. | ||
These examples show how to create and use cryptographic materials managers. | ||
""" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. | ||
# SPDX-License-Identifier: Apache-2.0 | ||
""" | ||
Caching cryptographic materials manager examples. | ||
These examples show how to configure and use the caching cryptographic materials manager. | ||
""" |
94 changes: 94 additions & 0 deletions
94
examples/src/crypto_materials_manager/caching/simple_cache.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. | ||
# SPDX-License-Identifier: Apache-2.0 | ||
""" | ||
The default cryptographic materials manager (CMM) | ||
creates new encryption and decryption materials | ||
on every call. | ||
This means every encrypted message is protected by a unique data key, | ||
but it also means that you need to interact with your key management system | ||
in order to process any message. | ||
If this causes performance, operations, or cost issues for you, | ||
you might benefit from data key caching. | ||
https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/data-key-caching.html | ||
This example shows how to configure the caching CMM | ||
to reuse data keys across multiple encrypted messages. | ||
In this example, we use an AWS KMS customer master key (CMK), | ||
but you can use other key management options with the AWS Encryption SDK. | ||
For examples that demonstrate how to use other key management configurations, | ||
see the ``keyring`` and ``master_key_provider`` directories. | ||
In this example, we use the one-step encrypt and decrypt APIs. | ||
""" | ||
import aws_encryption_sdk | ||
from aws_encryption_sdk.caches.local import LocalCryptoMaterialsCache | ||
from aws_encryption_sdk.keyrings.aws_kms import KmsKeyring | ||
from aws_encryption_sdk.materials_managers.caching import CachingCryptoMaterialsManager | ||
|
||
|
||
def run(aws_kms_cmk, source_plaintext): | ||
# type: (str, bytes) -> None | ||
"""Demonstrate an encrypt/decrypt cycle using the caching cryptographic materials manager. | ||
:param str aws_kms_cmk: The ARN of an AWS KMS CMK that protects data keys | ||
:param bytes source_plaintext: Plaintext to encrypt | ||
""" | ||
# Prepare your encryption context. | ||
# https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/concepts.html#encryption-context | ||
encryption_context = { | ||
"encryption": "context", | ||
"is not": "secret", | ||
"but adds": "useful metadata", | ||
"that can help you": "be confident that", | ||
"the data you are handling": "is what you think it is", | ||
} | ||
|
||
# Create the keyring that determines how your data keys are protected. | ||
keyring = KmsKeyring(generator_key_id=aws_kms_cmk) | ||
|
||
# Create the caching cryptographic materials manager using your keyring. | ||
cmm = CachingCryptoMaterialsManager( | ||
keyring=keyring, | ||
# The cache is where the caching CMM stores the materials. | ||
# | ||
# LocalCryptoMaterialsCache gives you a local, in-memory, cache. | ||
cache=LocalCryptoMaterialsCache(capacity=100), | ||
# max_age determines how long the caching CMM will reuse materials. | ||
# | ||
# This example uses two minutes. | ||
# In production, always choose as small a value as possible | ||
# that works for your requirements. | ||
max_age=120.0, | ||
# max_messages_encrypted determines how many messages | ||
# the caching CMM will protect with the same materials. | ||
# | ||
# In production, always choose as small a value as possible | ||
# that works for your requirements. | ||
max_messages_encrypted=10, | ||
) | ||
|
||
# Encrypt your plaintext data. | ||
ciphertext, _encrypt_header = aws_encryption_sdk.encrypt( | ||
source=source_plaintext, encryption_context=encryption_context, materials_manager=cmm | ||
) | ||
|
||
# Demonstrate that the ciphertext and plaintext are different. | ||
assert ciphertext != source_plaintext | ||
|
||
# Decrypt your encrypted data using the same cryptographic materials manager you used on encrypt. | ||
# | ||
# You do not need to specify the encryption context on decrypt | ||
# because the header of the encrypted message includes the encryption context. | ||
decrypted, decrypt_header = aws_encryption_sdk.decrypt(source=ciphertext, materials_manager=cmm) | ||
|
||
# Demonstrate that the decrypted plaintext is identical to the original plaintext. | ||
assert decrypted == source_plaintext | ||
|
||
# Verify that the encryption context used in the decrypt operation includes | ||
# the encryption context that you specified when encrypting. | ||
# The AWS Encryption SDK can add pairs, so don't require an exact match. | ||
# | ||
# In production, always use a meaningful encryption context. | ||
assert set(encryption_context.items()) <= set(decrypt_header.encryption_context.items()) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. | ||
# SPDX-License-Identifier: Apache-2.0 | ||
""" | ||
Custom cryptographic materials manager (CMM) examples. | ||
The AWS Encryption SDK includes CMMs for common use cases, | ||
but you might need to do something else. | ||
These examples show how you could create your own CMM for some specific requirements. | ||
""" |
138 changes: 138 additions & 0 deletions
138
examples/src/crypto_materials_manager/custom/algorithm_suite_enforcement.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,138 @@ | ||
# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. | ||
# SPDX-License-Identifier: Apache-2.0 | ||
""" | ||
The AWS Encryption SDK supports several different algorithm suites | ||
that offer different security properties. | ||
https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/supported-algorithms.html | ||
By default, the AWS Encryption SDK will let you use any of these, | ||
but you might want to restrict that further. | ||
We recommend that you use the default algorithm suite, | ||
which uses AES-GCM with 256-bit keys, HKDF, and ECDSA message signing. | ||
If your readers and writers have the same permissions, | ||
you might want to omit the message signature for faster operation. | ||
For more information about choosing a signed or unsigned algorithm suite, | ||
see the AWS Encryption SDK developer guide: | ||
https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/supported-algorithms.html#other-algorithms | ||
This example shows how you can make a custom cryptographic materials manager (CMM) | ||
that only allows encrypt requests that either specify one of these two algorithm suites | ||
or do not specify an algorithm suite, in which case the default CMM uses the default algorithm suite. | ||
""" | ||
import aws_encryption_sdk | ||
from aws_encryption_sdk.identifiers import AlgorithmSuite | ||
from aws_encryption_sdk.keyrings.aws_kms import KmsKeyring | ||
from aws_encryption_sdk.keyrings.base import Keyring | ||
from aws_encryption_sdk.materials_managers import ( | ||
DecryptionMaterials, | ||
DecryptionMaterialsRequest, | ||
EncryptionMaterials, | ||
EncryptionMaterialsRequest, | ||
) | ||
from aws_encryption_sdk.materials_managers.base import CryptoMaterialsManager | ||
from aws_encryption_sdk.materials_managers.default import DefaultCryptoMaterialsManager | ||
|
||
|
||
class UnapprovedAlgorithmSuite(Exception): | ||
"""Indicate that an unsupported algorithm suite was requested.""" | ||
|
||
|
||
class RequireApprovedAlgorithmSuitesCryptoMaterialsManager(CryptoMaterialsManager): | ||
"""Only allow encryption requests for approved algorithm suites.""" | ||
|
||
def __init__(self, keyring): | ||
# type: (Keyring) -> None | ||
"""Set up the inner cryptographic materials manager using the provided keyring. | ||
:param Keyring keyring: Keyring to use in the inner cryptographic materials manager | ||
""" | ||
self._allowed_algorithm_suites = { | ||
None, # no algorithm suite in the request | ||
AlgorithmSuite.AES_256_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384, # the default algorithm suite | ||
AlgorithmSuite.AES_256_GCM_IV12_TAG16_HKDF_SHA256, # the recommended unsigned algorithm suite | ||
} | ||
# Wrap the provided keyring in the default cryptographic materials manager (CMM). | ||
# | ||
# This is the same thing that the encrypt and decrypt APIs, as well as the caching CMM, | ||
# do if you provide a keyring instead of a CMM. | ||
self._cmm = DefaultCryptoMaterialsManager(keyring=keyring) | ||
|
||
def get_encryption_materials(self, request): | ||
# type: (EncryptionMaterialsRequest) -> EncryptionMaterials | ||
"""Block any requests that include an unapproved algorithm suite.""" | ||
if request.algorithm not in self._allowed_algorithm_suites: | ||
raise UnapprovedAlgorithmSuite("Unapproved algorithm suite requested!") | ||
|
||
return self._cmm.get_encryption_materials(request) | ||
|
||
def decrypt_materials(self, request): | ||
# type: (DecryptionMaterialsRequest) -> DecryptionMaterials | ||
"""Be more permissive on decrypt and just pass through.""" | ||
return self._cmm.decrypt_materials(request) | ||
|
||
|
||
def run(aws_kms_cmk, source_plaintext): | ||
# type: (str, bytes) -> None | ||
"""Demonstrate an encrypt/decrypt cycle using a custom cryptographic materials manager that filters requests. | ||
:param str aws_kms_cmk: The ARN of an AWS KMS CMK that protects data keys | ||
:param bytes source_plaintext: Plaintext to encrypt | ||
""" | ||
# Prepare your encryption context. | ||
# https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/concepts.html#encryption-context | ||
encryption_context = { | ||
"encryption": "context", | ||
"is not": "secret", | ||
"but adds": "useful metadata", | ||
"that can help you": "be confident that", | ||
"the data you are handling": "is what you think it is", | ||
} | ||
|
||
# Create the keyring that determines how your data keys are protected. | ||
keyring = KmsKeyring(generator_key_id=aws_kms_cmk) | ||
|
||
# Create the algorithm suite restricting cryptographic materials manager using your keyring. | ||
cmm = RequireApprovedAlgorithmSuitesCryptoMaterialsManager(keyring=keyring) | ||
|
||
# Demonstrate that the algorithm suite restricting CMM will not let you use an unapproved algorithm suite. | ||
try: | ||
aws_encryption_sdk.encrypt( | ||
source=source_plaintext, | ||
encryption_context=encryption_context, | ||
materials_manager=cmm, | ||
algorithm=AlgorithmSuite.AES_256_GCM_IV12_TAG16, | ||
) | ||
except UnapprovedAlgorithmSuite: | ||
# You asked for an unapproved algorithm suite. | ||
# Reaching this point means everything is working as expected. | ||
pass | ||
else: | ||
# The algorithm suite restricting CMM keeps this from happening. | ||
raise AssertionError("The algorithm suite restricting CMM does not let this happen!") | ||
|
||
# Encrypt your plaintext data. | ||
ciphertext, _encrypt_header = aws_encryption_sdk.encrypt( | ||
source=source_plaintext, encryption_context=encryption_context, materials_manager=cmm | ||
) | ||
|
||
# Demonstrate that the ciphertext and plaintext are different. | ||
assert ciphertext != source_plaintext | ||
|
||
# Decrypt your encrypted data using the same cryptographic materials manager you used on encrypt. | ||
# | ||
# You do not need to specify the encryption context on decrypt | ||
# because the header of the encrypted message includes the encryption context. | ||
decrypted, decrypt_header = aws_encryption_sdk.decrypt(source=ciphertext, materials_manager=cmm) | ||
|
||
# Demonstrate that the decrypted plaintext is identical to the original plaintext. | ||
assert decrypted == source_plaintext | ||
|
||
# Verify that the encryption context used in the decrypt operation includes | ||
# the encryption context that you specified when encrypting. | ||
# The AWS Encryption SDK can add pairs, so don't require an exact match. | ||
# | ||
# In production, always use a meaningful encryption context. | ||
assert set(encryption_context.items()) <= set(decrypt_header.encryption_context.items()) |
Oops, something went wrong.