diff --git a/examples/src/custom_mpl_cmm_example.py b/examples/src/custom_mpl_cmm_example.py new file mode 100644 index 000000000..544ca5f00 --- /dev/null +++ b/examples/src/custom_mpl_cmm_example.py @@ -0,0 +1,125 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +""" +Example to create a custom implementation of the MPL's ICryptographicMaterialsManager class and use it with the ESDK. + +The cryptographic materials manager (CMM) assembles the cryptographic materials that are used +to encrypt and decrypt data. The cryptographic materials include plaintext and encrypted data keys, +and an optional message signing key. + +Cryptographic Materials Managers (CMMs) are composable; if you just want to extend the behavior of +the default CMM, you can do this as demonstrated in this example. This is the easiest approach if +you are just adding a small check to the CMM methods, as in this example. + +If your use case calls for fundamentally changing aspects of the default CMM, you can also write +your own implementation without extending an existing CMM. The default CMM's implementation is a +good reference to use if you need to write a custom CMM implementation from scratch. +Custom implementations of CMMs must implement get_encryption_materials and decrypt_materials. + +For more information on a default implementation of a CMM, +please look at the default_cryptographic_materials_manager_example.py example. + +For more information on Cryptographic Material Managers, see +https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/concepts.html#crypt-materials-manager +""" + +from aws_cryptographic_materialproviders.mpl import AwsCryptographicMaterialProviders +from aws_cryptographic_materialproviders.mpl.config import MaterialProvidersConfig +from aws_cryptographic_materialproviders.mpl.models import ( + CreateDefaultCryptographicMaterialsManagerInput, + SignatureAlgorithmNone, +) +from aws_cryptographic_materialproviders.mpl.references import ICryptographicMaterialsManager, IKeyring + +import aws_encryption_sdk +from aws_encryption_sdk import CommitmentPolicy + + +# Custom CMM implementation using the MPL. +# This CMM only allows encryption/decryption using signing algorithms. +# It wraps an underlying CMM implementation and checks its materials +# to ensure that it is only using signed encryption algorithms. +class MPLCustomSigningSuiteOnlyCMM(ICryptographicMaterialsManager): + """Example custom crypto materials manager class.""" + + def __init__(self, keyring: IKeyring, cmm: ICryptographicMaterialsManager = None) -> None: + """Constructor for MPLCustomSigningSuiteOnlyCMM class.""" + if cmm is not None: + self.underlying_cmm = cmm + else: + mat_prov: AwsCryptographicMaterialProviders = AwsCryptographicMaterialProviders( + config=MaterialProvidersConfig() + ) + + # Create a CryptographicMaterialsManager for encryption and decryption + cmm_input: CreateDefaultCryptographicMaterialsManagerInput = \ + CreateDefaultCryptographicMaterialsManagerInput( + keyring=keyring + ) + + self.underlying_cmm: ICryptographicMaterialsManager = \ + mat_prov.create_default_cryptographic_materials_manager( + input=cmm_input + ) + + def get_encryption_materials(self, param): + """Provides encryption materials appropriate for the request for the custom CMM. + + :param aws_cryptographic_materialproviders.mpl.models.GetEncryptionMaterialsInput param: Input object to + provide to a crypto material manager's `get_encryption_materials` method. + :returns: Encryption materials output + :rtype: aws_cryptographic_materialproviders.mpl.models.GetEncryptionMaterialsOutput + """ + materials = self.underlying_cmm.get_encryption_materials(param) + if isinstance(materials.encryption_materials.algorithm_suite.signature, SignatureAlgorithmNone): + raise ValueError( + "Algorithm provided to MPLCustomSigningSuiteOnlyCMM" + + " is not a supported signing algorithm: " + str(materials.encryption_materials.algorithm_suite) + ) + return materials + + def decrypt_materials(self, param): + """Provides decryption materials appropriate for the request for the custom CMM. + + :param aws_cryptographic_materialproviders.mpl.models.DecryptMaterialsInput param: Input object to provide + to a crypto material manager's `decrypt_materials` method. + :returns: Decryption materials output + :rtype: aws_cryptographic_materialproviders.mpl.models.GetDecryptionMaterialsOutput + """ + materials = self.underlying_cmm.decrypt_materials(param) + if isinstance(materials.decryption_materials.algorithm_suite.signature, SignatureAlgorithmNone): + raise ValueError( + "Algorithm provided to MPLCustomSigningSuiteOnlyCMM" + + " is not a supported signing algorithm: " + str(materials.decryption_materials.algorithm_suite) + ) + return materials + + +EXAMPLE_DATA: bytes = b"Hello World" + + +def encrypt_decrypt_with_cmm( + cmm: ICryptographicMaterialsManager +): + """Encrypts and decrypts a string using a custom CMM. + + :param ICryptographicMaterialsManager cmm: CMM to use for encryption and decryption + """ + # Set up an encryption client with an explicit commitment policy. Note that if you do not explicitly choose a + # commitment policy, REQUIRE_ENCRYPT_REQUIRE_DECRYPT is used by default. + client = aws_encryption_sdk.EncryptionSDKClient(commitment_policy=CommitmentPolicy.REQUIRE_ENCRYPT_REQUIRE_DECRYPT) + + # Encrypt the plaintext source data + ciphertext, _ = client.encrypt( + source=EXAMPLE_DATA, + materials_manager=cmm + ) + + # Decrypt the ciphertext + cycled_plaintext, _ = client.decrypt( + source=ciphertext, + materials_manager=cmm + ) + + # Verify that the "cycled" (encrypted, then decrypted) plaintext is identical to the source plaintext + assert cycled_plaintext == EXAMPLE_DATA diff --git a/examples/src/default_cryptographic_materials_manager_example.py b/examples/src/default_cryptographic_materials_manager_example.py new file mode 100644 index 000000000..bfffc36d9 --- /dev/null +++ b/examples/src/default_cryptographic_materials_manager_example.py @@ -0,0 +1,133 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +""" +This example sets up the default Cryptographic Material Managers (CMM). + +The default cryptographic materials manager (CMM) assembles the cryptographic materials +that are used to encrypt and decrypt data. The cryptographic materials include +plaintext and encrypted data keys, and an optional message signing key. +This example creates a CMM and then encrypts a custom input EXAMPLE_DATA +with an encryption context. Creating a CMM involves taking a keyring as input, +and we use an AWS KMS Keyring for this example. +This example also includes some sanity checks for demonstration: +1. Ciphertext and plaintext data are not the same +2. Encryption context is correct in the decrypted message header +3. Decrypted plaintext value matches EXAMPLE_DATA +These sanity checks are for demonstration in the example only. You do not need these in your code. + +For more information on Cryptographic Material Managers, see +https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/concepts.html#crypt-materials-manager +""" +import sys + +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, + CreateDefaultCryptographicMaterialsManagerInput, +) +from aws_cryptographic_materialproviders.mpl.references import ICryptographicMaterialsManager, IKeyring +from typing import Dict # noqa pylint: disable=wrong-import-order + +import aws_encryption_sdk +from aws_encryption_sdk import CommitmentPolicy + +# TODO-MPL: Remove this as part of removing PYTHONPATH hacks. +MODULE_ROOT_DIR = '/'.join(__file__.split("/")[:-1]) + +sys.path.append(MODULE_ROOT_DIR) + +EXAMPLE_DATA: bytes = b"Hello World" + + +def encrypt_and_decrypt_with_default_cmm( + kms_key_id: str +): + """Demonstrate an encrypt/decrypt cycle using default Cryptographic Material Managers. + + Usage: encrypt_and_decrypt_with_default_cmm(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 + """ + # 1. Instantiate the encryption SDK client. + # This builds the client with the REQUIRE_ENCRYPT_REQUIRE_DECRYPT commitment policy, + # which enforces that this client only encrypts using committing algorithm suites and enforces + # that this client will only decrypt encrypted messages that were created with a committing + # algorithm suite. + # This is the default commitment policy if you were to build the client as + # `client = aws_encryption_sdk.EncryptionSDKClient()`. + client = aws_encryption_sdk.EncryptionSDKClient( + commitment_policy=CommitmentPolicy.REQUIRE_ENCRYPT_REQUIRE_DECRYPT + ) + + # 2. Create encryption context. + # Remember that your encryption context is NOT SECRET. + # For more information, see + # https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/concepts.html#encryption-context + 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", + } + + # 3. Create a KMS keyring to use with the CryptographicMaterialsManager + kms_client = boto3.client('kms', region_name="us-west-2") + + mat_prov: AwsCryptographicMaterialProviders = AwsCryptographicMaterialProviders( + config=MaterialProvidersConfig() + ) + + keyring_input: CreateAwsKmsKeyringInput = CreateAwsKmsKeyringInput( + kms_key_id=kms_key_id, + kms_client=kms_client + ) + + kms_keyring: IKeyring = mat_prov.create_aws_kms_keyring( + input=keyring_input + ) + + # 4. Create a CryptographicMaterialsManager for encryption and decryption + cmm_input: CreateDefaultCryptographicMaterialsManagerInput = \ + CreateDefaultCryptographicMaterialsManagerInput( + keyring=kms_keyring + ) + + cmm: ICryptographicMaterialsManager = mat_prov.create_default_cryptographic_materials_manager( + input=cmm_input + ) + + # 5. Encrypt the data with the encryptionContext. + ciphertext, _ = client.encrypt( + source=EXAMPLE_DATA, + materials_manager=cmm, + encryption_context=encryption_context + ) + + # 6. Demonstrate that the ciphertext and plaintext are different. + # (This is an example for demonstration; you do not need to do this in your own code.) + assert ciphertext != EXAMPLE_DATA, \ + "Ciphertext and plaintext data are the same. Invalid encryption" + + # 7. Decrypt your encrypted data using the same cmm you used on encrypt. + plaintext_bytes, dec_header = client.decrypt( + source=ciphertext, + materials_manager=cmm + ) + + # 8. Demonstrate that the encryption context is correct in the decrypted message header + # (This is an example for demonstration; you do not need to do this in your own code.) + for k, v in encryption_context.items(): + assert v == dec_header.encryption_context[k], \ + "Encryption context does not match expected values" + + # 9. Demonstrate that the decrypted plaintext is identical to the original plaintext. + # (This is an example for demonstration; you do not need to do this in your own code.) + assert plaintext_bytes == EXAMPLE_DATA, \ + "Decrypted plaintext should be identical to the original plaintext. Invalid decryption" diff --git a/examples/src/legacy/custom_cmm_example.py b/examples/src/legacy/custom_cmm_example.py new file mode 100644 index 000000000..07e8ca50b --- /dev/null +++ b/examples/src/legacy/custom_cmm_example.py @@ -0,0 +1,87 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +"""Example to create a custom implementation of the native ESDK CryptoMaterialsManager class.""" + +import aws_encryption_sdk +from aws_encryption_sdk import CommitmentPolicy, StrictAwsKmsMasterKeyProvider +from aws_encryption_sdk.materials_managers.base import CryptoMaterialsManager +from aws_encryption_sdk.materials_managers.default import DefaultCryptoMaterialsManager + + +# Custom CMM implementation. +# This CMM only allows encryption/decryption using signing algorithms. +# It wraps an underlying CMM implementation and checks its materials +# to ensure that it is only using signed encryption algorithms. +class CustomSigningSuiteOnlyCMM(CryptoMaterialsManager): + """Example custom crypto materials manager class.""" + + def __init__(self, master_key_provider: StrictAwsKmsMasterKeyProvider) -> None: + """Constructor for CustomSigningSuiteOnlyCMM class.""" + self.underlying_cmm = DefaultCryptoMaterialsManager(master_key_provider) + + def get_encryption_materials(self, request): + """Provides encryption materials appropriate for the request for the custom CMM. + + :param EncryptionMaterialsRequest request: Request object to provide to a + crypto material manager's `get_encryption_materials` method. + :returns: Encryption materials + :rtype: EncryptionMaterials + """ + materials = self.underlying_cmm.get_encryption_materials(request) + if not materials.algorithm.is_signing(): + raise ValueError( + "Algorithm provided to CustomSigningSuiteOnlyCMM" + + " is not a supported signing algorithm: " + materials.algorithm + ) + return materials + + def decrypt_materials(self, request): + """Provides decryption materials appropriate for the request for the custom CMM. + + :param DecryptionMaterialsRequest request: Request object to provide to a + crypto material manager's `decrypt_materials` method. + """ + if not request.algorithm.is_signing(): + raise ValueError( + "Algorithm provided to CustomSigningSuiteOnlyCMM" + + " is not a supported signing algorithm: " + request.algorithm + ) + return self.underlying_cmm.decrypt_materials(request) + + +def encrypt_decrypt_with_cmm( + cmm: CryptoMaterialsManager, + source_plaintext: str +): + """Encrypts and decrypts a string using a custom CMM. + + :param CryptoMaterialsManager cmm: CMM to use for encryption and decryption + :param bytes source_plaintext: Data to encrypt + """ + # Set up an encryption client with an explicit commitment policy. Note that if you do not explicitly choose a + # commitment policy, REQUIRE_ENCRYPT_REQUIRE_DECRYPT is used by default. + client = aws_encryption_sdk.EncryptionSDKClient(commitment_policy=CommitmentPolicy.REQUIRE_ENCRYPT_REQUIRE_DECRYPT) + + # Encrypt the plaintext source data + ciphertext, encryptor_header = client.encrypt( + source=source_plaintext, + materials_manager=cmm + ) + + # Decrypt the ciphertext + cycled_plaintext, decrypted_header = client.decrypt( + source=ciphertext, + materials_manager=cmm + ) + + # Verify that the "cycled" (encrypted, then decrypted) plaintext is identical to the source plaintext + assert cycled_plaintext == source_plaintext + + # Verify that the encryption context used in the decrypt operation includes all key pairs from + # the encrypt operation. (The SDK can add pairs, so don't require an exact match.) + # + # In production, always use a meaningful encryption context. In this sample, we omit the + # encryption context (no key pairs). + assert all( + pair in decrypted_header.encryption_context.items() for pair in encryptor_header.encryption_context.items() + ) diff --git a/examples/test/legacy/examples_test_utils.py b/examples/test/legacy/examples_test_utils.py index 3f877e301..8787e0f38 100644 --- a/examples/test/legacy/examples_test_utils.py +++ b/examples/test/legacy/examples_test_utils.py @@ -39,7 +39,7 @@ from integration_test_utils import ( # noqa pylint: disable=unused-import,import-error get_cmk_arn, - get_second_cmk_arn, get_mrk_arn, + get_second_cmk_arn, get_second_mrk_arn, ) diff --git a/examples/test/legacy/test_i_custom_cmm_example.py b/examples/test/legacy/test_i_custom_cmm_example.py new file mode 100644 index 000000000..397230090 --- /dev/null +++ b/examples/test/legacy/test_i_custom_cmm_example.py @@ -0,0 +1,51 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +"""Test suite for encryption and decryption using custom CMM.""" +import botocore.session +import pytest + +import aws_encryption_sdk + +from ...src.legacy.custom_cmm_example import CustomSigningSuiteOnlyCMM, encrypt_decrypt_with_cmm +from .examples_test_utils import get_cmk_arn, static_plaintext +from .v3_default_cmm import V3DefaultCryptoMaterialsManager + +pytestmark = [pytest.mark.examples] + + +def test_custom_cmm_example(): + """Test method for encryption and decryption using V3 default CMM.""" + plaintext = static_plaintext + cmk_arn = get_cmk_arn() + botocore_session = botocore.session.Session() + + # Create a KMS master key provider. + kms_kwargs = dict(key_ids=[cmk_arn]) + if botocore_session is not None: + kms_kwargs["botocore_session"] = botocore_session + master_key_provider = aws_encryption_sdk.StrictAwsKmsMasterKeyProvider(**kms_kwargs) + + # Create the custom signing CMM using the master_key_provider + cmm = CustomSigningSuiteOnlyCMM(master_key_provider=master_key_provider) + + encrypt_decrypt_with_cmm(cmm=cmm, + source_plaintext=plaintext) + + +def test_v3_default_cmm(): + """Test method for encryption and decryption using V3 default CMM.""" + plaintext = static_plaintext + cmk_arn = get_cmk_arn() + botocore_session = botocore.session.Session() + + # Create a KMS master key provider. + kms_kwargs = dict(key_ids=[cmk_arn]) + if botocore_session is not None: + kms_kwargs["botocore_session"] = botocore_session + master_key_provider = aws_encryption_sdk.StrictAwsKmsMasterKeyProvider(**kms_kwargs) + + # Create the V3 default CMM (V3DefaultCryptoMaterialsManager) using the master_key_provider + cmm = V3DefaultCryptoMaterialsManager(master_key_provider=master_key_provider) + + encrypt_decrypt_with_cmm(cmm=cmm, + source_plaintext=plaintext) diff --git a/examples/test/legacy/v3_default_cmm.py b/examples/test/legacy/v3_default_cmm.py new file mode 100644 index 000000000..f077e26c9 --- /dev/null +++ b/examples/test/legacy/v3_default_cmm.py @@ -0,0 +1,159 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +"""Copy-paste of the V3 default CMM with small changes to pass linters.""" +import logging + +import attr + +from aws_encryption_sdk.exceptions import MasterKeyProviderError, SerializationError +from aws_encryption_sdk.identifiers import CommitmentPolicy +from aws_encryption_sdk.internal.crypto.authentication import Signer, Verifier +from aws_encryption_sdk.internal.crypto.elliptic_curve import generate_ecc_signing_key +from aws_encryption_sdk.internal.defaults import ALGORITHM, ALGORITHM_COMMIT_KEY, ENCODED_SIGNER_KEY +from aws_encryption_sdk.internal.str_ops import to_str +from aws_encryption_sdk.internal.utils import prepare_data_keys +from aws_encryption_sdk.internal.utils.commitment import ( + validate_commitment_policy_on_decrypt, + validate_commitment_policy_on_encrypt, +) +from aws_encryption_sdk.key_providers.base import MasterKeyProvider +from aws_encryption_sdk.materials_managers import DecryptionMaterials, EncryptionMaterials +from aws_encryption_sdk.materials_managers.base import CryptoMaterialsManager + +_LOGGER = logging.getLogger(__name__) + + +@attr.s(hash=False) +class V3DefaultCryptoMaterialsManager(CryptoMaterialsManager): + """Copy of the default crypto material manager for ESDK V3. + + This is a copy-paste of the DefaultCryptoMaterialsManager implementation + from the V3 ESDK commit: 98b5eb7c2bd7d1b2a3380aacfa508e8721c4d8a9 + This CMM is used to explicitly assert that the V3 implementation of + the DefaultCMM is compatible with future version's logic, + which implicitly asserts that custom implementations of V3-compatible CMMs + are also compatible with future version's logic. + + :param master_key_provider: Master key provider to use + :type master_key_provider: aws_encryption_sdk.key_providers.base.MasterKeyProvider + """ + + master_key_provider = attr.ib(validator=attr.validators.instance_of(MasterKeyProvider)) + +# pylint: disable=no-self-use + def _generate_signing_key_and_update_encryption_context(self, algorithm, encryption_context): + """Generates a signing key based on the provided algorithm. + + :param algorithm: Algorithm for which to generate signing key + :type algorithm: aws_encryption_sdk.identifiers.Algorithm + :param dict encryption_context: Encryption context from request + :returns: Signing key bytes + :rtype: bytes or None + """ + _LOGGER.debug("Generating signing key") + if algorithm.signing_algorithm_info is None: + return None + + signer = Signer(algorithm=algorithm, key=generate_ecc_signing_key(algorithm=algorithm)) + encryption_context[ENCODED_SIGNER_KEY] = to_str(signer.encoded_public_key()) + return signer.key_bytes() + + def get_encryption_materials(self, request): + """Creates encryption materials using underlying master key provider. + + :param request: encryption materials request + :type request: aws_encryption_sdk.materials_managers.EncryptionMaterialsRequest + :returns: encryption materials + :rtype: aws_encryption_sdk.materials_managers.EncryptionMaterials + :raises MasterKeyProviderError: if no master keys are available from the underlying master key provider + :raises MasterKeyProviderError: if the primary master key provided by the underlying master key provider + is not included in the full set of master keys provided by that provider + :raises ActionNotAllowedError: if the commitment policy in the request is violated by the algorithm being + used + """ + default_algorithm = ALGORITHM + if request.commitment_policy in ( + CommitmentPolicy.REQUIRE_ENCRYPT_REQUIRE_DECRYPT, + CommitmentPolicy.REQUIRE_ENCRYPT_ALLOW_DECRYPT, + ): + default_algorithm = ALGORITHM_COMMIT_KEY + algorithm = request.algorithm if request.algorithm is not None else default_algorithm + + validate_commitment_policy_on_encrypt(request.commitment_policy, request.algorithm) + + encryption_context = request.encryption_context.copy() + + signing_key = self._generate_signing_key_and_update_encryption_context(algorithm, encryption_context) + + primary_master_key, master_keys = self.master_key_provider.master_keys_for_encryption( + encryption_context=encryption_context, + plaintext_rostream=request.plaintext_rostream, + plaintext_length=request.plaintext_length, + ) + if not master_keys: + raise MasterKeyProviderError("No Master Keys available from Master Key Provider") + if primary_master_key not in master_keys: + raise MasterKeyProviderError("Primary Master Key not in provided Master Keys") + + data_encryption_key, encrypted_data_keys = prepare_data_keys( + primary_master_key=primary_master_key, + master_keys=master_keys, + algorithm=algorithm, + encryption_context=encryption_context, + ) + + _LOGGER.debug("Post-encrypt encryption context: %s", encryption_context) + + return EncryptionMaterials( + algorithm=algorithm, + data_encryption_key=data_encryption_key, + encrypted_data_keys=encrypted_data_keys, + encryption_context=encryption_context, + signing_key=signing_key, + ) + +# pylint: disable=no-self-use + def _load_verification_key_from_encryption_context(self, algorithm, encryption_context): + """Loads the verification key from the encryption context if used by algorithm suite. + + :param algorithm: Algorithm for which to generate signing key + :type algorithm: aws_encryption_sdk.identifiers.Algorithm + :param dict encryption_context: Encryption context from request + :returns: Raw verification key + :rtype: bytes + :raises SerializationError: if algorithm suite requires message signing and no verification key is found + """ + encoded_verification_key = encryption_context.get(ENCODED_SIGNER_KEY, None) + + if algorithm.signing_algorithm_info is not None and encoded_verification_key is None: + raise SerializationError("No signature verification key found in header for signed algorithm.") + + if algorithm.signing_algorithm_info is None: + if encoded_verification_key is not None: + raise SerializationError("Signature verification key found in header for non-signed algorithm.") + return None + + verifier = Verifier.from_encoded_point(algorithm=algorithm, encoded_point=encoded_verification_key) + return verifier.key_bytes() + + def decrypt_materials(self, request): + """Obtains a plaintext data key from one or more encrypted data keys + using underlying master key provider. + + :param request: decrypt materials request + :type request: aws_encryption_sdk.materials_managers.DecryptionMaterialsRequest + :returns: decryption materials + :rtype: aws_encryption_sdk.materials_managers.DecryptionMaterials + """ + validate_commitment_policy_on_decrypt(request.commitment_policy, request.algorithm) + + data_key = self.master_key_provider.decrypt_data_key_from_list( + encrypted_data_keys=request.encrypted_data_keys, + algorithm=request.algorithm, + encryption_context=request.encryption_context, + ) + verification_key = self._load_verification_key_from_encryption_context( + algorithm=request.algorithm, encryption_context=request.encryption_context + ) + + return DecryptionMaterials(data_key=data_key, verification_key=verification_key) diff --git a/examples/test/migration/test_i_migration_aws_kms_key_example.py b/examples/test/migration/test_i_migration_aws_kms_key_example.py index d4cf49ce9..612a896ba 100644 --- a/examples/test/migration/test_i_migration_aws_kms_key_example.py +++ b/examples/test/migration/test_i_migration_aws_kms_key_example.py @@ -3,9 +3,7 @@ """Test suite for the migration_aws_kms_key_example.""" import pytest -from ...src.migration.migration_aws_kms_key_example import ( - migration_aws_kms_key, -) +from ...src.migration.migration_aws_kms_key_example import migration_aws_kms_key pytestmark = [pytest.mark.examples] diff --git a/examples/test/migration/test_i_migration_raw_aes_key_example.py b/examples/test/migration/test_i_migration_raw_aes_key_example.py index 7601e7dc0..d5e4f7789 100644 --- a/examples/test/migration/test_i_migration_raw_aes_key_example.py +++ b/examples/test/migration/test_i_migration_raw_aes_key_example.py @@ -3,9 +3,7 @@ """Test suite for the migration_raw_aes_key_example.""" import pytest -from ...src.migration.migration_raw_aes_key_example import ( - migration_raw_aes_key, -) +from ...src.migration.migration_raw_aes_key_example import migration_raw_aes_key pytestmark = [pytest.mark.examples] diff --git a/examples/test/migration/test_i_migration_raw_rsa_key_example.py b/examples/test/migration/test_i_migration_raw_rsa_key_example.py index 9e111d25a..238dcbaab 100644 --- a/examples/test/migration/test_i_migration_raw_rsa_key_example.py +++ b/examples/test/migration/test_i_migration_raw_rsa_key_example.py @@ -3,9 +3,7 @@ """Test suite for the migration_raw_rsa_key_example.""" import pytest -from ...src.migration.migration_raw_rsa_key_example import ( - migration_raw_rsa_key, -) +from ...src.migration.migration_raw_rsa_key_example import migration_raw_rsa_key pytestmark = [pytest.mark.examples] diff --git a/examples/test/test_i_custom_mpl_cmm_example.py b/examples/test/test_i_custom_mpl_cmm_example.py new file mode 100644 index 000000000..d98b6b6b9 --- /dev/null +++ b/examples/test/test_i_custom_mpl_cmm_example.py @@ -0,0 +1,39 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +"""Test suite for encryption and decryption using custom CMM.""" +import boto3 +import pytest +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 ..src.custom_mpl_cmm_example import MPLCustomSigningSuiteOnlyCMM, encrypt_decrypt_with_cmm + +pytestmark = [pytest.mark.examples] + + +def test_custom_cmm_example(): + """Test method for encryption and decryption using V3 default CMM.""" + kms_key_id = "arn:aws:kms:us-west-2:658956600833:key/b3537ef1-d8dc-4780-9f5a-55776cbb2f7f" + + # Create KMS keyring to use with the CMM + kms_client = boto3.client('kms', region_name="us-west-2") + + mat_prov: AwsCryptographicMaterialProviders = AwsCryptographicMaterialProviders( + config=MaterialProvidersConfig() + ) + + keyring_input: CreateAwsKmsKeyringInput = CreateAwsKmsKeyringInput( + kms_key_id=kms_key_id, + kms_client=kms_client + ) + + kms_keyring: IKeyring = mat_prov.create_aws_kms_keyring( + input=keyring_input + ) + + # Create the custom MPL signing CMM using the keyring + cmm = MPLCustomSigningSuiteOnlyCMM(keyring=kms_keyring) + + encrypt_decrypt_with_cmm(cmm=cmm) diff --git a/examples/test/test_i_default_cryptographic_materials_manager_example.py b/examples/test/test_i_default_cryptographic_materials_manager_example.py new file mode 100644 index 000000000..8a18f655d --- /dev/null +++ b/examples/test/test_i_default_cryptographic_materials_manager_example.py @@ -0,0 +1,14 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +"""Test suite for the default Cryptographic Materials Manager example.""" +import pytest + +from ..src.default_cryptographic_materials_manager_example import encrypt_and_decrypt_with_default_cmm + +pytestmark = [pytest.mark.examples] + + +def test_encrypt_and_decrypt_with_default_cmm(): + """Test function for encrypt and decrypt using the default Cryptographic Materials Manager example.""" + kms_key_id = "arn:aws:kms:us-west-2:658956600833:key/b3537ef1-d8dc-4780-9f5a-55776cbb2f7f" + encrypt_and_decrypt_with_default_cmm(kms_key_id) diff --git a/tox.ini b/tox.ini index 9152f51a6..28be94a63 100644 --- a/tox.ini +++ b/tox.ini @@ -169,10 +169,12 @@ deps = {[testenv:flake8]deps} commands = flake8 examples/src/ flake8 \ - # Ingore D103 missing docstring errors in tests (test names should be self-documenting) + # Ignore D103 missing docstring errors in tests (test names should be self-documenting) # E203 is not PEP8 compliant https://github.com/ambv/black#slices # W503 is not PEP8 compliant https://github.com/ambv/black#line-breaks--binary-operators --ignore D103,E203,W503 \ + # copy-paste test for v3_default_cmm; intentionally not changing code + --per-file-ignores 'examples/test/legacy/v3_default_cmm.py: D205,D400,D401' \ examples/test/ [testenv:pylint]