-
Notifications
You must be signed in to change notification settings - Fork 85
docs: add CMM examples #239
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 2 commits
f0951f7
be23069
048b46d
6792aa1
1d07025
82333bd
1f6f7a0
7688847
c1ed9c0
b83fdf2
2102542
1445c37
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
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. | ||
""" |
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. | ||
""" |
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 examples 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 a KMS keyring with a single CMK. | ||
|
||
: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()) |
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 | ||
""" | ||
Cuystom cryptographic materials manager (CMM) examples. | ||
mattsb42-aws marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
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. | ||
""" |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
# 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 do not recommend using the algorithm suites without key derivation, | ||
so for this example we will show how to make a custom CMM | ||
that will not allow you to use those algorithm suites. | ||
""" | ||
import aws_encryption_sdk | ||
from aws_encryption_sdk.identifiers import AlgorithmSuite, KDFSuite | ||
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 UnsupportedAlgorithmSuite(Exception): | ||
"""Indicate that an unsupported algorithm suite was requested.""" | ||
|
||
|
||
class OnlyKdfAlgorithmSuitesCryptoMaterialsManager(CryptoMaterialsManager): | ||
"""Only allow encryption requests for algorithm suites with a KDF.""" | ||
|
||
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._cmm = DefaultCryptoMaterialsManager(keyring=keyring) | ||
|
||
def get_encryption_materials(self, request): | ||
# type: (EncryptionMaterialsRequest) -> EncryptionMaterials | ||
"""Block any requests that include an algorithm suite without a KDF.""" | ||
if request.algorithm is not None and request.algorithm.kdf is KDFSuite.NONE: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There isn't a particularly elegant way to do this in the Java ESDK. It would be something like: if(!request.getRequestedAlgorithm().getDataKeyAlgo().contains("Hkdf")) I wouldn't normally recommend someone write code that depends on a string in that way. Alternatively, both Java and Python both have the isSafeToCache parameter, could this make use of that instead? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe. If we want to go that route I want to re-frame what the example is about: changing it from specifically barring non-KDF suites to instead making sure that you can cache the request. Another option would be changing the requirement to be one of our two recommended (default or default - signing). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yeah, I'd say let's do the second option. The example doesn't have to do anything particularly interesting or innovative to serve its purpose, that would show a basic validation so the user can get a sense of whats possible. |
||
raise UnsupportedAlgorithmSuite("Non-KDF algorithm suites are not allowed!") | ||
|
||
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 KMS keyring with a single CMK. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Update |
||
|
||
: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 filtering cryptographic materials manager using your keyring. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is the first time you used the terminology "filtering CMM". Do you want to introduce that at the top? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This was just shorthand I was using, but you're right; I'll just replace these with references back to the actual custom CMM. |
||
cmm = OnlyKdfAlgorithmSuitesCryptoMaterialsManager(keyring=keyring) | ||
|
||
# Demonstrate that the filtering CMM will not let you use non-KDF algorithm suites. | ||
try: | ||
aws_encryption_sdk.encrypt( | ||
source=source_plaintext, | ||
encryption_context=encryption_context, | ||
materials_manager=cmm, | ||
algorithm=AlgorithmSuite.AES_256_GCM_IV12_TAG16, | ||
) | ||
except UnsupportedAlgorithmSuite: | ||
# You asked for a non-KDF algorithm suite. | ||
# Reaching this point means everything is working as expected. | ||
pass | ||
else: | ||
# The filtering CMM keeps this from happening. | ||
raise AssertionError("The filtering 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()) |
Uh oh!
There was an error while loading. Please reload this page.