-
Notifications
You must be signed in to change notification settings - Fork 86
chore(migration examples): added KMS, raw AES and raw RSA keyring/MKP… #687
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
Merged
Merged
Changes from all commits
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
f1fca97
chore(migration examples): added KMS, raw AES and raw RSA keyring/MKP…
RitvikKapila 7f95db8
added README; minor fix
RitvikKapila b69c418
fix flake8
RitvikKapila 13acd28
refactoring
RitvikKapila a528e2d
fix
RitvikKapila 1ba28ef
removed classes for keyrings / mkps
RitvikKapila 67d866f
inline encrypt and decrypt
RitvikKapila 4c61b23
fix
RitvikKapila 7c721ed
minor fix
RitvikKapila 6d44ed1
fix comments
RitvikKapila 2da41df
fix
RitvikKapila File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or 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,19 @@ | ||
################## | ||
Migration Examples | ||
################## | ||
|
||
The `Encryption SDK for Python`_ now uses the `AWS Cryptographic Material Providers Library`_. The MPL abstracts lower | ||
level cryptographic materials management of encryption and decryption materials. | ||
|
||
This directory contains migration examples for: | ||
|
||
#. Moving to Keyrings from Master Key Providers: | ||
* Migration example to AWS KMS keyring from AWS KMS Master Key Provider. | ||
* Migration example to Raw AES keyring from Raw AES Master Key Provider. | ||
* Migration example to Raw RSA keyring from Raw RSA Master Key Provider. | ||
|
||
#. Migration to newer versions of the ESDK (4.x+) from 1.x versions: | ||
* Setting a 'CommitmentPolicy' during migration - If you have messages encrypted with 1.x versions of the ESDK (i.e. not using key commitment) and want to migrate to encrypt with key commitment using the keyring providers introduced in ESDK 4.x, this example will guide you on how to decrypt those messages using the new version of the ESDK. | ||
|
||
.. _AWS Cryptographic Material Providers Library: https://github.com/aws/aws-cryptographic-material-providers-library | ||
.. _Encryption SDK for Python: https://github.com/aws/aws-encryption-sdk-python/tree/9c34aad60fc918c1a9186ec5215a451e8bfd0f65 |
166 changes: 166 additions & 0 deletions
166
examples/src/migration/migration_aws_kms_key_example.py
This file contains hidden or 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,166 @@ | ||
# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. | ||
# SPDX-License-Identifier: Apache-2.0 | ||
""" | ||
This is a migration example for moving to the AWS KMS Keyring from AWS KMS master key provider (MKP) | ||
|
||
The AWS KMS keyring uses symmetric encryption KMS keys to generate, encrypt and | ||
decrypt data keys. This example creates a KMS Keyring and KMS MKP and | ||
then encrypts a custom input EXAMPLE_DATA with the same encryption context using both | ||
the keyring and MKP. The example then decrypts the ciphertexts using both keyring and MKPs. | ||
This example also includes some sanity checks for demonstration: | ||
1. Decryption of these ciphertexts encrypted using keyring and MKP | ||
is possible using both KMS keyring and KMS MKP | ||
2. Both decrypted plaintexts are same and match EXAMPLE_DATA | ||
These sanity checks are for demonstration in the example only. You do not need these in your code. | ||
|
||
Note: The ciphertexts obtained by encrypting EXAMPLE_DATA using keyring and MKP are not | ||
the same because the ESDK generates different data keys each time for encryption of the data. | ||
But both ciphertexts when decrypted using keyring and MKP should give the same plaintext result. | ||
|
||
For more information on how to use KMS keyrings, see | ||
https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/use-kms-keyring.html | ||
""" | ||
import boto3 | ||
from aws_cryptographic_materialproviders.mpl import AwsCryptographicMaterialProviders | ||
from aws_cryptographic_materialproviders.mpl.config import MaterialProvidersConfig | ||
from aws_cryptographic_materialproviders.mpl.models import CreateAwsKmsKeyringInput | ||
from aws_cryptographic_materialproviders.mpl.references import IKeyring | ||
from typing import Dict # noqa pylint: disable=wrong-import-order | ||
|
||
import aws_encryption_sdk | ||
|
||
EXAMPLE_DATA: bytes = b"Hello World" | ||
|
||
DEFAULT_ENCRYPTION_CONTEXT : Dict[str, str] = { | ||
"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", | ||
} | ||
|
||
|
||
def create_keyring( | ||
kms_key_id: str, | ||
aws_region="us-west-2" | ||
): | ||
"""Demonstrate how to create an AWS KMS keyring. | ||
|
||
Usage: create_keyring(kms_key_id) | ||
:param kms_key_id: KMS Key identifier for the KMS key you want to use. | ||
:type kms_key_id: string | ||
|
||
For more information on KMS Key identifiers, see | ||
https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#key-id | ||
""" | ||
# Create a boto3 client for KMS. | ||
kms_client = boto3.client('kms', region_name=aws_region) | ||
|
||
# Create a KMS keyring | ||
mat_prov: AwsCryptographicMaterialProviders = AwsCryptographicMaterialProviders( | ||
config=MaterialProvidersConfig() | ||
) | ||
|
||
keyring_input: CreateAwsKmsKeyringInput = CreateAwsKmsKeyringInput( | ||
kms_key_id=kms_key_id, | ||
kms_client=kms_client | ||
) | ||
|
||
keyring: IKeyring = mat_prov.create_aws_kms_keyring( | ||
input=keyring_input | ||
) | ||
|
||
return keyring | ||
|
||
|
||
def create_key_provider( | ||
kms_key_id: str | ||
): | ||
"""Demonstrate how to create an AWS KMS master key provider. | ||
|
||
Usage: create_key_provider(kms_key_id) | ||
:param kms_key_id: KMS Key identifier for the KMS key you want to use. | ||
:type kms_key_id: string | ||
|
||
For more information on KMS Key identifiers, see | ||
https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#key-id | ||
""" | ||
# Create a KMS master key provider. | ||
key_provider = aws_encryption_sdk.StrictAwsKmsMasterKeyProvider(key_ids=[ | ||
kms_key_id, | ||
]) | ||
|
||
return key_provider | ||
|
||
|
||
def migration_aws_kms_key( | ||
kms_key_id: str | ||
): | ||
"""Demonstrate a migration example for moving to an AWS KMS keyring from AWS KMS MKP. | ||
|
||
Usage: migration_aws_kms_key(kms_key_id) | ||
:param kms_key_id: KMS Key identifier for the KMS key you want to use for encryption and | ||
decryption of your data keys. | ||
:type kms_key_id: string | ||
|
||
For more information on KMS Key identifiers, see | ||
https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#key-id | ||
""" | ||
client = aws_encryption_sdk.EncryptionSDKClient() | ||
|
||
# 1a. Create a AWS KMS Keyring | ||
aws_kms_keyring = create_keyring(kms_key_id=kms_key_id) | ||
|
||
# 1b. Create a AWS KMS Master Key Provider | ||
aws_kms_master_key_provider = create_key_provider(kms_key_id=kms_key_id) | ||
|
||
# 2a. Encrypt EXAMPLE_DATA using AWS KMS Keyring | ||
ciphertext_keyring, _ = client.encrypt( | ||
source=EXAMPLE_DATA, | ||
keyring=aws_kms_keyring, | ||
encryption_context=DEFAULT_ENCRYPTION_CONTEXT | ||
) | ||
|
||
# 2b. Encrypt EXAMPLE_DATA using AWS KMS Master Key Provider | ||
ciphertext_mkp, _ = client.encrypt( | ||
source=EXAMPLE_DATA, | ||
key_provider=aws_kms_master_key_provider, | ||
encryption_context=DEFAULT_ENCRYPTION_CONTEXT | ||
) | ||
|
||
# Note: The ciphertexts obtained by encrypting EXAMPLE_DATA using keyring and MKP | ||
# (that is ciphertext_keyring and ciphertext_mkp) are not the same because the ESDK | ||
# generates different data keys each time for encryption of the data. But both | ||
# ciphertexts when decrypted using keyring and MKP should give the same plaintext result. | ||
|
||
# 3. Decrypt the ciphertext_keyring using both the keyring and MKP and ensure the | ||
# resulting plaintext is the same and also equal to EXAMPLE_DATA | ||
decrypted_ciphertext_keyring_using_keyring, _ = client.decrypt( | ||
source=ciphertext_keyring, | ||
keyring=aws_kms_keyring | ||
) | ||
|
||
decrypted_ciphertext_keyring_using_mkp, _ = client.decrypt( | ||
source=ciphertext_keyring, | ||
key_provider=aws_kms_master_key_provider | ||
) | ||
|
||
assert decrypted_ciphertext_keyring_using_keyring == decrypted_ciphertext_keyring_using_mkp \ | ||
and decrypted_ciphertext_keyring_using_keyring == EXAMPLE_DATA, \ | ||
"Decrypted outputs using keyring and master key provider are not the same" | ||
|
||
# 4. Decrypt the ciphertext_mkp using both the keyring and MKP and ensure the | ||
# resulting plaintext is the same and also equal to EXAMPLE_DATA | ||
decrypted_ciphertext_mkp_using_keyring, _ = client.decrypt( | ||
source=ciphertext_mkp, | ||
keyring=aws_kms_keyring | ||
) | ||
|
||
decrypted_ciphertext_mkp_using_mkp, _ = client.decrypt( | ||
source=ciphertext_mkp, | ||
key_provider=aws_kms_master_key_provider | ||
) | ||
|
||
assert decrypted_ciphertext_mkp_using_keyring == decrypted_ciphertext_mkp_using_mkp \ | ||
and decrypted_ciphertext_mkp_using_keyring == EXAMPLE_DATA, \ | ||
"Decrypted outputs using keyring and master key provider are not the same" |
207 changes: 207 additions & 0 deletions
207
examples/src/migration/migration_raw_aes_key_example.py
This file contains hidden or 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,207 @@ | ||
# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. | ||
# SPDX-License-Identifier: Apache-2.0 | ||
""" | ||
This is a migration example for moving to the Raw AES Keyring from Raw AES master key provider (MKP) | ||
|
||
The Raw AES keyring lets you use an AES symmetric key that you provide as a wrapping key that | ||
protects your data key. You need to generate, store, and protect the key material, | ||
preferably in a hardware security module (HSM) or key management system. Use a Raw AES keyring | ||
when you need to provide the wrapping key and encrypt the data keys locally or offline. | ||
|
||
This example creates a Raw AES Keyring and Raw AES MKP and | ||
then encrypts a custom input EXAMPLE_DATA with the same encryption context using both | ||
the keyring and MKP. The example then decrypts the ciphertexts using both keyring and MKPs. | ||
This example also includes some sanity checks for demonstration: | ||
1. Decryption of these ciphertexts encrypted using keyring and MKP | ||
is possible using both Raw AES keyring and Raw AES MKP | ||
2. Both decrypted plaintexts are same and match EXAMPLE_DATA | ||
These sanity checks are for demonstration in the example only. You do not need these in your code. | ||
|
||
Note: The ciphertexts obtained by encrypting EXAMPLE_DATA using keyring and MKP are not | ||
the same because the ESDK generates different data keys each time for encryption of the data. | ||
But both ciphertexts when decrypted using keyring and MKP will give the same plaintext result. | ||
|
||
For more information on how to use Raw AES keyrings, see | ||
https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/use-raw-aes-keyring.html | ||
""" | ||
import secrets | ||
|
||
from aws_cryptographic_materialproviders.mpl import AwsCryptographicMaterialProviders | ||
from aws_cryptographic_materialproviders.mpl.config import MaterialProvidersConfig | ||
from aws_cryptographic_materialproviders.mpl.models import AesWrappingAlg, CreateRawAesKeyringInput | ||
from aws_cryptographic_materialproviders.mpl.references import IKeyring | ||
from typing import Dict # noqa pylint: disable=wrong-import-order | ||
|
||
import aws_encryption_sdk | ||
from aws_encryption_sdk.identifiers import EncryptionKeyType, WrappingAlgorithm | ||
from aws_encryption_sdk.internal.crypto.wrapping_keys import WrappingKey | ||
from aws_encryption_sdk.key_providers.raw import RawMasterKeyProvider | ||
|
||
EXAMPLE_DATA: bytes = b"Hello World" | ||
|
||
DEFAULT_ENCRYPTION_CONTEXT : Dict[str, str] = { | ||
"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", | ||
} | ||
|
||
DEFAULT_AES_256_STATIC_KEY = secrets.token_bytes(32) | ||
|
||
# The key namespace in the Raw keyrings is equivalent to Provider ID (or Provider) field | ||
# in the Raw Master Key Providers | ||
DEFAULT_KEY_NAME_SPACE = "Some managed raw keys" | ||
|
||
# The key name in the Raw keyrings is equivalent to the Key ID field | ||
# in the Raw Master Key Providers | ||
DEFAULT_KEY_NAME = "My 256-bit AES wrapping key" | ||
|
||
|
||
def create_keyring(): | ||
"""Demonstrate how to create a Raw AES keyring. | ||
|
||
Usage: create_keyring() | ||
""" | ||
# We fix the static key in order to make the test deterministic | ||
static_key = DEFAULT_AES_256_STATIC_KEY | ||
|
||
mat_prov: AwsCryptographicMaterialProviders = AwsCryptographicMaterialProviders( | ||
config=MaterialProvidersConfig() | ||
) | ||
|
||
# The key namespace in the Raw keyrings is equivalent to Provider ID (or Provider) field | ||
# in the Raw Master Key Providers | ||
# The key name in the Raw keyrings is equivalent to the Key ID field | ||
# in the Raw Master Key Providers | ||
keyring_input: CreateRawAesKeyringInput = CreateRawAesKeyringInput( | ||
key_namespace=DEFAULT_KEY_NAME_SPACE, | ||
key_name=DEFAULT_KEY_NAME, | ||
wrapping_key=static_key, | ||
wrapping_alg=AesWrappingAlg.ALG_AES256_GCM_IV12_TAG16 | ||
) | ||
|
||
keyring: IKeyring = mat_prov.create_raw_aes_keyring( | ||
input=keyring_input | ||
) | ||
|
||
return keyring | ||
|
||
|
||
# This is a helper class necessary for the Raw AES master key provider | ||
# In the StaticMasterKeyProvider, we fix the static key to | ||
# DEFAULT_AES_256_STATIC_KEY in order to make the test deterministic. | ||
# Thus, both the Raw AES keyring and Raw AES MKP have the same key | ||
# and we are able to encrypt data using keyrings and decrypt using MKP and vice versa | ||
# In practice, users should generate a new random key for each key id. | ||
class StaticMasterKeyProvider(RawMasterKeyProvider): | ||
"""Generates 256-bit keys for each unique key ID.""" | ||
|
||
# The key namespace in the Raw keyrings is equivalent to Provider ID (or Provider) field | ||
# in the Raw Master Key Providers | ||
provider_id = DEFAULT_KEY_NAME_SPACE | ||
|
||
def __init__(self, **kwargs): # pylint: disable=unused-argument | ||
"""Initialize empty map of keys.""" | ||
self._static_keys = {} | ||
|
||
def _get_raw_key(self, key_id): | ||
"""Returns a static, symmetric key for the specified key ID. | ||
|
||
:param str key_id: Key ID | ||
:returns: Wrapping key that contains the specified static key | ||
:rtype: :class:`aws_encryption_sdk.internal.crypto.WrappingKey` | ||
""" | ||
try: | ||
static_key = self._static_keys[key_id] | ||
except KeyError: | ||
# We fix the static key in order to make the test deterministic | ||
# In practice, you should get this key from a secure key management system such as an HSM. | ||
static_key = DEFAULT_AES_256_STATIC_KEY | ||
self._static_keys[key_id] = static_key | ||
return WrappingKey( | ||
wrapping_algorithm=WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING, | ||
wrapping_key=static_key, | ||
wrapping_key_type=EncryptionKeyType.SYMMETRIC, | ||
) | ||
|
||
|
||
def create_key_provider(): | ||
"""Demonstrate how to create a Raw AES master key provider. | ||
|
||
Usage: create_key_provider() | ||
""" | ||
# Create a Raw AES master key provider. | ||
|
||
# The key name in the Raw keyrings is equivalent to the Key ID field | ||
# in the Raw Master Key Providers | ||
key_id = DEFAULT_KEY_NAME | ||
key_provider = StaticMasterKeyProvider() | ||
key_provider.add_master_key(key_id) | ||
|
||
return key_provider | ||
|
||
|
||
def migration_raw_aes_key(): | ||
"""Demonstrate a migration example for moving to a Raw AES keyring from Raw AES MKP. | ||
|
||
Usage: migration_raw_aes_key() | ||
""" | ||
client = aws_encryption_sdk.EncryptionSDKClient() | ||
|
||
# 1a. Create a Raw AES Keyring | ||
raw_aes_keyring = create_keyring() | ||
|
||
# 1b. Create a Raw AES Master Key Provider | ||
raw_aes_master_key_provider = create_key_provider() | ||
|
||
# 2a. Encrypt EXAMPLE_DATA using Raw AES Keyring | ||
ciphertext_keyring, _ = client.encrypt( | ||
source=EXAMPLE_DATA, | ||
keyring=raw_aes_keyring, | ||
encryption_context=DEFAULT_ENCRYPTION_CONTEXT | ||
) | ||
|
||
# 2b. Encrypt EXAMPLE_DATA using Raw AES Master Key Provider | ||
ciphertext_mkp, _ = client.encrypt( | ||
source=EXAMPLE_DATA, | ||
key_provider=raw_aes_master_key_provider, | ||
encryption_context=DEFAULT_ENCRYPTION_CONTEXT | ||
) | ||
|
||
# Note: The ciphertexts obtained by encrypting EXAMPLE_DATA using keyring and MKP | ||
# (that is ciphertext_keyring and ciphertext_mkp) are not the same because the ESDK | ||
# generates different data keys each time for encryption of the data. But both | ||
# ciphertexts when decrypted using keyring and MKP will give the same plaintext result. | ||
|
||
# 3. Decrypt the ciphertext_keyring using both the keyring and MKP and ensure the | ||
# resulting plaintext is the same and also equal to EXAMPLE_DATA | ||
decrypted_ciphertext_keyring_using_keyring, _ = client.decrypt( | ||
source=ciphertext_keyring, | ||
keyring=raw_aes_keyring | ||
) | ||
|
||
decrypted_ciphertext_keyring_using_mkp, _ = client.decrypt( | ||
source=ciphertext_keyring, | ||
key_provider=raw_aes_master_key_provider | ||
) | ||
|
||
assert decrypted_ciphertext_keyring_using_keyring == decrypted_ciphertext_keyring_using_mkp \ | ||
and decrypted_ciphertext_keyring_using_keyring == EXAMPLE_DATA, \ | ||
"Decrypted outputs using keyring and master key provider are not the same" | ||
|
||
# 4. Decrypt the ciphertext_mkp using both the keyring and MKP and ensure the | ||
# resulting plaintext is the same and also equal to EXAMPLE_DATA | ||
decrypted_ciphertext_mkp_using_keyring, _ = client.decrypt( | ||
source=ciphertext_mkp, | ||
keyring=raw_aes_keyring | ||
) | ||
|
||
decrypted_ciphertext_mkp_using_mkp, _ = client.decrypt( | ||
source=ciphertext_mkp, | ||
key_provider=raw_aes_master_key_provider | ||
) | ||
|
||
assert decrypted_ciphertext_mkp_using_keyring == decrypted_ciphertext_mkp_using_mkp \ | ||
and decrypted_ciphertext_mkp_using_keyring == EXAMPLE_DATA, \ | ||
"Decrypted outputs using keyring and master key provider are not the same" |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.