From 0d2963176e4b3d4d298876189870fd7f6fbc848e Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Tue, 18 Jun 2019 14:07:50 -0700 Subject: [PATCH 01/61] Adding Keyring API --- src/aws_encryption_sdk/keyring/__init__.py | 13 ++++++ src/aws_encryption_sdk/keyring/base.py | 40 +++++++++++++++++++ src/aws_encryption_sdk/keyring/raw_keyring.py | 0 3 files changed, 53 insertions(+) create mode 100644 src/aws_encryption_sdk/keyring/__init__.py create mode 100644 src/aws_encryption_sdk/keyring/base.py create mode 100644 src/aws_encryption_sdk/keyring/raw_keyring.py diff --git a/src/aws_encryption_sdk/keyring/__init__.py b/src/aws_encryption_sdk/keyring/__init__.py new file mode 100644 index 000000000..b9037ea16 --- /dev/null +++ b/src/aws_encryption_sdk/keyring/__init__.py @@ -0,0 +1,13 @@ +# Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"). You +# may not use this file except in compliance with the License. A copy of +# the License is located at +# +# http://aws.amazon.com/apache2.0/ +# +# or in the "license" file accompanying this file. This file is +# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF +# ANY KIND, either express or implied. See the License for the specific +# language governing permissions and limitations under the License. +"""All provided keyrings.""" diff --git a/src/aws_encryption_sdk/keyring/base.py b/src/aws_encryption_sdk/keyring/base.py new file mode 100644 index 000000000..0d6b9000c --- /dev/null +++ b/src/aws_encryption_sdk/keyring/base.py @@ -0,0 +1,40 @@ +# Copyright 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"). You +# may not use this file except in compliance with the License. A copy of +# the License is located at +# +# http://aws.amazon.com/apache2.0/ +# +# or in the "license" file accompanying this file. This file is +# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF +# ANY KIND, either express or implied. See the License for the specific +# language governing permissions and limitations under the License. +"""Base class interface for Keyrings.""" + + +class Keyring(object): + def on_encrypt(self, encryption_materials): + """Generates a data key and encrypts it using all wrapping keys the Keyring is associated with. + + :param encryption_materials: Contains signing key, encryption context and algorithm suite + required to encrypt data key + :type : aws_encryption_sdk.materials_managers.EncryptionMaterials + :returns encryption_materials: Contains signing key, unencrypted data key, encrypted data keys, + encryption context and algorithm suite required to encrypt data key + :rtype : aws_encryption_sdk.materials_managers.EncryptionMaterials + :raises AttributeError: if encryption materials not available + """ + raise NotImplementedError("Keyring does not implement on_encrypt function") + + def on_decrypt(self, decryption_materials): + """Tries to decrypt one of the keys in the list of encrypted data keys using wrapping keys + the Keyring is associated with. + + :param decryption_materials: Contains verification key, list of encrypted data keys. + :type : aws_encryption_sdk.materials_managers.DecryptionMaterials + :returns decryption_materials: Contains verification key, list of encrypted data keys and decrypted data key. + :rtype : aws_encryption_sdk.materials_managers.DecryptionMaterials + :raises AttributeError: if decryption materials not available + """ + raise NotImplementedError("Keyring does not implement on_decrypt function") diff --git a/src/aws_encryption_sdk/keyring/raw_keyring.py b/src/aws_encryption_sdk/keyring/raw_keyring.py new file mode 100644 index 000000000..e69de29bb From 237a2af41266312a6bd0a374f683395e31b169c3 Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Tue, 18 Jun 2019 14:51:28 -0700 Subject: [PATCH 02/61] Added docstring to public class --- src/aws_encryption_sdk/keyring/base.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/aws_encryption_sdk/keyring/base.py b/src/aws_encryption_sdk/keyring/base.py index 0d6b9000c..575758edd 100644 --- a/src/aws_encryption_sdk/keyring/base.py +++ b/src/aws_encryption_sdk/keyring/base.py @@ -14,6 +14,8 @@ class Keyring(object): + """Parent interface for Keyring classes. + """ def on_encrypt(self, encryption_materials): """Generates a data key and encrypts it using all wrapping keys the Keyring is associated with. From 9bbdf835e40522a39581d20fbc780463f302f2e6 Mon Sep 17 00:00:00 2001 From: MeghaShetty Date: Tue, 18 Jun 2019 14:12:41 -0700 Subject: [PATCH 03/61] Delete __init__.py --- src/aws_encryption_sdk/keyring/__init__.py | 13 ------------- 1 file changed, 13 deletions(-) delete mode 100644 src/aws_encryption_sdk/keyring/__init__.py diff --git a/src/aws_encryption_sdk/keyring/__init__.py b/src/aws_encryption_sdk/keyring/__init__.py deleted file mode 100644 index b9037ea16..000000000 --- a/src/aws_encryption_sdk/keyring/__init__.py +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"). You -# may not use this file except in compliance with the License. A copy of -# the License is located at -# -# http://aws.amazon.com/apache2.0/ -# -# or in the "license" file accompanying this file. This file is -# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF -# ANY KIND, either express or implied. See the License for the specific -# language governing permissions and limitations under the License. -"""All provided keyrings.""" From 1a14a3b82af0891b2190f294309b7573904dfd67 Mon Sep 17 00:00:00 2001 From: MeghaShetty Date: Tue, 18 Jun 2019 14:12:53 -0700 Subject: [PATCH 04/61] Delete raw_keyring.py --- src/aws_encryption_sdk/keyring/raw_keyring.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 src/aws_encryption_sdk/keyring/raw_keyring.py diff --git a/src/aws_encryption_sdk/keyring/raw_keyring.py b/src/aws_encryption_sdk/keyring/raw_keyring.py deleted file mode 100644 index e69de29bb..000000000 From c1a1c77e7c5a11f21825d3acb5c4be54e9247d1d Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Tue, 18 Jun 2019 15:36:18 -0700 Subject: [PATCH 05/61] Edited docstring --- src/aws_encryption_sdk/keyring/base.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/aws_encryption_sdk/keyring/base.py b/src/aws_encryption_sdk/keyring/base.py index 575758edd..a1e77e905 100644 --- a/src/aws_encryption_sdk/keyring/base.py +++ b/src/aws_encryption_sdk/keyring/base.py @@ -16,6 +16,7 @@ class Keyring(object): """Parent interface for Keyring classes. """ + def on_encrypt(self, encryption_materials): """Generates a data key and encrypts it using all wrapping keys the Keyring is associated with. From 66b348f45f4edba14c313c8d315ca7da8286380f Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Tue, 18 Jun 2019 16:07:06 -0700 Subject: [PATCH 06/61] Edited docstring again --- src/aws_encryption_sdk/keyring/base.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/aws_encryption_sdk/keyring/base.py b/src/aws_encryption_sdk/keyring/base.py index a1e77e905..88e3ae068 100644 --- a/src/aws_encryption_sdk/keyring/base.py +++ b/src/aws_encryption_sdk/keyring/base.py @@ -14,8 +14,7 @@ class Keyring(object): - """Parent interface for Keyring classes. - """ + """Parent interface for Keyring classes.""" def on_encrypt(self, encryption_materials): """Generates a data key and encrypts it using all wrapping keys the Keyring is associated with. From 4a0a1c6dcc1cd828f2e63fafdca95a0bc4d82725 Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Wed, 19 Jun 2019 12:58:14 -0700 Subject: [PATCH 07/61] Changes in docstring statements --- src/aws_encryption_sdk/keyring/__init__.py | 13 ++++ src/aws_encryption_sdk/keyring/base.py | 5 +- src/aws_encryption_sdk/keyring/raw_keyring.py | 74 +++++++++++++++++++ 3 files changed, 89 insertions(+), 3 deletions(-) create mode 100644 src/aws_encryption_sdk/keyring/__init__.py create mode 100644 src/aws_encryption_sdk/keyring/raw_keyring.py diff --git a/src/aws_encryption_sdk/keyring/__init__.py b/src/aws_encryption_sdk/keyring/__init__.py new file mode 100644 index 000000000..ada03b4d7 --- /dev/null +++ b/src/aws_encryption_sdk/keyring/__init__.py @@ -0,0 +1,13 @@ +# Copyright 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"). You +# may not use this file except in compliance with the License. A copy of +# the License is located at +# +# http://aws.amazon.com/apache2.0/ +# +# or in the "license" file accompanying this file. This file is +# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF +# ANY KIND, either express or implied. See the License for the specific +# language governing permissions and limitations under the License. +"""All provided Keyrings.""" diff --git a/src/aws_encryption_sdk/keyring/base.py b/src/aws_encryption_sdk/keyring/base.py index 88e3ae068..19f2ae169 100644 --- a/src/aws_encryption_sdk/keyring/base.py +++ b/src/aws_encryption_sdk/keyring/base.py @@ -17,7 +17,7 @@ class Keyring(object): """Parent interface for Keyring classes.""" def on_encrypt(self, encryption_materials): - """Generates a data key and encrypts it using all wrapping keys the Keyring is associated with. + """Generate a data key and encrypt it using all wrapping keys the Keyring is associated with. :param encryption_materials: Contains signing key, encryption context and algorithm suite required to encrypt data key @@ -30,8 +30,7 @@ def on_encrypt(self, encryption_materials): raise NotImplementedError("Keyring does not implement on_encrypt function") def on_decrypt(self, decryption_materials): - """Tries to decrypt one of the keys in the list of encrypted data keys using wrapping keys - the Keyring is associated with. + """Attempt to decrypt the encrypted data keys. :param decryption_materials: Contains verification key, list of encrypted data keys. :type : aws_encryption_sdk.materials_managers.DecryptionMaterials diff --git a/src/aws_encryption_sdk/keyring/raw_keyring.py b/src/aws_encryption_sdk/keyring/raw_keyring.py new file mode 100644 index 000000000..30d2bbd5a --- /dev/null +++ b/src/aws_encryption_sdk/keyring/raw_keyring.py @@ -0,0 +1,74 @@ +# Copyright 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"). You +# may not use this file except in compliance with the License. A copy of +# the License is located at +# +# http://aws.amazon.com/apache2.0/ +# +# or in the "license" file accompanying this file. This file is +# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF +# ANY KIND, either express or implied. See the License for the specific +# language governing permissions and limitations under the License. +"""Resources required for Raw Keyrings.""" +import os +import attr + +import aws_encryption_sdk.internal.formatting.deserialize +import aws_encryption_sdk.internal.formatting.serialize +from aws_encryption_sdk.internal.crypto.wrapping_keys import WrappingKey +from aws_encryption_sdk.keyring.base import Keyring +from aws_encryption_sdk.structures import DataKey, RawDataKey + + +class RawAESKeyring(Keyring): + """Public class for Raw AES Keyring.""" + + def on_encrypt(self, encryption_materials): + # Generate data key + plaintext_data_key = os.urandom(encryption_materials.algorithm.kdf_input_len) + + # Encrypt data key + wrapping_key = attr.ib(hash=True, validator=attr.validators.instance_of(WrappingKey)) + encrypted_wrapped_key = wrapping_key.encrypt( + plaintext_data_key=plaintext_data_key, + encryption_context=encryption_materials.encryption_context + ) + encrypted_data_key = aws_encryption_sdk.internal.formatting.serialize.serialize_wrapped_key( + # WHAAAAT + key_provider=self.key_provider, + wrapping_algorithm=wrapping_key.wrapping_algorithm, + # WHAAAAT + wrapping_key_id=self.key_id, + encrypted_wrapped_key=encrypted_wrapped_key, + ) + + # Update keyring trace + + # Update encryption materials + encryption_materials.data_encryption_key = RawDataKey( + # WHAAAAT + key_provider=self.key_provider, + data_key=plaintext_data_key + ) + encryption_materials.encrypted_data_keys.add(encrypted_data_key) + + return encryption_materials + + def on_decrypt(self, decryption_materials): + # Decrypt data key + + + # Update keyring trace + + return decryption_materials + + +class RawRSAKeyring(Keyring): + """Public class for Raw RSA Keyring.""" + + def on_encrypt(self, encryption_materials): + return encryption_materials + + def on_decrypt(self, decryption_materials): + return decryption_materials From 5f6fcb958274da6109a6ccdab8b3fae010c21fdf Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Wed, 19 Jun 2019 13:06:19 -0700 Subject: [PATCH 08/61] Docstring changes --- src/aws_encryption_sdk/keyring/base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/aws_encryption_sdk/keyring/base.py b/src/aws_encryption_sdk/keyring/base.py index 19f2ae169..cdec0842a 100644 --- a/src/aws_encryption_sdk/keyring/base.py +++ b/src/aws_encryption_sdk/keyring/base.py @@ -17,7 +17,7 @@ class Keyring(object): """Parent interface for Keyring classes.""" def on_encrypt(self, encryption_materials): - """Generate a data key and encrypt it using all wrapping keys the Keyring is associated with. + """Generate a data key if not present and encrypt it using any available wrapping key. :param encryption_materials: Contains signing key, encryption context and algorithm suite required to encrypt data key From 9d8d96407e69229985625e16caaff72e3630c774 Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Thu, 20 Jun 2019 13:53:32 -0700 Subject: [PATCH 09/61] Changes in docstring --- src/aws_encryption_sdk/keyring/base.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/aws_encryption_sdk/keyring/base.py b/src/aws_encryption_sdk/keyring/base.py index cdec0842a..3c4689d70 100644 --- a/src/aws_encryption_sdk/keyring/base.py +++ b/src/aws_encryption_sdk/keyring/base.py @@ -21,11 +21,11 @@ def on_encrypt(self, encryption_materials): :param encryption_materials: Contains signing key, encryption context and algorithm suite required to encrypt data key - :type : aws_encryption_sdk.materials_managers.EncryptionMaterials - :returns encryption_materials: Contains signing key, unencrypted data key, encrypted data keys, + :type encryption_materials: aws_encryption_sdk.materials_managers.EncryptionMaterials + :returns: Contains signing key, unencrypted data key, encrypted data keys, encryption context and algorithm suite required to encrypt data key - :rtype : aws_encryption_sdk.materials_managers.EncryptionMaterials - :raises AttributeError: if encryption materials not available + :rtype: aws_encryption_sdk.materials_managers.EncryptionMaterials + :raises NotImplementedError: if method is not implemented """ raise NotImplementedError("Keyring does not implement on_encrypt function") @@ -33,9 +33,9 @@ def on_decrypt(self, decryption_materials): """Attempt to decrypt the encrypted data keys. :param decryption_materials: Contains verification key, list of encrypted data keys. - :type : aws_encryption_sdk.materials_managers.DecryptionMaterials - :returns decryption_materials: Contains verification key, list of encrypted data keys and decrypted data key. - :rtype : aws_encryption_sdk.materials_managers.DecryptionMaterials - :raises AttributeError: if decryption materials not available + :type decryption_materials: aws_encryption_sdk.materials_managers.DecryptionMaterials + :returns: Contains verification key, list of encrypted data keys and decrypted data key. + :rtype: aws_encryption_sdk.materials_managers.DecryptionMaterials + :raises NotImplementedError: if method is not implemented """ raise NotImplementedError("Keyring does not implement on_decrypt function") From 83ccdd3f286fe9b6aac726c99ee429c288bca7e4 Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Thu, 20 Jun 2019 14:16:36 -0700 Subject: [PATCH 10/61] Raw keyring initial --- src/aws_encryption_sdk/keyring/raw_keyring.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/aws_encryption_sdk/keyring/raw_keyring.py b/src/aws_encryption_sdk/keyring/raw_keyring.py index 30d2bbd5a..2a853a462 100644 --- a/src/aws_encryption_sdk/keyring/raw_keyring.py +++ b/src/aws_encryption_sdk/keyring/raw_keyring.py @@ -12,6 +12,7 @@ # language governing permissions and limitations under the License. """Resources required for Raw Keyrings.""" import os + import attr import aws_encryption_sdk.internal.formatting.deserialize @@ -31,8 +32,7 @@ def on_encrypt(self, encryption_materials): # Encrypt data key wrapping_key = attr.ib(hash=True, validator=attr.validators.instance_of(WrappingKey)) encrypted_wrapped_key = wrapping_key.encrypt( - plaintext_data_key=plaintext_data_key, - encryption_context=encryption_materials.encryption_context + plaintext_data_key=plaintext_data_key, encryption_context=encryption_materials.encryption_context ) encrypted_data_key = aws_encryption_sdk.internal.formatting.serialize.serialize_wrapped_key( # WHAAAAT @@ -49,7 +49,7 @@ def on_encrypt(self, encryption_materials): encryption_materials.data_encryption_key = RawDataKey( # WHAAAAT key_provider=self.key_provider, - data_key=plaintext_data_key + data_key=plaintext_data_key, ) encryption_materials.encrypted_data_keys.add(encrypted_data_key) @@ -58,7 +58,6 @@ def on_encrypt(self, encryption_materials): def on_decrypt(self, decryption_materials): # Decrypt data key - # Update keyring trace return decryption_materials From aed1ed7e3d802fdba19482ecd1a214bed3ceb817 Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Thu, 20 Jun 2019 14:19:54 -0700 Subject: [PATCH 11/61] Raw keyring encrypt commit --- requirements.txt | 1 + src/aws_encryption_sdk/keyring/raw_keyring.py | 28 +++++++++++++------ 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/requirements.txt b/requirements.txt index f04114485..7540d66bf 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,4 @@ +six boto3>=1.4.4 cryptography>=1.8.1 attrs>=17.4.0 diff --git a/src/aws_encryption_sdk/keyring/raw_keyring.py b/src/aws_encryption_sdk/keyring/raw_keyring.py index 2a853a462..a2ab060bb 100644 --- a/src/aws_encryption_sdk/keyring/raw_keyring.py +++ b/src/aws_encryption_sdk/keyring/raw_keyring.py @@ -18,27 +18,38 @@ import aws_encryption_sdk.internal.formatting.deserialize import aws_encryption_sdk.internal.formatting.serialize from aws_encryption_sdk.internal.crypto.wrapping_keys import WrappingKey +from aws_encryption_sdk.identifiers import WrappingAlgorithm from aws_encryption_sdk.keyring.base import Keyring -from aws_encryption_sdk.structures import DataKey, RawDataKey +from aws_encryption_sdk.structures import DataKey, RawDataKey, MasterKeyInfo +@attr.s class RawAESKeyring(Keyring): """Public class for Raw AES Keyring.""" + provider_id = attr.ib(validator=attr.validators.instance_of(str)) + key_id = attr.ib(hash=True, validator=attr.validators.instance_of(bytes)) + wrapping_key = attr.ib(hash=True, validator=attr.validators.instance_of(WrappingKey)) + wrapping_algorithm = attr.ib(validator=attr.validators.instance_of(WrappingAlgorithm)) + + key_provider = MasterKeyInfo( + provider_id=provider_id, + key_info=key_id + ) + def on_encrypt(self, encryption_materials): # Generate data key plaintext_data_key = os.urandom(encryption_materials.algorithm.kdf_input_len) # Encrypt data key - wrapping_key = attr.ib(hash=True, validator=attr.validators.instance_of(WrappingKey)) - encrypted_wrapped_key = wrapping_key.encrypt( - plaintext_data_key=plaintext_data_key, encryption_context=encryption_materials.encryption_context + encrypted_wrapped_key = self.wrapping_key.encrypt( + plaintext_data_key=plaintext_data_key, + encryption_context=encryption_materials.encryption_context ) + encrypted_data_key = aws_encryption_sdk.internal.formatting.serialize.serialize_wrapped_key( - # WHAAAAT key_provider=self.key_provider, - wrapping_algorithm=wrapping_key.wrapping_algorithm, - # WHAAAAT + wrapping_algorithm=self.wrapping_algorithm, wrapping_key_id=self.key_id, encrypted_wrapped_key=encrypted_wrapped_key, ) @@ -47,7 +58,6 @@ def on_encrypt(self, encryption_materials): # Update encryption materials encryption_materials.data_encryption_key = RawDataKey( - # WHAAAAT key_provider=self.key_provider, data_key=plaintext_data_key, ) @@ -71,3 +81,5 @@ def on_encrypt(self, encryption_materials): def on_decrypt(self, decryption_materials): return decryption_materials + + From dc9352c948248f07962e89492097dd5e8ee4b5e6 Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Thu, 20 Jun 2019 16:17:06 -0700 Subject: [PATCH 12/61] Encrypt functions for Raw RSA and AES --- src/aws_encryption_sdk/keyring/raw_keyring.py | 53 +++++++++++++------ 1 file changed, 38 insertions(+), 15 deletions(-) diff --git a/src/aws_encryption_sdk/keyring/raw_keyring.py b/src/aws_encryption_sdk/keyring/raw_keyring.py index a2ab060bb..9bc5ad03e 100644 --- a/src/aws_encryption_sdk/keyring/raw_keyring.py +++ b/src/aws_encryption_sdk/keyring/raw_keyring.py @@ -17,25 +17,22 @@ import aws_encryption_sdk.internal.formatting.deserialize import aws_encryption_sdk.internal.formatting.serialize -from aws_encryption_sdk.internal.crypto.wrapping_keys import WrappingKey from aws_encryption_sdk.identifiers import WrappingAlgorithm +from aws_encryption_sdk.internal.crypto.wrapping_keys import WrappingKey from aws_encryption_sdk.keyring.base import Keyring -from aws_encryption_sdk.structures import DataKey, RawDataKey, MasterKeyInfo +from aws_encryption_sdk.structures import DataKey, MasterKeyInfo, RawDataKey @attr.s class RawAESKeyring(Keyring): """Public class for Raw AES Keyring.""" - provider_id = attr.ib(validator=attr.validators.instance_of(str)) - key_id = attr.ib(hash=True, validator=attr.validators.instance_of(bytes)) + key_namespace = attr.ib(validator=attr.validators.instance_of(str)) + key_name = attr.ib(hash=True, validator=attr.validators.instance_of(bytes)) wrapping_key = attr.ib(hash=True, validator=attr.validators.instance_of(WrappingKey)) wrapping_algorithm = attr.ib(validator=attr.validators.instance_of(WrappingAlgorithm)) - key_provider = MasterKeyInfo( - provider_id=provider_id, - key_info=key_id - ) + key_provider = MasterKeyInfo(provider_id=key_namespace, key_info=key_name) def on_encrypt(self, encryption_materials): # Generate data key @@ -43,14 +40,13 @@ def on_encrypt(self, encryption_materials): # Encrypt data key encrypted_wrapped_key = self.wrapping_key.encrypt( - plaintext_data_key=plaintext_data_key, - encryption_context=encryption_materials.encryption_context + plaintext_data_key=plaintext_data_key, encryption_context=encryption_materials.encryption_context ) encrypted_data_key = aws_encryption_sdk.internal.formatting.serialize.serialize_wrapped_key( key_provider=self.key_provider, wrapping_algorithm=self.wrapping_algorithm, - wrapping_key_id=self.key_id, + wrapping_key_id=self.key_name, encrypted_wrapped_key=encrypted_wrapped_key, ) @@ -58,8 +54,7 @@ def on_encrypt(self, encryption_materials): # Update encryption materials encryption_materials.data_encryption_key = RawDataKey( - key_provider=self.key_provider, - data_key=plaintext_data_key, + key_provider=self.key_provider, data_key=plaintext_data_key ) encryption_materials.encrypted_data_keys.add(encrypted_data_key) @@ -76,10 +71,38 @@ def on_decrypt(self, decryption_materials): class RawRSAKeyring(Keyring): """Public class for Raw RSA Keyring.""" + key_namespace = attr.ib(validator=attr.validators.instance_of(str)) + key_name = attr.ib(hash=True, validator=attr.validators.instance_of(bytes)) + wrapping_key = attr.ib(hash=True, validator=attr.validators.instance_of(WrappingKey)) + wrapping_algorithm = attr.ib(validator=attr.validators.instance_of(WrappingAlgorithm)) + + key_provider = MasterKeyInfo(provider_id=key_namespace, key_info=key_name) + def on_encrypt(self, encryption_materials): + # Generate data key + plaintext_data_key = os.urandom(encryption_materials.algorithm.kdf_input_len) + + # Encrypt data key + encrypted_wrapped_key = self.wrapping_key.encrypt( + plaintext_data_key=plaintext_data_key, encryption_context=encryption_materials.encryption_context + ) + + encrypted_data_key = aws_encryption_sdk.internal.formatting.serialize.serialize_wrapped_key( + key_provider=self.key_provider, + wrapping_algorithm=self.wrapping_algorithm, + wrapping_key_id=self.key_name, + encrypted_wrapped_key=encrypted_wrapped_key, + ) + + # Update keyring trace + + # Update encryption materials + encryption_materials.data_encryption_key = RawDataKey( + key_provider=self.key_provider, data_key=plaintext_data_key + ) + encryption_materials.encrypted_data_keys.add(encrypted_data_key) + return encryption_materials def on_decrypt(self, decryption_materials): return decryption_materials - - From b9c22b9b533c7ad9fbf28e6709f8342478e8b50e Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Thu, 20 Jun 2019 16:59:54 -0700 Subject: [PATCH 13/61] Raw RSA and AES initial --- src/aws_encryption_sdk/keyring/raw_keyring.py | 84 +++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/src/aws_encryption_sdk/keyring/raw_keyring.py b/src/aws_encryption_sdk/keyring/raw_keyring.py index 9bc5ad03e..74e19c653 100644 --- a/src/aws_encryption_sdk/keyring/raw_keyring.py +++ b/src/aws_encryption_sdk/keyring/raw_keyring.py @@ -12,6 +12,7 @@ # language governing permissions and limitations under the License. """Resources required for Raw Keyrings.""" import os +import struct import attr @@ -19,6 +20,7 @@ import aws_encryption_sdk.internal.formatting.serialize from aws_encryption_sdk.identifiers import WrappingAlgorithm from aws_encryption_sdk.internal.crypto.wrapping_keys import WrappingKey +from aws_encryption_sdk.internal.str_ops import to_bytes from aws_encryption_sdk.keyring.base import Keyring from aws_encryption_sdk.structures import DataKey, MasterKeyInfo, RawDataKey @@ -34,7 +36,25 @@ class RawAESKeyring(Keyring): key_provider = MasterKeyInfo(provider_id=key_namespace, key_info=key_name) + key_info_prefix = struct.pack( + ">{}sII".format(len(key_name)), + to_bytes(key_name), + # Tag Length is stored in bits, not bytes + wrapping_algorithm.algorithm.tag_len * 8, + wrapping_algorithm.algorithm.iv_len, + ) + def on_encrypt(self, encryption_materials): + """Generate a data key if not present and encrypt it using any available wrapping key. + + :param encryption_materials: Contains signing key, encryption context and algorithm suite + required to encrypt data key + :type encryption_materials: aws_encryption_sdk.materials_managers.EncryptionMaterials + :returns: Contains signing key, unencrypted data key, encrypted data keys, + encryption context and algorithm suite required to encrypt data key + :rtype: aws_encryption_sdk.materials_managers.EncryptionMaterials + """ + # Generate data key plaintext_data_key = os.urandom(encryption_materials.algorithm.kdf_input_len) @@ -61,7 +81,35 @@ def on_encrypt(self, encryption_materials): return encryption_materials def on_decrypt(self, decryption_materials): + """Attempt to decrypt the encrypted data keys. + + :param decryption_materials: Contains verification key, list of encrypted data keys. + :type decryption_materials: aws_encryption_sdk.materials_managers.DecryptionMaterials + :returns: Contains verification key, list of encrypted data keys and decrypted data key. + :rtype: aws_encryption_sdk.materials_managers.DecryptionMaterials + """ + # Decrypt data key + expected_key_info_len = len(self.key_info_prefix) + self.wrapping_algorithm.algorithm.iv_len + if ( + decryption_materials.encrypted_data_key.key_provider.provider_id == self.key_provider.provider_id + and len(decryption_materials.encrypted_data_key.key_provider.key_info) == expected_key_info_len + and decryption_materials.encrypted_data_key.key_provider.key_info.startswith(self.key_info_prefix) + ): + encrypted_wrapped_key = aws_encryption_sdk.internal.formatting.deserialize.deserialize_wrapped_key( + wrapping_algorithm=self.wrapping_algorithm, + wrapping_key_id=self.key_name, + wrapped_encrypted_key=decryption_materials.encrypted_data_key, + ) + plaintext_data_key = self.wrapping_key.decrypt( + encrypted_wrapped_data_key=encrypted_wrapped_key, + encryption_context=decryption_materials.encryption_context, + ) + decryption_materials.data_key = DataKey( + key_provider=decryption_materials.encrypted_data_key.key_provider, + data_key=plaintext_data_key, + encrypted_data_key=decryption_materials.encrypted_data_key.encrypted_data_key, + ) # Update keyring trace @@ -79,6 +127,16 @@ class RawRSAKeyring(Keyring): key_provider = MasterKeyInfo(provider_id=key_namespace, key_info=key_name) def on_encrypt(self, encryption_materials): + """Generate a data key if not present and encrypt it using any available wrapping key. + + :param encryption_materials: Contains signing key, encryption context and algorithm suite + required to encrypt data key + :type encryption_materials: aws_encryption_sdk.materials_managers.EncryptionMaterials + :returns: Contains signing key, unencrypted data key, encrypted data keys, + encryption context and algorithm suite required to encrypt data key + :rtype: aws_encryption_sdk.materials_managers.EncryptionMaterials + """ + # Generate data key plaintext_data_key = os.urandom(encryption_materials.algorithm.kdf_input_len) @@ -105,4 +163,30 @@ def on_encrypt(self, encryption_materials): return encryption_materials def on_decrypt(self, decryption_materials): + """Attempt to decrypt the encrypted data keys. + + :param decryption_materials: Contains verification key, list of encrypted data keys. + :type decryption_materials: aws_encryption_sdk.materials_managers.DecryptionMaterials + :returns: Contains verification key, list of encrypted data keys and decrypted data key. + :rtype: aws_encryption_sdk.materials_managers.DecryptionMaterials + """ + + # Decrypt data key + if decryption_materials.encrypted_data_key.key_provider == self.key_provider: + encrypted_wrapped_key = aws_encryption_sdk.internal.formatting.deserialize.deserialize_wrapped_key( + wrapping_algorithm=self.wrapping_algorithm, + wrapping_key_id=self.key_name, + wrapped_encrypted_key=decryption_materials.encrypted_data_key, + ) + plaintext_data_key = self.wrapping_key.decrypt( + encrypted_wrapped_data_key=encrypted_wrapped_key, + encryption_context=decryption_materials.encryption_context, + ) + decryption_materials.data_key = DataKey( + key_provider=decryption_materials.encrypted_data_key.key_provider, + data_key=plaintext_data_key, + encrypted_data_key=decryption_materials.encrypted_data_key.encrypted_data_key, + ) + + # Update keyring trace return decryption_materials From 369a744a7ed6d3886f119f453fd361c7db11a2e5 Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Fri, 21 Jun 2019 15:36:34 -0700 Subject: [PATCH 14/61] raw keyrings first commit --- .../internal/crypto/wrapping_keys.py | 2 +- .../keyring/multi_keyring.py | 0 src/aws_encryption_sdk/keyring/raw_keyring.py | 21 ++++++++++++++++--- 3 files changed, 19 insertions(+), 4 deletions(-) create mode 100644 src/aws_encryption_sdk/keyring/multi_keyring.py diff --git a/src/aws_encryption_sdk/internal/crypto/wrapping_keys.py b/src/aws_encryption_sdk/internal/crypto/wrapping_keys.py index 91f9fd834..047db4986 100644 --- a/src/aws_encryption_sdk/internal/crypto/wrapping_keys.py +++ b/src/aws_encryption_sdk/internal/crypto/wrapping_keys.py @@ -67,7 +67,7 @@ def encrypt(self, plaintext_data_key, encryption_context): :rtype: aws_encryption_sdk.internal.structures.EncryptedData """ if self.wrapping_algorithm.encryption_type is EncryptionType.ASYMMETRIC: - if self.wrapping_key_type is EncryptionKeyType.PRIVATE: + if self.wrapping_key_type is EncryptionKeyType.PRIVATE:x encrypted_key = self._wrapping_key.public_key().encrypt( plaintext=plaintext_data_key, padding=self.wrapping_algorithm.padding ) diff --git a/src/aws_encryption_sdk/keyring/multi_keyring.py b/src/aws_encryption_sdk/keyring/multi_keyring.py new file mode 100644 index 000000000..e69de29bb diff --git a/src/aws_encryption_sdk/keyring/raw_keyring.py b/src/aws_encryption_sdk/keyring/raw_keyring.py index 74e19c653..1defb85e0 100644 --- a/src/aws_encryption_sdk/keyring/raw_keyring.py +++ b/src/aws_encryption_sdk/keyring/raw_keyring.py @@ -63,6 +63,7 @@ def on_encrypt(self, encryption_materials): plaintext_data_key=plaintext_data_key, encryption_context=encryption_materials.encryption_context ) + # EncryptedData to EncryptedDataKey encrypted_data_key = aws_encryption_sdk.internal.formatting.serialize.serialize_wrapped_key( key_provider=self.key_provider, wrapping_algorithm=self.wrapping_algorithm, @@ -96,23 +97,29 @@ def on_decrypt(self, decryption_materials): and len(decryption_materials.encrypted_data_key.key_provider.key_info) == expected_key_info_len and decryption_materials.encrypted_data_key.key_provider.key_info.startswith(self.key_info_prefix) ): + + # Wrapped EncryptedDataKey to deserialized EncryptedData encrypted_wrapped_key = aws_encryption_sdk.internal.formatting.deserialize.deserialize_wrapped_key( wrapping_algorithm=self.wrapping_algorithm, wrapping_key_id=self.key_name, wrapped_encrypted_key=decryption_materials.encrypted_data_key, ) + + # EncryptedData to raw key string plaintext_data_key = self.wrapping_key.decrypt( encrypted_wrapped_data_key=encrypted_wrapped_key, encryption_context=decryption_materials.encryption_context, ) + + # Update keyring trace + + # Update decryption materials decryption_materials.data_key = DataKey( key_provider=decryption_materials.encrypted_data_key.key_provider, data_key=plaintext_data_key, encrypted_data_key=decryption_materials.encrypted_data_key.encrypted_data_key, ) - # Update keyring trace - return decryption_materials @@ -145,6 +152,7 @@ def on_encrypt(self, encryption_materials): plaintext_data_key=plaintext_data_key, encryption_context=encryption_materials.encryption_context ) + # EncryptedData to EncryptedDataKey encrypted_data_key = aws_encryption_sdk.internal.formatting.serialize.serialize_wrapped_key( key_provider=self.key_provider, wrapping_algorithm=self.wrapping_algorithm, @@ -173,20 +181,27 @@ def on_decrypt(self, decryption_materials): # Decrypt data key if decryption_materials.encrypted_data_key.key_provider == self.key_provider: + + # Wrapped EncryptedDataKey to deserialized EncryptedData encrypted_wrapped_key = aws_encryption_sdk.internal.formatting.deserialize.deserialize_wrapped_key( wrapping_algorithm=self.wrapping_algorithm, wrapping_key_id=self.key_name, wrapped_encrypted_key=decryption_materials.encrypted_data_key, ) + + # EncryptedData to raw key string plaintext_data_key = self.wrapping_key.decrypt( encrypted_wrapped_data_key=encrypted_wrapped_key, encryption_context=decryption_materials.encryption_context, ) + + # Update keyring trace + + # Update decryption materials decryption_materials.data_key = DataKey( key_provider=decryption_materials.encrypted_data_key.key_provider, data_key=plaintext_data_key, encrypted_data_key=decryption_materials.encrypted_data_key.encrypted_data_key, ) - # Update keyring trace return decryption_materials From a8d30191c3acfce3f0e9feda2bcb02709e6ab30f Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Mon, 24 Jun 2019 09:35:53 -0700 Subject: [PATCH 15/61] Multi keyring first commit --- .../keyring/multi_keyring.py | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/aws_encryption_sdk/keyring/multi_keyring.py b/src/aws_encryption_sdk/keyring/multi_keyring.py index e69de29bb..972c952d3 100644 --- a/src/aws_encryption_sdk/keyring/multi_keyring.py +++ b/src/aws_encryption_sdk/keyring/multi_keyring.py @@ -0,0 +1,29 @@ +# Copyright 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"). You +# may not use this file except in compliance with the License. A copy of +# the License is located at +# +# http://aws.amazon.com/apache2.0/ +# +# or in the "license" file accompanying this file. This file is +# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF +# ANY KIND, either express or implied. See the License for the specific +# language governing permissions and limitations under the License. +"""Resources required for Multi Keyrings.""" +import attr +from aws_encryption_sdk.keyring.base import Keyring +from aws_encryption_sdk.keyring.raw_keyring import RawAESKeyring, RawRSAKeyring + + +@attr.s +class MultiKeyring(Keyring): + generator = attr.ib(validator=attr.validators.instance_of(Keyring)) + children = attr.ib(validator=attr.validators.instance_of(list)) + + def on_encrypt(self, encryption_materials): + + return encryption_materials + + def on_decrypt(self, decryption_materials): + return decryption_materials From 366a189f4cb8399f04ff89b395b0b9b55c5a89a5 Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Mon, 24 Jun 2019 10:44:07 -0700 Subject: [PATCH 16/61] Changes in the base file --- src/aws_encryption_sdk/keyring/base.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/aws_encryption_sdk/keyring/base.py b/src/aws_encryption_sdk/keyring/base.py index 3c4689d70..e18cd9e45 100644 --- a/src/aws_encryption_sdk/keyring/base.py +++ b/src/aws_encryption_sdk/keyring/base.py @@ -14,7 +14,10 @@ class Keyring(object): - """Parent interface for Keyring classes.""" + """Parent interface for Keyring classes. + + .. versionadded:: 1.5.0 + """ def on_encrypt(self, encryption_materials): """Generate a data key if not present and encrypt it using any available wrapping key. From 05fa2b2ffe05e843ea1d63f7272450ce10bc8929 Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Thu, 27 Jun 2019 14:25:31 -0700 Subject: [PATCH 17/61] Temporary changes in multiple files --- src/aws_encryption_sdk/keyring/base.py | 11 +- .../keyring/multi_keyring.py | 60 ++++- src/aws_encryption_sdk/keyring/raw_keyring.py | 246 +++++++++--------- test/functional/test_f_raw_aes.py | 69 +++++ 4 files changed, 264 insertions(+), 122 deletions(-) create mode 100644 test/functional/test_f_raw_aes.py diff --git a/src/aws_encryption_sdk/keyring/base.py b/src/aws_encryption_sdk/keyring/base.py index e18cd9e45..3192a5688 100644 --- a/src/aws_encryption_sdk/keyring/base.py +++ b/src/aws_encryption_sdk/keyring/base.py @@ -25,19 +25,22 @@ def on_encrypt(self, encryption_materials): :param encryption_materials: Contains signing key, encryption context and algorithm suite required to encrypt data key :type encryption_materials: aws_encryption_sdk.materials_managers.EncryptionMaterials - :returns: Contains signing key, unencrypted data key, encrypted data keys, + :returns: Encryption materials containing signing key, unencrypted data key, encrypted data keys, encryption context and algorithm suite required to encrypt data key :rtype: aws_encryption_sdk.materials_managers.EncryptionMaterials :raises NotImplementedError: if method is not implemented """ raise NotImplementedError("Keyring does not implement on_encrypt function") - def on_decrypt(self, decryption_materials): + def on_decrypt(self, decryption_materials, encrypted_data_keys): """Attempt to decrypt the encrypted data keys. - :param decryption_materials: Contains verification key, list of encrypted data keys. + :param decryption_materials: May contain verification key, algorithm, encryption context and keyring trace. :type decryption_materials: aws_encryption_sdk.materials_managers.DecryptionMaterials - :returns: Contains verification key, list of encrypted data keys and decrypted data key. + :param encrypted_data_keys: List of encrypted data keys. + :type: Iterable of `aws_encryption_sdk.structures.EncryptedDataKey` + :returns: Decryption materials containing verification key, algorithm, data_encryption_key, + encryption context and keyring trace. :rtype: aws_encryption_sdk.materials_managers.DecryptionMaterials :raises NotImplementedError: if method is not implemented """ diff --git a/src/aws_encryption_sdk/keyring/multi_keyring.py b/src/aws_encryption_sdk/keyring/multi_keyring.py index 972c952d3..204da3251 100644 --- a/src/aws_encryption_sdk/keyring/multi_keyring.py +++ b/src/aws_encryption_sdk/keyring/multi_keyring.py @@ -12,18 +12,74 @@ # language governing permissions and limitations under the License. """Resources required for Multi Keyrings.""" import attr + from aws_encryption_sdk.keyring.base import Keyring -from aws_encryption_sdk.keyring.raw_keyring import RawAESKeyring, RawRSAKeyring +from aws_encryption_sdk.exceptions import EncryptKeyError @attr.s class MultiKeyring(Keyring): + """Public class for Multi Keyring. + + :param generator: Generator keyring used to generate data encryption key + :type generator: Keyring + :param list children: List of keyrings used to encrypt the data encryption key + :raises EncryptKeyError: if encryption of data key fails for any reason + """ + generator = attr.ib(validator=attr.validators.instance_of(Keyring)) children = attr.ib(validator=attr.validators.instance_of(list)) def on_encrypt(self, encryption_materials): - + """Generate a data key using generator keyring + and encrypt it using any available wrapping key in any child keyring. + + :param encryption_materials: Contains signing key, encryption context and algorithm suite + required to encrypt data key + :type encryption_materials: aws_encryption_sdk.materials_managers.EncryptionMaterials + :returns: Contains signing key, unencrypted data key, encrypted data keys, + encryption context and algorithm suite required to encrypt data key + :rtype: aws_encryption_sdk.materials_managers.EncryptionMaterials + """ + + # Check if generator keyring is provided + if not self.generator: + return EncryptKeyError("Generator keyring not provided.") + + # Check if generator keyring is provided and data key is generated + if self.generator and encryption_materials.data_encryption_key: + return EncryptKeyError("Data encryption key already exists.") + + # Call on_encrypt on the generator keyring + encryption_materials = self.generator.on_encrypt(encryption_materials) + + # Check if data key is generated + if not encryption_materials.data_encryption_key: + return EncryptKeyError("Unable to generate data encryption key.") + + # Call on_encrypt on all other keyrings + for keyring in self.children: + encryption_materials = keyring.on_encrypt(encryption_materials) + return encryption_materials def on_decrypt(self, decryption_materials): + """Attempt to decrypt the encrypted data keys. + + :param decryption_materials: Contains verification key, list of encrypted data keys. + :type decryption_materials: aws_encryption_sdk.materials_managers.DecryptionMaterials + :returns: Contains verification key, list of encrypted data keys and decrypted data key. + :rtype: aws_encryption_sdk.materials_managers.DecryptionMaterials + """ + + # Check if plaintext data key exists + if decryption_materials.data_key: + return decryption_materials + + # Call on_decrypt on all keyrings till decryption is successful + for keyring in self.children: + decryption_materials = keyring.on_decrypt(decryption_materials) + if decryption_materials.data_key: + return decryption_materials + return decryption_materials diff --git a/src/aws_encryption_sdk/keyring/raw_keyring.py b/src/aws_encryption_sdk/keyring/raw_keyring.py index 1defb85e0..4bbdd0ced 100644 --- a/src/aws_encryption_sdk/keyring/raw_keyring.py +++ b/src/aws_encryption_sdk/keyring/raw_keyring.py @@ -13,6 +13,7 @@ """Resources required for Raw Keyrings.""" import os import struct +import six import attr @@ -23,27 +24,107 @@ from aws_encryption_sdk.internal.str_ops import to_bytes from aws_encryption_sdk.keyring.base import Keyring from aws_encryption_sdk.structures import DataKey, MasterKeyInfo, RawDataKey +from aws_encryption_sdk.exceptions import EncryptKeyError -@attr.s -class RawAESKeyring(Keyring): - """Public class for Raw AES Keyring.""" +def on_encrypt_helper(encryption_materials, key_provider, wrapping_key, wrapping_algorithm, key_name): + # Check if data key already exists + if not encryption_materials.data_encryption_key: - key_namespace = attr.ib(validator=attr.validators.instance_of(str)) - key_name = attr.ib(hash=True, validator=attr.validators.instance_of(bytes)) - wrapping_key = attr.ib(hash=True, validator=attr.validators.instance_of(WrappingKey)) - wrapping_algorithm = attr.ib(validator=attr.validators.instance_of(WrappingAlgorithm)) + # Generate data key + plaintext_data_key = os.urandom(encryption_materials.algorithm.kdf_input_len) + + # Check if data key is generated + if not plaintext_data_key: + return EncryptKeyError("Unable to generate data encryption key.") + + # plaintext_data_key to RawDataKey + data_encryption_key = RawDataKey( + key_provider=key_provider, data_key=plaintext_data_key + ) + + # Add generated data key to encryption_materials + encryption_materials.add_data_encryption_key(data_encryption_key, encryption_materials.keyring_trace) + + else: + plaintext_data_key = encryption_materials.data_encryption_key + + # Encrypt data key + encrypted_wrapped_key = wrapping_key.encrypt( + plaintext_data_key=plaintext_data_key, encryption_context=encryption_materials.encryption_context + ) + + # EncryptedData to EncryptedDataKey + encrypted_data_key = aws_encryption_sdk.internal.formatting.serialize.serialize_wrapped_key( + key_provider=key_provider, + wrapping_algorithm=wrapping_algorithm, + wrapping_key_id=key_name, + encrypted_wrapped_key=encrypted_wrapped_key + ) + + # Add encrypted data key to encryption_materials + encryption_materials.add_encrypted_data_key(encrypted_data_key, encryption_materials.keyring_trace) + + return encryption_materials - key_provider = MasterKeyInfo(provider_id=key_namespace, key_info=key_name) - key_info_prefix = struct.pack( - ">{}sII".format(len(key_name)), - to_bytes(key_name), - # Tag Length is stored in bits, not bytes - wrapping_algorithm.algorithm.tag_len * 8, - wrapping_algorithm.algorithm.iv_len, +def on_decrypt_helper(decryption_materials, wrapping_key, wrapping_algorithm, key_name, encrypted_data_key): + # Check if plaintext data key exists + if decryption_materials.data_key: + return decryption_materials + + # Wrapped EncryptedDataKey to deserialized EncryptedData + encrypted_wrapped_key = aws_encryption_sdk.internal.formatting.deserialize.deserialize_wrapped_key( + wrapping_algorithm=wrapping_algorithm, + wrapping_key_id=key_name, + wrapped_encrypted_key=encrypted_data_key ) + # EncryptedData to raw key string + plaintext_data_key = wrapping_key.decrypt( + encrypted_wrapped_data_key=encrypted_wrapped_key, + encryption_context=decryption_materials.encryption_context + ) + + # Update decryption materials + decryption_materials.data_key = DataKey( + key_provider=decryption_materials.encrypted_data_key.key_provider, + data_key=plaintext_data_key, + encrypted_data_key=encrypted_data_key.encrypted_data_key + ) + + return decryption_materials + + +@attr.s +class RawAESKeyring(Keyring): + """Public class for Raw AES Keyring. + + :param str key_namespace: String defining the keyring ID + :param bytes key_name: Key ID + :param wrapping_key: Encryption key with which to wrap plaintext data key + :type wrapping_key: WrappingKey + :param wrapping_algorithm: Wrapping Algorithm with which to wrap plaintext data key + :type wrapping_algorithm: WrappingAlgorithm + """ + + key_namespace = attr.ib(validator=attr.validators.instance_of(six.string_types)) + key_name = attr.ib(hash=True, validator=attr.validators.instance_of(six.binary_type)) + _wrapping_key = attr.ib(hash=True, repr=False, validator=attr.validators.instance_of(WrappingKey)) + _wrapping_algorithm = attr.ib(repr=False, validator=attr.validators.instance_of(WrappingAlgorithm)) + + def __attrs_post_init__(self): + + _key_provider = MasterKeyInfo(provider_id=self.key_namespace, key_info=self.key_name) + + _key_info_prefix = struct.pack( + ">{}sII".format(len(self.key_name)), + to_bytes(self.key_name), + # Tag Length is stored in bits, not bytes + self._wrapping_algorithm.algorithm.tag_len * 8, + self._wrapping_algorithm.algorithm.iv_len + ) + def on_encrypt(self, encryption_materials): """Generate a data key if not present and encrypt it using any available wrapping key. @@ -55,83 +136,54 @@ def on_encrypt(self, encryption_materials): :rtype: aws_encryption_sdk.materials_managers.EncryptionMaterials """ - # Generate data key - plaintext_data_key = os.urandom(encryption_materials.algorithm.kdf_input_len) - - # Encrypt data key - encrypted_wrapped_key = self.wrapping_key.encrypt( - plaintext_data_key=plaintext_data_key, encryption_context=encryption_materials.encryption_context - ) - - # EncryptedData to EncryptedDataKey - encrypted_data_key = aws_encryption_sdk.internal.formatting.serialize.serialize_wrapped_key( - key_provider=self.key_provider, - wrapping_algorithm=self.wrapping_algorithm, - wrapping_key_id=self.key_name, - encrypted_wrapped_key=encrypted_wrapped_key, - ) - - # Update keyring trace - - # Update encryption materials - encryption_materials.data_encryption_key = RawDataKey( - key_provider=self.key_provider, data_key=plaintext_data_key - ) - encryption_materials.encrypted_data_keys.add(encrypted_data_key) + encryption_materials = on_encrypt_helper(encryption_materials, self._key_provider, self._wrapping_key, + self._wrapping_algorithm, self.key_name) return encryption_materials - def on_decrypt(self, decryption_materials): + def on_decrypt(self, decryption_materials, encrypted_data_keys): """Attempt to decrypt the encrypted data keys. - :param decryption_materials: Contains verification key, list of encrypted data keys. + :param decryption_materials: Contains verification key, algorithm, encryption context and keyring trace. :type decryption_materials: aws_encryption_sdk.materials_managers.DecryptionMaterials - :returns: Contains verification key, list of encrypted data keys and decrypted data key. + :param encrypted_data_keys: List of encrypted data keys. + :type: List of `aws_encryption_sdk.structures.EncryptedDataKey` + :returns: Contains verification key, algorithm, data_encryption_key, encryption context and keyring trac :rtype: aws_encryption_sdk.materials_managers.DecryptionMaterials """ # Decrypt data key - expected_key_info_len = len(self.key_info_prefix) + self.wrapping_algorithm.algorithm.iv_len + expected_key_info_len = len(self._key_info_prefix) + self._wrapping_algorithm.algorithm.iv_len if ( - decryption_materials.encrypted_data_key.key_provider.provider_id == self.key_provider.provider_id + decryption_materials.encrypted_data_key.key_provider.provider_id == self._key_provider.provider_id and len(decryption_materials.encrypted_data_key.key_provider.key_info) == expected_key_info_len - and decryption_materials.encrypted_data_key.key_provider.key_info.startswith(self.key_info_prefix) + and decryption_materials.encrypted_data_key.key_provider.key_info.startswith(self._key_info_prefix) ): - - # Wrapped EncryptedDataKey to deserialized EncryptedData - encrypted_wrapped_key = aws_encryption_sdk.internal.formatting.deserialize.deserialize_wrapped_key( - wrapping_algorithm=self.wrapping_algorithm, - wrapping_key_id=self.key_name, - wrapped_encrypted_key=decryption_materials.encrypted_data_key, - ) - - # EncryptedData to raw key string - plaintext_data_key = self.wrapping_key.decrypt( - encrypted_wrapped_data_key=encrypted_wrapped_key, - encryption_context=decryption_materials.encryption_context, - ) - - # Update keyring trace - - # Update decryption materials - decryption_materials.data_key = DataKey( - key_provider=decryption_materials.encrypted_data_key.key_provider, - data_key=plaintext_data_key, - encrypted_data_key=decryption_materials.encrypted_data_key.encrypted_data_key, - ) + decryption_materials = on_decrypt_helper(decryption_materials, self._wrapping_key, self._wrapping_algorithm, + self.key_name, encrypted_data_keys) return decryption_materials class RawRSAKeyring(Keyring): - """Public class for Raw RSA Keyring.""" + """Public class for Raw RSA Keyring. + + :param str key_namespace: String defining the keyring ID + :param bytes key_name: Key ID + :param wrapping_key: Encryption key with which to wrap plaintext data key + :type wrapping_key: WrappingKey + :param wrapping_algorithm: Wrapping Algorithm with which to wrap plaintext data key + :type wrapping_algorithm: WrappingAlgorithm + :param key_provider: Complete information about the key in the keyring + :type key_provider: MasterKeyInfo + """ key_namespace = attr.ib(validator=attr.validators.instance_of(str)) key_name = attr.ib(hash=True, validator=attr.validators.instance_of(bytes)) - wrapping_key = attr.ib(hash=True, validator=attr.validators.instance_of(WrappingKey)) - wrapping_algorithm = attr.ib(validator=attr.validators.instance_of(WrappingAlgorithm)) + _wrapping_key = attr.ib(hash=True, repr=False, validator=attr.validators.instance_of(WrappingKey)) + _wrapping_algorithm = attr.ib(repr=False, validator=attr.validators.instance_of(WrappingAlgorithm)) - key_provider = MasterKeyInfo(provider_id=key_namespace, key_info=key_name) + _key_provider = MasterKeyInfo(provider_id=key_namespace, key_info=key_name) def on_encrypt(self, encryption_materials): """Generate a data key if not present and encrypt it using any available wrapping key. @@ -144,64 +196,26 @@ def on_encrypt(self, encryption_materials): :rtype: aws_encryption_sdk.materials_managers.EncryptionMaterials """ - # Generate data key - plaintext_data_key = os.urandom(encryption_materials.algorithm.kdf_input_len) - - # Encrypt data key - encrypted_wrapped_key = self.wrapping_key.encrypt( - plaintext_data_key=plaintext_data_key, encryption_context=encryption_materials.encryption_context - ) - - # EncryptedData to EncryptedDataKey - encrypted_data_key = aws_encryption_sdk.internal.formatting.serialize.serialize_wrapped_key( - key_provider=self.key_provider, - wrapping_algorithm=self.wrapping_algorithm, - wrapping_key_id=self.key_name, - encrypted_wrapped_key=encrypted_wrapped_key, - ) - - # Update keyring trace - - # Update encryption materials - encryption_materials.data_encryption_key = RawDataKey( - key_provider=self.key_provider, data_key=plaintext_data_key - ) - encryption_materials.encrypted_data_keys.add(encrypted_data_key) + encryption_materials = on_encrypt_helper(encryption_materials, self._key_provider, self._wrapping_key, + self._wrapping_algorithm, self.key_name) return encryption_materials - def on_decrypt(self, decryption_materials): + def on_decrypt(self, decryption_materials, encrypted_data_keys): """Attempt to decrypt the encrypted data keys. - :param decryption_materials: Contains verification key, list of encrypted data keys. + :param decryption_materials: Contains verification key, algorithm, encryption context and keyring trace. :type decryption_materials: aws_encryption_sdk.materials_managers.DecryptionMaterials - :returns: Contains verification key, list of encrypted data keys and decrypted data key. + :param encrypted_data_keys: List of encrypted data keys. + :type: List of `aws_encryption_sdk.structures.EncryptedDataKey` + :returns: Contains verification key, algorithm, data_encryption_key, encryption context and keyring trac :rtype: aws_encryption_sdk.materials_managers.DecryptionMaterials """ # Decrypt data key if decryption_materials.encrypted_data_key.key_provider == self.key_provider: - # Wrapped EncryptedDataKey to deserialized EncryptedData - encrypted_wrapped_key = aws_encryption_sdk.internal.formatting.deserialize.deserialize_wrapped_key( - wrapping_algorithm=self.wrapping_algorithm, - wrapping_key_id=self.key_name, - wrapped_encrypted_key=decryption_materials.encrypted_data_key, - ) - - # EncryptedData to raw key string - plaintext_data_key = self.wrapping_key.decrypt( - encrypted_wrapped_data_key=encrypted_wrapped_key, - encryption_context=decryption_materials.encryption_context, - ) - - # Update keyring trace - - # Update decryption materials - decryption_materials.data_key = DataKey( - key_provider=decryption_materials.encrypted_data_key.key_provider, - data_key=plaintext_data_key, - encrypted_data_key=decryption_materials.encrypted_data_key.encrypted_data_key, - ) + decryption_materials = on_decrypt_helper(decryption_materials, self._wrapping_key, self._wrapping_algorithm, + self.key_name, encrypted_data_keys) return decryption_materials diff --git a/test/functional/test_f_raw_aes.py b/test/functional/test_f_raw_aes.py new file mode 100644 index 000000000..0526e3002 --- /dev/null +++ b/test/functional/test_f_raw_aes.py @@ -0,0 +1,69 @@ +# Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"). You +# may not use this file except in compliance with the License. A copy of +# the License is located at +# +# http://aws.amazon.com/apache2.0/ +# +# or in the "license" file accompanying this file. This file is +# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF +# ANY KIND, either express or implied. See the License for the specific +# language governing permissions and limitations under the License. +"""Functional tests for Raw AES keyring encryption decryption path.""" + +import pytest + +# from aws_encryption_sdk.keyring.base import Keyring +from aws_encryption_sdk.keyring.raw_keyring import RawAESKeyring + +pytestmark = [pytest.mark.functional, pytest.mark.local] + +_PLAINTEXT_DATA_KEY = b'*!\xa1"^-(\xf3\x105\x05i@B\xc2\xa2\xb7\xdd\xd5\xd5\xa9\xddm\xfae\xa8\\$\xf9d\x1e(' +_ENCRYPTION_CONTEXT = {"encryption": "context", "values": "here"} +_PROVIDER_ID = "Random Raw Keys" +_WRAPPING_KEY = b"\xeby-\x80A6\x15rA8\x83#,\xe4\xab\xac`\xaf\x99Z\xc1\xce\xdb\xb6\x0f\xb7\x805\xb2\x14J3" + +# _ENCRYPTED_DATA_KEYS = [ +# { +# "wrapping_key": (b"\xeby-\x80A6\x15rA8\x83#,\xe4\xab\xac`\xaf\x99Z\xc1\xce\xdb\xb6\x0f\xb7\x805\xb2\x14J3"), +# "key_id": b"5325b043-5843-4629-869c-64794af77ada", +# "key_info": ( +# b"5325b043-5843-4629-869c-64794af77ada\x00\x00\x00\x80\x00\x00\x00\x0c\xe0h\xe2NT\x1c\xb8\x8f!\t\xc2\x94" +# ), +# "edk": ( +# b"\xde^\x97\x7f\x84\xe9\x9e\x98\xd0\xe2\xf8\xd5\xcb\xe9\x7f.}\x87\x16,\x11n#\xc8p\xdb\xbf\x94\x86*Q\x06" +# b"\xd2\xf5\xdah\x08\xa4p\x81\xf7\xf4G\x07FzE\xde" +# ), +# }, +# { +# "wrapping_key": ( +# b"Q\xfd\xaa[\"\xb3\x00\xc3E\xc0\xa7\xba_\xea\x92'vS$\x12\xa4h\x04\xd8\xdf\x80\xce\x16\x0ca\x9c\xc7" +# ), +# "key_id": b"ead3f97e-49fe-48ce-be12-5c126c0d6adf", +# "key_info": ( +# b"ead3f97e-49fe-48ce-be12-5c126c0d6adf\x00\x00\x00\x80\x00\x00\x00\x0c\xb6r9\x14Q\xd2\x0f\x02\x87\xcet\xec" +# ), +# "edk": ( +# b"\x86\xe2\x80\xc9\x7f\x93\x13\xdf\x8e\xcc\xde_\xa0\x88p\xa5\xd3\x1b\x1atqUW\x96\xfft\x85gB\xadjy\xedeQ\r" +# b"\xebL\x17\xf7\xd85\xea7_\xb3\xdb\x99" +# ), +# }, +# ] +# _EDK_MAP = {_key["key_id"]: _key for _key in _ENCRYPTED_DATA_KEYS} +# +# _ENCRYPTION_MATERIALS = { +# "" +# } + + +class RawAESEncryptionDecryption(RawAESKeyring): + + key_namespace = _PROVIDER_ID + key_name = attr.ib(hash=True, validator=attr.validators.instance_of(six.binary_type)) + _wrapping_key = attr.ib(hash=True, repr=False, validator=attr.validators.instance_of(WrappingKey)) + _wrapping_algorithm = attr.ib(repr=False, validator=attr.validators.instance_of(WrappingAlgorithm)) + + + + From b37028cf59f4a32981233c0a4654dedcae557f51 Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Thu, 27 Jun 2019 16:39:28 -0700 Subject: [PATCH 18/61] Committing initial code --- .../internal/crypto/wrapping_keys.py | 2 +- .../keyring/multi_keyring.py | 6 ++- src/aws_encryption_sdk/keyring/raw_keyring.py | 13 +++--- test/functional/test_f_raw_aes.py | 44 +++---------------- 4 files changed, 19 insertions(+), 46 deletions(-) diff --git a/src/aws_encryption_sdk/internal/crypto/wrapping_keys.py b/src/aws_encryption_sdk/internal/crypto/wrapping_keys.py index 047db4986..91f9fd834 100644 --- a/src/aws_encryption_sdk/internal/crypto/wrapping_keys.py +++ b/src/aws_encryption_sdk/internal/crypto/wrapping_keys.py @@ -67,7 +67,7 @@ def encrypt(self, plaintext_data_key, encryption_context): :rtype: aws_encryption_sdk.internal.structures.EncryptedData """ if self.wrapping_algorithm.encryption_type is EncryptionType.ASYMMETRIC: - if self.wrapping_key_type is EncryptionKeyType.PRIVATE:x + if self.wrapping_key_type is EncryptionKeyType.PRIVATE: encrypted_key = self._wrapping_key.public_key().encrypt( plaintext=plaintext_data_key, padding=self.wrapping_algorithm.padding ) diff --git a/src/aws_encryption_sdk/keyring/multi_keyring.py b/src/aws_encryption_sdk/keyring/multi_keyring.py index 204da3251..922226c3f 100644 --- a/src/aws_encryption_sdk/keyring/multi_keyring.py +++ b/src/aws_encryption_sdk/keyring/multi_keyring.py @@ -63,11 +63,13 @@ def on_encrypt(self, encryption_materials): return encryption_materials - def on_decrypt(self, decryption_materials): + def on_decrypt(self, decryption_materials, encrypted_data_keys): """Attempt to decrypt the encrypted data keys. :param decryption_materials: Contains verification key, list of encrypted data keys. :type decryption_materials: aws_encryption_sdk.materials_managers.DecryptionMaterials + :param encrypted_data_keys: List of encrypted data keys. + :type: List of `aws_encryption_sdk.structures.EncryptedDataKey` :returns: Contains verification key, list of encrypted data keys and decrypted data key. :rtype: aws_encryption_sdk.materials_managers.DecryptionMaterials """ @@ -78,7 +80,7 @@ def on_decrypt(self, decryption_materials): # Call on_decrypt on all keyrings till decryption is successful for keyring in self.children: - decryption_materials = keyring.on_decrypt(decryption_materials) + decryption_materials = keyring.on_decrypt(decryption_materials, encrypted_data_keys) if decryption_materials.data_key: return decryption_materials diff --git a/src/aws_encryption_sdk/keyring/raw_keyring.py b/src/aws_encryption_sdk/keyring/raw_keyring.py index 4bbdd0ced..71321e08d 100644 --- a/src/aws_encryption_sdk/keyring/raw_keyring.py +++ b/src/aws_encryption_sdk/keyring/raw_keyring.py @@ -87,11 +87,12 @@ def on_decrypt_helper(decryption_materials, wrapping_key, wrapping_algorithm, ke ) # Update decryption materials - decryption_materials.data_key = DataKey( - key_provider=decryption_materials.encrypted_data_key.key_provider, + data_encryption_key = DataKey( + key_provider=encrypted_data_key.key_provider, data_key=plaintext_data_key, encrypted_data_key=encrypted_data_key.encrypted_data_key ) + decryption_materials.add_data_encryption_key(data_encryption_key, decryption_materials.keyring_trace) return decryption_materials @@ -155,9 +156,9 @@ def on_decrypt(self, decryption_materials, encrypted_data_keys): # Decrypt data key expected_key_info_len = len(self._key_info_prefix) + self._wrapping_algorithm.algorithm.iv_len if ( - decryption_materials.encrypted_data_key.key_provider.provider_id == self._key_provider.provider_id - and len(decryption_materials.encrypted_data_key.key_provider.key_info) == expected_key_info_len - and decryption_materials.encrypted_data_key.key_provider.key_info.startswith(self._key_info_prefix) + encrypted_data_keys.key_provider.provider_id == self._key_provider.provider_id + and len(encrypted_data_keys.key_provider.key_info) == expected_key_info_len + and encrypted_data_keys.key_provider.key_info.startswith(self._key_info_prefix) ): decryption_materials = on_decrypt_helper(decryption_materials, self._wrapping_key, self._wrapping_algorithm, self.key_name, encrypted_data_keys) @@ -213,7 +214,7 @@ def on_decrypt(self, decryption_materials, encrypted_data_keys): """ # Decrypt data key - if decryption_materials.encrypted_data_key.key_provider == self.key_provider: + if encrypted_data_keys.key_provider == self._key_provider: decryption_materials = on_decrypt_helper(decryption_materials, self._wrapping_key, self._wrapping_algorithm, self.key_name, encrypted_data_keys) diff --git a/test/functional/test_f_raw_aes.py b/test/functional/test_f_raw_aes.py index 0526e3002..60ee7c13e 100644 --- a/test/functional/test_f_raw_aes.py +++ b/test/functional/test_f_raw_aes.py @@ -14,8 +14,8 @@ import pytest -# from aws_encryption_sdk.keyring.base import Keyring -from aws_encryption_sdk.keyring.raw_keyring import RawAESKeyring +from aws_encryption_sdk.identifiers import WrappingAlgorithm +from aws_encryption_sdk.keyring.raw_keyring import RawAESKeyring, WrappingKey pytestmark = [pytest.mark.functional, pytest.mark.local] @@ -23,46 +23,16 @@ _ENCRYPTION_CONTEXT = {"encryption": "context", "values": "here"} _PROVIDER_ID = "Random Raw Keys" _WRAPPING_KEY = b"\xeby-\x80A6\x15rA8\x83#,\xe4\xab\xac`\xaf\x99Z\xc1\xce\xdb\xb6\x0f\xb7\x805\xb2\x14J3" - -# _ENCRYPTED_DATA_KEYS = [ -# { -# "wrapping_key": (b"\xeby-\x80A6\x15rA8\x83#,\xe4\xab\xac`\xaf\x99Z\xc1\xce\xdb\xb6\x0f\xb7\x805\xb2\x14J3"), -# "key_id": b"5325b043-5843-4629-869c-64794af77ada", -# "key_info": ( -# b"5325b043-5843-4629-869c-64794af77ada\x00\x00\x00\x80\x00\x00\x00\x0c\xe0h\xe2NT\x1c\xb8\x8f!\t\xc2\x94" -# ), -# "edk": ( -# b"\xde^\x97\x7f\x84\xe9\x9e\x98\xd0\xe2\xf8\xd5\xcb\xe9\x7f.}\x87\x16,\x11n#\xc8p\xdb\xbf\x94\x86*Q\x06" -# b"\xd2\xf5\xdah\x08\xa4p\x81\xf7\xf4G\x07FzE\xde" -# ), -# }, -# { -# "wrapping_key": ( -# b"Q\xfd\xaa[\"\xb3\x00\xc3E\xc0\xa7\xba_\xea\x92'vS$\x12\xa4h\x04\xd8\xdf\x80\xce\x16\x0ca\x9c\xc7" -# ), -# "key_id": b"ead3f97e-49fe-48ce-be12-5c126c0d6adf", -# "key_info": ( -# b"ead3f97e-49fe-48ce-be12-5c126c0d6adf\x00\x00\x00\x80\x00\x00\x00\x0c\xb6r9\x14Q\xd2\x0f\x02\x87\xcet\xec" -# ), -# "edk": ( -# b"\x86\xe2\x80\xc9\x7f\x93\x13\xdf\x8e\xcc\xde_\xa0\x88p\xa5\xd3\x1b\x1atqUW\x96\xfft\x85gB\xadjy\xedeQ\r" -# b"\xebL\x17\xf7\xd85\xea7_\xb3\xdb\x99" -# ), -# }, -# ] -# _EDK_MAP = {_key["key_id"]: _key for _key in _ENCRYPTED_DATA_KEYS} -# -# _ENCRYPTION_MATERIALS = { -# "" -# } +_KEY_ID = b"5325b043-5843-4629-869c-64794af77ada" +_KEY_INFO = b"5325b043-5843-4629-869c-64794af77ada\x00\x00\x00\x80\x00\x00\x00\x0c\xe0h\xe2NT\x1c\xb8\x8f!\t\xc2\x94" class RawAESEncryptionDecryption(RawAESKeyring): key_namespace = _PROVIDER_ID - key_name = attr.ib(hash=True, validator=attr.validators.instance_of(six.binary_type)) - _wrapping_key = attr.ib(hash=True, repr=False, validator=attr.validators.instance_of(WrappingKey)) - _wrapping_algorithm = attr.ib(repr=False, validator=attr.validators.instance_of(WrappingAlgorithm)) + key_name = _KEY_ID + _wrapping_key = WrappingKey(wrapping_algorithm=WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING, + wrapping_key=_WRAPPING_KEY) From 5d6cbe4ec184e63af21b0e1542d6611d40258c81 Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Fri, 28 Jun 2019 12:06:51 -0700 Subject: [PATCH 19/61] Deleted raw aes test --- test/functional/test_f_raw_aes.py | 39 ------------------------------- 1 file changed, 39 deletions(-) delete mode 100644 test/functional/test_f_raw_aes.py diff --git a/test/functional/test_f_raw_aes.py b/test/functional/test_f_raw_aes.py deleted file mode 100644 index 60ee7c13e..000000000 --- a/test/functional/test_f_raw_aes.py +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"). You -# may not use this file except in compliance with the License. A copy of -# the License is located at -# -# http://aws.amazon.com/apache2.0/ -# -# or in the "license" file accompanying this file. This file is -# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF -# ANY KIND, either express or implied. See the License for the specific -# language governing permissions and limitations under the License. -"""Functional tests for Raw AES keyring encryption decryption path.""" - -import pytest - -from aws_encryption_sdk.identifiers import WrappingAlgorithm -from aws_encryption_sdk.keyring.raw_keyring import RawAESKeyring, WrappingKey - -pytestmark = [pytest.mark.functional, pytest.mark.local] - -_PLAINTEXT_DATA_KEY = b'*!\xa1"^-(\xf3\x105\x05i@B\xc2\xa2\xb7\xdd\xd5\xd5\xa9\xddm\xfae\xa8\\$\xf9d\x1e(' -_ENCRYPTION_CONTEXT = {"encryption": "context", "values": "here"} -_PROVIDER_ID = "Random Raw Keys" -_WRAPPING_KEY = b"\xeby-\x80A6\x15rA8\x83#,\xe4\xab\xac`\xaf\x99Z\xc1\xce\xdb\xb6\x0f\xb7\x805\xb2\x14J3" -_KEY_ID = b"5325b043-5843-4629-869c-64794af77ada" -_KEY_INFO = b"5325b043-5843-4629-869c-64794af77ada\x00\x00\x00\x80\x00\x00\x00\x0c\xe0h\xe2NT\x1c\xb8\x8f!\t\xc2\x94" - - -class RawAESEncryptionDecryption(RawAESKeyring): - - key_namespace = _PROVIDER_ID - key_name = _KEY_ID - _wrapping_key = WrappingKey(wrapping_algorithm=WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING, - wrapping_key=_WRAPPING_KEY) - - - - From 1c07ddea0111be14d3d1651f5c626a3bb95ef869 Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Mon, 1 Jul 2019 11:45:06 -0700 Subject: [PATCH 20/61] Multi Keyrings --- src/aws_encryption_sdk/keyring/multi_keyring.py | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/aws_encryption_sdk/keyring/multi_keyring.py b/src/aws_encryption_sdk/keyring/multi_keyring.py index 922226c3f..c5fb88b68 100644 --- a/src/aws_encryption_sdk/keyring/multi_keyring.py +++ b/src/aws_encryption_sdk/keyring/multi_keyring.py @@ -34,14 +34,11 @@ def on_encrypt(self, encryption_materials): """Generate a data key using generator keyring and encrypt it using any available wrapping key in any child keyring. - :param encryption_materials: Contains signing key, encryption context and algorithm suite - required to encrypt data key + :param encryption_materials: Encryption materials for keyring to modify. :type encryption_materials: aws_encryption_sdk.materials_managers.EncryptionMaterials - :returns: Contains signing key, unencrypted data key, encrypted data keys, - encryption context and algorithm suite required to encrypt data key + :returns: Optionally modified encryption materials. :rtype: aws_encryption_sdk.materials_managers.EncryptionMaterials """ - # Check if generator keyring is provided if not self.generator: return EncryptKeyError("Generator keyring not provided.") @@ -66,14 +63,13 @@ def on_encrypt(self, encryption_materials): def on_decrypt(self, decryption_materials, encrypted_data_keys): """Attempt to decrypt the encrypted data keys. - :param decryption_materials: Contains verification key, list of encrypted data keys. + :param decryption_materials: Decryption materials for keyring to modify. :type decryption_materials: aws_encryption_sdk.materials_managers.DecryptionMaterials :param encrypted_data_keys: List of encrypted data keys. :type: List of `aws_encryption_sdk.structures.EncryptedDataKey` - :returns: Contains verification key, list of encrypted data keys and decrypted data key. + :returns: Optionally modified decryption materials. :rtype: aws_encryption_sdk.materials_managers.DecryptionMaterials """ - # Check if plaintext data key exists if decryption_materials.data_key: return decryption_materials From 8932c1c81c4cc8f24c5a85376a79b5db34cde270 Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Mon, 1 Jul 2019 11:57:40 -0700 Subject: [PATCH 21/61] Updating base API and raw keyrings --- src/aws_encryption_sdk/keyring/base.py | 24 ++-- src/aws_encryption_sdk/keyring/raw_keyring.py | 106 +++++++++++------- 2 files changed, 79 insertions(+), 51 deletions(-) diff --git a/src/aws_encryption_sdk/keyring/base.py b/src/aws_encryption_sdk/keyring/base.py index 3192a5688..59195a682 100644 --- a/src/aws_encryption_sdk/keyring/base.py +++ b/src/aws_encryption_sdk/keyring/base.py @@ -11,6 +11,14 @@ # ANY KIND, either express or implied. See the License for the specific # language governing permissions and limitations under the License. """Base class interface for Keyrings.""" +from aws_encryption_sdk.materials_managers import DecryptionMaterials, EncryptionMaterials +from aws_encryption_sdk.structures import EncryptedDataKey + +try: # Python 3.5.0 and 3.5.1 have incompatible typing modules + from typing import Iterable # noqa pylint: disable=unused-import +except ImportError: # pragma: no cover + # We only actually need these imports when running the mypy checks + pass class Keyring(object): @@ -20,28 +28,28 @@ class Keyring(object): """ def on_encrypt(self, encryption_materials): + # type: (EncryptionMaterials) -> EncryptionMaterials """Generate a data key if not present and encrypt it using any available wrapping key. - :param encryption_materials: Contains signing key, encryption context and algorithm suite - required to encrypt data key + :param encryption_materials: Encryption materials for the keyring to modify. :type encryption_materials: aws_encryption_sdk.materials_managers.EncryptionMaterials - :returns: Encryption materials containing signing key, unencrypted data key, encrypted data keys, - encryption context and algorithm suite required to encrypt data key + :returns: Optionally modified encryption materials. :rtype: aws_encryption_sdk.materials_managers.EncryptionMaterials :raises NotImplementedError: if method is not implemented """ raise NotImplementedError("Keyring does not implement on_encrypt function") def on_decrypt(self, decryption_materials, encrypted_data_keys): + # type: (DecryptionMaterials, Iterable[EncryptedDataKey]) -> DecryptionMaterials """Attempt to decrypt the encrypted data keys. - :param decryption_materials: May contain verification key, algorithm, encryption context and keyring trace. + :param decryption_materials: Decryption materials for the keyring to modify. :type decryption_materials: aws_encryption_sdk.materials_managers.DecryptionMaterials :param encrypted_data_keys: List of encrypted data keys. - :type: Iterable of `aws_encryption_sdk.structures.EncryptedDataKey` - :returns: Decryption materials containing verification key, algorithm, data_encryption_key, - encryption context and keyring trace. + :type: Iterable of :class:`aws_encryption_sdk.structures.EncryptedDataKey` + :returns: Optionally modified decryption materials. :rtype: aws_encryption_sdk.materials_managers.DecryptionMaterials :raises NotImplementedError: if method is not implemented """ raise NotImplementedError("Keyring does not implement on_decrypt function") + diff --git a/src/aws_encryption_sdk/keyring/raw_keyring.py b/src/aws_encryption_sdk/keyring/raw_keyring.py index 71321e08d..a0d9de69a 100644 --- a/src/aws_encryption_sdk/keyring/raw_keyring.py +++ b/src/aws_encryption_sdk/keyring/raw_keyring.py @@ -11,23 +11,38 @@ # ANY KIND, either express or implied. See the License for the specific # language governing permissions and limitations under the License. """Resources required for Raw Keyrings.""" + import os import struct -import six import attr +import six import aws_encryption_sdk.internal.formatting.deserialize import aws_encryption_sdk.internal.formatting.serialize +from aws_encryption_sdk.exceptions import EncryptKeyError from aws_encryption_sdk.identifiers import WrappingAlgorithm from aws_encryption_sdk.internal.crypto.wrapping_keys import WrappingKey from aws_encryption_sdk.internal.str_ops import to_bytes from aws_encryption_sdk.keyring.base import Keyring from aws_encryption_sdk.structures import DataKey, MasterKeyInfo, RawDataKey -from aws_encryption_sdk.exceptions import EncryptKeyError def on_encrypt_helper(encryption_materials, key_provider, wrapping_key, wrapping_algorithm, key_name): + """Helper function for the on_encrypt function of keyring. + + :param encryption_materials: Encryption materials for the keyring to modify. + :type encryption_materials: aws_encryption_sdk.materials_managers.EncryptionMaterials + :param key_provider: Information abput the key in the keyring. + :type key_provider: MasterKeyInfo + :param wrapping_key: Encryption key with which to wrap plaintext data key. + :type wrapping_key: WrappingKey + :param wrapping_algorithm: Wrapping Algorithm with which to wrap plaintext data key. + :type wrapping_algorithm: WrappingAlgorithm + :param bytes key_name: Key ID. + :return: Optionally modified encryption materials. + :rtype encryption_materials: aws_encryption_sdk.materials_managers.EncryptionMaterials + """ # Check if data key already exists if not encryption_materials.data_encryption_key: @@ -39,9 +54,7 @@ def on_encrypt_helper(encryption_materials, key_provider, wrapping_key, wrapping return EncryptKeyError("Unable to generate data encryption key.") # plaintext_data_key to RawDataKey - data_encryption_key = RawDataKey( - key_provider=key_provider, data_key=plaintext_data_key - ) + data_encryption_key = RawDataKey(key_provider=key_provider, data_key=plaintext_data_key) # Add generated data key to encryption_materials encryption_materials.add_data_encryption_key(data_encryption_key, encryption_materials.keyring_trace) @@ -59,7 +72,7 @@ def on_encrypt_helper(encryption_materials, key_provider, wrapping_key, wrapping key_provider=key_provider, wrapping_algorithm=wrapping_algorithm, wrapping_key_id=key_name, - encrypted_wrapped_key=encrypted_wrapped_key + encrypted_wrapped_key=encrypted_wrapped_key, ) # Add encrypted data key to encryption_materials @@ -69,28 +82,39 @@ def on_encrypt_helper(encryption_materials, key_provider, wrapping_key, wrapping def on_decrypt_helper(decryption_materials, wrapping_key, wrapping_algorithm, key_name, encrypted_data_key): + """Helper function for the on_decrypt function of keyring. + + :param decryption_materials: Decryption materials for the keyring to modify. + :type decryption_materials: aws_encryption_sdk.materials_managers.DecryptionMaterials + :param wrapping_key: Encryption key with which to wrap plaintext data key. + :type wrapping_key: WrappingKey + :param wrapping_algorithm: Wrapping Algorithm with which to wrap plaintext data key. + :type wrapping_algorithm: WrappingAlgorithm + :param bytes key_name: Key ID. + :param encrypted_data_key: Data key encrypted with a wrapping key. + :type encrypted_data_key: aws_encryption_sdk.structures.EncryptedDataKey + :return: Optionally modified decryption materials. + :rtype decryption_materials: aws_encryption_sdk.materials_managers.DecryptionMaterials + """ # Check if plaintext data key exists if decryption_materials.data_key: return decryption_materials # Wrapped EncryptedDataKey to deserialized EncryptedData encrypted_wrapped_key = aws_encryption_sdk.internal.formatting.deserialize.deserialize_wrapped_key( - wrapping_algorithm=wrapping_algorithm, - wrapping_key_id=key_name, - wrapped_encrypted_key=encrypted_data_key + wrapping_algorithm=wrapping_algorithm, wrapping_key_id=key_name, wrapped_encrypted_key=encrypted_data_key ) # EncryptedData to raw key string plaintext_data_key = wrapping_key.decrypt( - encrypted_wrapped_data_key=encrypted_wrapped_key, - encryption_context=decryption_materials.encryption_context + encrypted_wrapped_data_key=encrypted_wrapped_key, encryption_context=decryption_materials.encryption_context ) # Update decryption materials data_encryption_key = DataKey( key_provider=encrypted_data_key.key_provider, data_key=plaintext_data_key, - encrypted_data_key=encrypted_data_key.encrypted_data_key + encrypted_data_key=encrypted_data_key.encrypted_data_key, ) decryption_materials.add_data_encryption_key(data_encryption_key, decryption_materials.keyring_trace) @@ -101,11 +125,11 @@ def on_decrypt_helper(decryption_materials, wrapping_key, wrapping_algorithm, ke class RawAESKeyring(Keyring): """Public class for Raw AES Keyring. - :param str key_namespace: String defining the keyring ID + :param str key_namespace: String defining the keyring. :param bytes key_name: Key ID - :param wrapping_key: Encryption key with which to wrap plaintext data key + :param wrapping_key: Encryption key with which to wrap plaintext data key. :type wrapping_key: WrappingKey - :param wrapping_algorithm: Wrapping Algorithm with which to wrap plaintext data key + :param wrapping_algorithm: Wrapping Algorithm with which to wrap plaintext data key. :type wrapping_algorithm: WrappingAlgorithm """ @@ -115,44 +139,41 @@ class RawAESKeyring(Keyring): _wrapping_algorithm = attr.ib(repr=False, validator=attr.validators.instance_of(WrappingAlgorithm)) def __attrs_post_init__(self): + """Prepares initial values not handled by attrs.""" + self._key_provider = MasterKeyInfo(provider_id=self.key_namespace, key_info=self.key_name) - _key_provider = MasterKeyInfo(provider_id=self.key_namespace, key_info=self.key_name) - - _key_info_prefix = struct.pack( + self._key_info_prefix = struct.pack( ">{}sII".format(len(self.key_name)), to_bytes(self.key_name), # Tag Length is stored in bits, not bytes self._wrapping_algorithm.algorithm.tag_len * 8, - self._wrapping_algorithm.algorithm.iv_len + self._wrapping_algorithm.algorithm.iv_len, ) def on_encrypt(self, encryption_materials): """Generate a data key if not present and encrypt it using any available wrapping key. - :param encryption_materials: Contains signing key, encryption context and algorithm suite - required to encrypt data key + :param encryption_materials: Encryption materials for the keyring to modify. :type encryption_materials: aws_encryption_sdk.materials_managers.EncryptionMaterials - :returns: Contains signing key, unencrypted data key, encrypted data keys, - encryption context and algorithm suite required to encrypt data key + :returns: Optionally modified encryption materials. :rtype: aws_encryption_sdk.materials_managers.EncryptionMaterials """ - - encryption_materials = on_encrypt_helper(encryption_materials, self._key_provider, self._wrapping_key, - self._wrapping_algorithm, self.key_name) + encryption_materials = on_encrypt_helper( + encryption_materials, self._key_provider, self._wrapping_key, self._wrapping_algorithm, self.key_name + ) return encryption_materials def on_decrypt(self, decryption_materials, encrypted_data_keys): """Attempt to decrypt the encrypted data keys. - :param decryption_materials: Contains verification key, algorithm, encryption context and keyring trace. + :param decryption_materials: Decryption materials for the keyring to modify. :type decryption_materials: aws_encryption_sdk.materials_managers.DecryptionMaterials :param encrypted_data_keys: List of encrypted data keys. :type: List of `aws_encryption_sdk.structures.EncryptedDataKey` - :returns: Contains verification key, algorithm, data_encryption_key, encryption context and keyring trac + :returns: Optionally modified decryption materials. :rtype: aws_encryption_sdk.materials_managers.DecryptionMaterials """ - # Decrypt data key expected_key_info_len = len(self._key_info_prefix) + self._wrapping_algorithm.algorithm.iv_len if ( @@ -160,8 +181,9 @@ def on_decrypt(self, decryption_materials, encrypted_data_keys): and len(encrypted_data_keys.key_provider.key_info) == expected_key_info_len and encrypted_data_keys.key_provider.key_info.startswith(self._key_info_prefix) ): - decryption_materials = on_decrypt_helper(decryption_materials, self._wrapping_key, self._wrapping_algorithm, - self.key_name, encrypted_data_keys) + decryption_materials = on_decrypt_helper( + decryption_materials, self._wrapping_key, self._wrapping_algorithm, self.key_name, encrypted_data_keys + ) return decryption_materials @@ -189,34 +211,32 @@ class RawRSAKeyring(Keyring): def on_encrypt(self, encryption_materials): """Generate a data key if not present and encrypt it using any available wrapping key. - :param encryption_materials: Contains signing key, encryption context and algorithm suite - required to encrypt data key + :param encryption_materials: Encryption materials for the keyring to modify. :type encryption_materials: aws_encryption_sdk.materials_managers.EncryptionMaterials - :returns: Contains signing key, unencrypted data key, encrypted data keys, - encryption context and algorithm suite required to encrypt data key + :returns: Optionally modified encryption materials. :rtype: aws_encryption_sdk.materials_managers.EncryptionMaterials """ - - encryption_materials = on_encrypt_helper(encryption_materials, self._key_provider, self._wrapping_key, - self._wrapping_algorithm, self.key_name) + encryption_materials = on_encrypt_helper( + encryption_materials, self._key_provider, self._wrapping_key, self._wrapping_algorithm, self.key_name + ) return encryption_materials def on_decrypt(self, decryption_materials, encrypted_data_keys): """Attempt to decrypt the encrypted data keys. - :param decryption_materials: Contains verification key, algorithm, encryption context and keyring trace. + :param decryption_materials: Decryption materials for the keyring to modify. :type decryption_materials: aws_encryption_sdk.materials_managers.DecryptionMaterials :param encrypted_data_keys: List of encrypted data keys. :type: List of `aws_encryption_sdk.structures.EncryptedDataKey` - :returns: Contains verification key, algorithm, data_encryption_key, encryption context and keyring trac + :returns: Optionally modified decryption materials. :rtype: aws_encryption_sdk.materials_managers.DecryptionMaterials """ - # Decrypt data key if encrypted_data_keys.key_provider == self._key_provider: - decryption_materials = on_decrypt_helper(decryption_materials, self._wrapping_key, self._wrapping_algorithm, - self.key_name, encrypted_data_keys) + decryption_materials = on_decrypt_helper( + decryption_materials, self._wrapping_key, self._wrapping_algorithm, self.key_name, encrypted_data_keys + ) return decryption_materials From 5ea033392f80e8690a78bdb8b02e6a52ed7b9298 Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Mon, 1 Jul 2019 13:48:35 -0700 Subject: [PATCH 22/61] Corrected tox errors --- src/aws_encryption_sdk/keyring/base.py | 1 - src/aws_encryption_sdk/keyring/multi_keyring.py | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/aws_encryption_sdk/keyring/base.py b/src/aws_encryption_sdk/keyring/base.py index 59195a682..770b53c0b 100644 --- a/src/aws_encryption_sdk/keyring/base.py +++ b/src/aws_encryption_sdk/keyring/base.py @@ -52,4 +52,3 @@ def on_decrypt(self, decryption_materials, encrypted_data_keys): :raises NotImplementedError: if method is not implemented """ raise NotImplementedError("Keyring does not implement on_decrypt function") - diff --git a/src/aws_encryption_sdk/keyring/multi_keyring.py b/src/aws_encryption_sdk/keyring/multi_keyring.py index c5fb88b68..4669ba82f 100644 --- a/src/aws_encryption_sdk/keyring/multi_keyring.py +++ b/src/aws_encryption_sdk/keyring/multi_keyring.py @@ -13,8 +13,8 @@ """Resources required for Multi Keyrings.""" import attr -from aws_encryption_sdk.keyring.base import Keyring from aws_encryption_sdk.exceptions import EncryptKeyError +from aws_encryption_sdk.keyring.base import Keyring @attr.s From 529689a49b5c0919935c678a07a9df9a9a958ef1 Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Tue, 2 Jul 2019 15:34:12 -0700 Subject: [PATCH 23/61] Added typehints --- src/aws_encryption_sdk/keyring/multi_keyring.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/aws_encryption_sdk/keyring/multi_keyring.py b/src/aws_encryption_sdk/keyring/multi_keyring.py index 4669ba82f..ce2ddcc8c 100644 --- a/src/aws_encryption_sdk/keyring/multi_keyring.py +++ b/src/aws_encryption_sdk/keyring/multi_keyring.py @@ -16,6 +16,12 @@ from aws_encryption_sdk.exceptions import EncryptKeyError from aws_encryption_sdk.keyring.base import Keyring +try: # Python 3.5.0 and 3.5.1 have incompatible typing modules + from typing import Iterable # noqa pylint: disable=unused-import +except ImportError: # pragma: no cover + # We only actually need these imports when running the mypy checks + pass + @attr.s class MultiKeyring(Keyring): @@ -31,6 +37,7 @@ class MultiKeyring(Keyring): children = attr.ib(validator=attr.validators.instance_of(list)) def on_encrypt(self, encryption_materials): + # type: (EncryptionMaterials) -> EncryptionMaterials """Generate a data key using generator keyring and encrypt it using any available wrapping key in any child keyring. @@ -38,21 +45,22 @@ def on_encrypt(self, encryption_materials): :type encryption_materials: aws_encryption_sdk.materials_managers.EncryptionMaterials :returns: Optionally modified encryption materials. :rtype: aws_encryption_sdk.materials_managers.EncryptionMaterials + :raises EncryptKeyError: if unable to encrypt data key. """ # Check if generator keyring is provided if not self.generator: - return EncryptKeyError("Generator keyring not provided.") + raise EncryptKeyError("Generator keyring not provided.") # Check if generator keyring is provided and data key is generated if self.generator and encryption_materials.data_encryption_key: - return EncryptKeyError("Data encryption key already exists.") + raise EncryptKeyError("Data encryption key already exists.") # Call on_encrypt on the generator keyring encryption_materials = self.generator.on_encrypt(encryption_materials) # Check if data key is generated if not encryption_materials.data_encryption_key: - return EncryptKeyError("Unable to generate data encryption key.") + raise EncryptKeyError("Unable to generate data encryption key.") # Call on_encrypt on all other keyrings for keyring in self.children: @@ -61,6 +69,7 @@ def on_encrypt(self, encryption_materials): return encryption_materials def on_decrypt(self, decryption_materials, encrypted_data_keys): + # type: (DecryptionMaterials, Iterable[EncryptedDataKey]) -> DecryptionMaterials """Attempt to decrypt the encrypted data keys. :param decryption_materials: Decryption materials for keyring to modify. From afdeb6c86b2eba557724f088bd2ac94f91aefd0f Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Tue, 2 Jul 2019 15:37:08 -0700 Subject: [PATCH 24/61] Updated raw keyrings --- src/aws_encryption_sdk/keyring/raw_keyring.py | 173 +++++++++++++----- 1 file changed, 124 insertions(+), 49 deletions(-) diff --git a/src/aws_encryption_sdk/keyring/raw_keyring.py b/src/aws_encryption_sdk/keyring/raw_keyring.py index a0d9de69a..344920196 100644 --- a/src/aws_encryption_sdk/keyring/raw_keyring.py +++ b/src/aws_encryption_sdk/keyring/raw_keyring.py @@ -13,27 +13,58 @@ """Resources required for Raw Keyrings.""" import os -import struct +import logging import attr import six -import aws_encryption_sdk.internal.formatting.deserialize -import aws_encryption_sdk.internal.formatting.serialize +from aws_encryption_sdk.internal.formatting.deserialize import deserialize_wrapped_key +from aws_encryption_sdk.internal.formatting.serialize import serialize_wrapped_key, serialize_raw_master_key_prefix from aws_encryption_sdk.exceptions import EncryptKeyError -from aws_encryption_sdk.identifiers import WrappingAlgorithm +from aws_encryption_sdk.identifiers import WrappingAlgorithm, EncryptionKeyType from aws_encryption_sdk.internal.crypto.wrapping_keys import WrappingKey -from aws_encryption_sdk.internal.str_ops import to_bytes from aws_encryption_sdk.keyring.base import Keyring -from aws_encryption_sdk.structures import DataKey, MasterKeyInfo, RawDataKey +from aws_encryption_sdk.structures import MasterKeyInfo, RawDataKey, KeyringTrace +from aws_encryption_sdk.key_providers.raw import RawMasterKey +try: # Python 3.5.0 and 3.5.1 have incompatible typing modules + from typing import Iterable # noqa pylint: disable=unused-import +except ImportError: # pragma: no cover + # We only actually need these imports when running the mypy checks + pass -def on_encrypt_helper(encryption_materials, key_provider, wrapping_key, wrapping_algorithm, key_name): + +def get_key_info_prefix(key_namespace, key_name, wrapping_key): + # type: (str, bytes, WrappingKey) -> six.binary_type + """Helper function to get key info prefix + + :param str key_namespace: String defining the keyring. + :param bytes key_name: Key ID + :param wrapping_key: Encryption key with which to wrap plaintext data key. + :type wrapping_key: WrappingKey + :return: Serialized key_info prefix + :rtype: bytes + """ + key_info_prefix = serialize_raw_master_key_prefix(RawMasterKey(provider_id=key_namespace, + key_id=key_name, + wrapping_key=wrapping_key + ) + ) + return key_info_prefix + + +def on_encrypt_helper(encryption_materials, # type: EncryptionMaterials + key_provider, # type: MasterKeyInfo + wrapping_key, # type: WrappingKey + wrapping_algorithm, # type: WrappingAlgorithm + key_name # type: bytes + ): + # type: (...) -> EncryptionMaterials """Helper function for the on_encrypt function of keyring. :param encryption_materials: Encryption materials for the keyring to modify. :type encryption_materials: aws_encryption_sdk.materials_managers.EncryptionMaterials - :param key_provider: Information abput the key in the keyring. + :param key_provider: Information about the key in the keyring. :type key_provider: MasterKeyInfo :param wrapping_key: Encryption key with which to wrap plaintext data key. :type wrapping_key: WrappingKey @@ -43,6 +74,12 @@ def on_encrypt_helper(encryption_materials, key_provider, wrapping_key, wrapping :return: Optionally modified encryption materials. :rtype encryption_materials: aws_encryption_sdk.materials_managers.EncryptionMaterials """ + # Create a keyring trace + keyring_trace = KeyringTrace( + wrapping_key=key_provider, + flags=set() + ) + # Check if data key already exists if not encryption_materials.data_encryption_key: @@ -57,7 +94,7 @@ def on_encrypt_helper(encryption_materials, key_provider, wrapping_key, wrapping data_encryption_key = RawDataKey(key_provider=key_provider, data_key=plaintext_data_key) # Add generated data key to encryption_materials - encryption_materials.add_data_encryption_key(data_encryption_key, encryption_materials.keyring_trace) + encryption_materials.add_data_encryption_key(data_encryption_key, keyring_trace) else: plaintext_data_key = encryption_materials.data_encryption_key @@ -68,7 +105,7 @@ def on_encrypt_helper(encryption_materials, key_provider, wrapping_key, wrapping ) # EncryptedData to EncryptedDataKey - encrypted_data_key = aws_encryption_sdk.internal.formatting.serialize.serialize_wrapped_key( + encrypted_data_key = serialize_wrapped_key( key_provider=key_provider, wrapping_algorithm=wrapping_algorithm, wrapping_key_id=key_name, @@ -76,16 +113,25 @@ def on_encrypt_helper(encryption_materials, key_provider, wrapping_key, wrapping ) # Add encrypted data key to encryption_materials - encryption_materials.add_encrypted_data_key(encrypted_data_key, encryption_materials.keyring_trace) + encryption_materials.add_encrypted_data_key(encrypted_data_key, keyring_trace) return encryption_materials -def on_decrypt_helper(decryption_materials, wrapping_key, wrapping_algorithm, key_name, encrypted_data_key): +def on_decrypt_helper(decryption_materials, # type: DecryptionMaterials + key_provider, # type: MasterKeyInfo + wrapping_key, # type: WrappingKey + wrapping_algorithm, # type: WrappingAlgorithm + key_name, # type: bytes + encrypted_data_key # type: EncryptedDataKey + ): + # type: (...) -> DecryptionMaterials """Helper function for the on_decrypt function of keyring. :param decryption_materials: Decryption materials for the keyring to modify. :type decryption_materials: aws_encryption_sdk.materials_managers.DecryptionMaterials + :param key_provider: Information about the key in the keyring. + :type key_provider: MasterKeyInfo :param wrapping_key: Encryption key with which to wrap plaintext data key. :type wrapping_key: WrappingKey :param wrapping_algorithm: Wrapping Algorithm with which to wrap plaintext data key. @@ -96,27 +142,37 @@ def on_decrypt_helper(decryption_materials, wrapping_key, wrapping_algorithm, ke :return: Optionally modified decryption materials. :rtype decryption_materials: aws_encryption_sdk.materials_managers.DecryptionMaterials """ + # Create a keyring trace + keyring_trace = KeyringTrace( + wrapping_key=key_provider, + flags=set() + ) + # Check if plaintext data key exists if decryption_materials.data_key: return decryption_materials # Wrapped EncryptedDataKey to deserialized EncryptedData - encrypted_wrapped_key = aws_encryption_sdk.internal.formatting.deserialize.deserialize_wrapped_key( + encrypted_wrapped_key = deserialize_wrapped_key( wrapping_algorithm=wrapping_algorithm, wrapping_key_id=key_name, wrapped_encrypted_key=encrypted_data_key ) # EncryptedData to raw key string - plaintext_data_key = wrapping_key.decrypt( - encrypted_wrapped_data_key=encrypted_wrapped_key, encryption_context=decryption_materials.encryption_context - ) + try: + plaintext_data_key = wrapping_key.decrypt( + encrypted_wrapped_data_key=encrypted_wrapped_key, encryption_context=decryption_materials.encryption_context + ) + except Exception as error: + logging.ERROR(error.__class__.__name__, ':', str(error)) + return decryption_materials # Update decryption materials - data_encryption_key = DataKey( - key_provider=encrypted_data_key.key_provider, - data_key=plaintext_data_key, - encrypted_data_key=encrypted_data_key.encrypted_data_key, + data_encryption_key = RawDataKey( + key_provider=MasterKeyInfo(provider_id=key_provider.provider_id, + key_info=key_name), + data_key=plaintext_data_key ) - decryption_materials.add_data_encryption_key(data_encryption_key, decryption_materials.keyring_trace) + decryption_materials.add_data_encryption_key(data_encryption_key, keyring_trace) return decryption_materials @@ -134,23 +190,26 @@ class RawAESKeyring(Keyring): """ key_namespace = attr.ib(validator=attr.validators.instance_of(six.string_types)) - key_name = attr.ib(hash=True, validator=attr.validators.instance_of(six.binary_type)) - _wrapping_key = attr.ib(hash=True, repr=False, validator=attr.validators.instance_of(WrappingKey)) + key_name = attr.ib(validator=attr.validators.instance_of(six.binary_type)) + _wrapping_key = attr.ib(repr=False, validator=attr.validators.instance_of(WrappingKey)) _wrapping_algorithm = attr.ib(repr=False, validator=attr.validators.instance_of(WrappingAlgorithm)) def __attrs_post_init__(self): + # type: () -> None """Prepares initial values not handled by attrs.""" self._key_provider = MasterKeyInfo(provider_id=self.key_namespace, key_info=self.key_name) - self._key_info_prefix = struct.pack( - ">{}sII".format(len(self.key_name)), - to_bytes(self.key_name), - # Tag Length is stored in bits, not bytes - self._wrapping_algorithm.algorithm.tag_len * 8, - self._wrapping_algorithm.algorithm.iv_len, - ) + self._key_info_prefix = get_key_info_prefix(key_namespace=self.key_namespace, + key_name=self.key_name, + wrapping_key=WrappingKey( + wrapping_algorithm=self._wrapping_algorithm, + wrapping_key=self._wrapping_key, + wrapping_key_type=EncryptionKeyType.SYMMETRIC + ) + ) def on_encrypt(self, encryption_materials): + # type: (EncryptionMaterials) -> EncryptionMaterials """Generate a data key if not present and encrypt it using any available wrapping key. :param encryption_materials: Encryption materials for the keyring to modify. @@ -159,12 +218,15 @@ def on_encrypt(self, encryption_materials): :rtype: aws_encryption_sdk.materials_managers.EncryptionMaterials """ encryption_materials = on_encrypt_helper( - encryption_materials, self._key_provider, self._wrapping_key, self._wrapping_algorithm, self.key_name + encryption_materials=encryption_materials, key_provider=self._key_provider, + wrapping_key=self._wrapping_key, wrapping_algorithm=self._wrapping_algorithm, + key_name=self.key_name ) return encryption_materials def on_decrypt(self, decryption_materials, encrypted_data_keys): + # type: (DecryptionMaterials, Iterable[EncryptedDataKey]) -> DecryptionMaterials """Attempt to decrypt the encrypted data keys. :param decryption_materials: Decryption materials for the keyring to modify. @@ -176,14 +238,18 @@ def on_decrypt(self, decryption_materials, encrypted_data_keys): """ # Decrypt data key expected_key_info_len = len(self._key_info_prefix) + self._wrapping_algorithm.algorithm.iv_len - if ( - encrypted_data_keys.key_provider.provider_id == self._key_provider.provider_id - and len(encrypted_data_keys.key_provider.key_info) == expected_key_info_len - and encrypted_data_keys.key_provider.key_info.startswith(self._key_info_prefix) - ): - decryption_materials = on_decrypt_helper( - decryption_materials, self._wrapping_key, self._wrapping_algorithm, self.key_name, encrypted_data_keys - ) + for key in encrypted_data_keys: + if (key.key_provider.provider_id == self._key_provider.provider_id + and len(key.key_provider.key_info) == expected_key_info_len + and key.key_provider.key_info.startswith(self._key_info_prefix) + ): + decryption_materials = on_decrypt_helper( + decryption_materials=decryption_materials, key_provider=self._key_provider, + wrapping_key=self._wrapping_key, wrapping_algorithm=self._wrapping_algorithm, + key_name=self.key_name, encrypted_data_key=key + ) + if decryption_materials.data_key: + return decryption_materials return decryption_materials @@ -201,14 +267,18 @@ class RawRSAKeyring(Keyring): :type key_provider: MasterKeyInfo """ - key_namespace = attr.ib(validator=attr.validators.instance_of(str)) - key_name = attr.ib(hash=True, validator=attr.validators.instance_of(bytes)) - _wrapping_key = attr.ib(hash=True, repr=False, validator=attr.validators.instance_of(WrappingKey)) + key_namespace = attr.ib(validator=attr.validators.instance_of(six.string_types)) + key_name = attr.ib(validator=attr.validators.instance_of(six.binary_type)) + _wrapping_key = attr.ib(repr=False, validator=attr.validators.instance_of(WrappingKey)) _wrapping_algorithm = attr.ib(repr=False, validator=attr.validators.instance_of(WrappingAlgorithm)) - _key_provider = MasterKeyInfo(provider_id=key_namespace, key_info=key_name) + def __attrs_post_init__(self): + # type: () -> None + """Prepares initial values not handled by attrs.""" + self._key_provider = MasterKeyInfo(provider_id=self.key_namespace, key_info=self.key_name) def on_encrypt(self, encryption_materials): + # type: (EncryptionMaterials) -> EncryptionMaterials """Generate a data key if not present and encrypt it using any available wrapping key. :param encryption_materials: Encryption materials for the keyring to modify. @@ -217,12 +287,15 @@ def on_encrypt(self, encryption_materials): :rtype: aws_encryption_sdk.materials_managers.EncryptionMaterials """ encryption_materials = on_encrypt_helper( - encryption_materials, self._key_provider, self._wrapping_key, self._wrapping_algorithm, self.key_name + encryption_materials=encryption_materials, key_provider=self._key_provider, + wrapping_key=self._wrapping_key, wrapping_algorithm=self._wrapping_algorithm, + key_name=self.key_name ) return encryption_materials def on_decrypt(self, decryption_materials, encrypted_data_keys): + # type: (DecryptionMaterials, Iterable[EncryptedDataKey]) -> DecryptionMaterials """Attempt to decrypt the encrypted data keys. :param decryption_materials: Decryption materials for the keyring to modify. @@ -233,10 +306,12 @@ def on_decrypt(self, decryption_materials, encrypted_data_keys): :rtype: aws_encryption_sdk.materials_managers.DecryptionMaterials """ # Decrypt data key - if encrypted_data_keys.key_provider == self._key_provider: - - decryption_materials = on_decrypt_helper( - decryption_materials, self._wrapping_key, self._wrapping_algorithm, self.key_name, encrypted_data_keys - ) + for key in encrypted_data_keys: + if key.key_provider == self._key_provider: + decryption_materials = on_decrypt_helper( + decryption_materials=decryption_materials, key_provider=self._key_provider, + wrapping_key=self._wrapping_key, wrapping_algorithm=self._wrapping_algorithm, + key_name=self.key_name, encrypted_data_key=key + ) return decryption_materials From 9038583c569e64dfe04871f8f1ff109c5119d20b Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Wed, 3 Jul 2019 09:26:38 -0700 Subject: [PATCH 25/61] Updated raw keyrings --- src/aws_encryption_sdk/keyring/raw_keyring.py | 119 +++++++++--------- 1 file changed, 62 insertions(+), 57 deletions(-) diff --git a/src/aws_encryption_sdk/keyring/raw_keyring.py b/src/aws_encryption_sdk/keyring/raw_keyring.py index 344920196..0831dc757 100644 --- a/src/aws_encryption_sdk/keyring/raw_keyring.py +++ b/src/aws_encryption_sdk/keyring/raw_keyring.py @@ -12,20 +12,21 @@ # language governing permissions and limitations under the License. """Resources required for Raw Keyrings.""" -import os import logging +import os import attr import six -from aws_encryption_sdk.internal.formatting.deserialize import deserialize_wrapped_key -from aws_encryption_sdk.internal.formatting.serialize import serialize_wrapped_key, serialize_raw_master_key_prefix from aws_encryption_sdk.exceptions import EncryptKeyError -from aws_encryption_sdk.identifiers import WrappingAlgorithm, EncryptionKeyType +from aws_encryption_sdk.identifiers import EncryptionKeyType, WrappingAlgorithm from aws_encryption_sdk.internal.crypto.wrapping_keys import WrappingKey -from aws_encryption_sdk.keyring.base import Keyring -from aws_encryption_sdk.structures import MasterKeyInfo, RawDataKey, KeyringTrace +from aws_encryption_sdk.internal.formatting.deserialize import deserialize_wrapped_key +from aws_encryption_sdk.internal.formatting.serialize import serialize_raw_master_key_prefix, serialize_wrapped_key from aws_encryption_sdk.key_providers.raw import RawMasterKey +from aws_encryption_sdk.keyring.base import Keyring +from aws_encryption_sdk.materials_managers import DecryptionMaterials, EncryptionMaterials +from aws_encryption_sdk.structures import EncryptedDataKey, KeyringTrace, MasterKeyInfo, RawDataKey try: # Python 3.5.0 and 3.5.1 have incompatible typing modules from typing import Iterable # noqa pylint: disable=unused-import @@ -45,20 +46,19 @@ def get_key_info_prefix(key_namespace, key_name, wrapping_key): :return: Serialized key_info prefix :rtype: bytes """ - key_info_prefix = serialize_raw_master_key_prefix(RawMasterKey(provider_id=key_namespace, - key_id=key_name, - wrapping_key=wrapping_key - ) - ) + key_info_prefix = serialize_raw_master_key_prefix( + RawMasterKey(provider_id=key_namespace, key_id=key_name, wrapping_key=wrapping_key) + ) return key_info_prefix -def on_encrypt_helper(encryption_materials, # type: EncryptionMaterials - key_provider, # type: MasterKeyInfo - wrapping_key, # type: WrappingKey - wrapping_algorithm, # type: WrappingAlgorithm - key_name # type: bytes - ): +def on_encrypt_helper( + encryption_materials, # type: EncryptionMaterials + key_provider, # type: MasterKeyInfo + wrapping_key, # type: WrappingKey + wrapping_algorithm, # type: WrappingAlgorithm + key_name, # type: bytes +): # type: (...) -> EncryptionMaterials """Helper function for the on_encrypt function of keyring. @@ -75,10 +75,7 @@ def on_encrypt_helper(encryption_materials, # type: EncryptionMaterials :rtype encryption_materials: aws_encryption_sdk.materials_managers.EncryptionMaterials """ # Create a keyring trace - keyring_trace = KeyringTrace( - wrapping_key=key_provider, - flags=set() - ) + keyring_trace = KeyringTrace(wrapping_key=key_provider, flags=set()) # Check if data key already exists if not encryption_materials.data_encryption_key: @@ -118,13 +115,14 @@ def on_encrypt_helper(encryption_materials, # type: EncryptionMaterials return encryption_materials -def on_decrypt_helper(decryption_materials, # type: DecryptionMaterials - key_provider, # type: MasterKeyInfo - wrapping_key, # type: WrappingKey - wrapping_algorithm, # type: WrappingAlgorithm - key_name, # type: bytes - encrypted_data_key # type: EncryptedDataKey - ): +def on_decrypt_helper( + decryption_materials, # type: DecryptionMaterials + key_provider, # type: MasterKeyInfo + wrapping_key, # type: WrappingKey + wrapping_algorithm, # type: WrappingAlgorithm + key_name, # type: bytes + encrypted_data_key, # type: EncryptedDataKey +): # type: (...) -> DecryptionMaterials """Helper function for the on_decrypt function of keyring. @@ -143,10 +141,7 @@ def on_decrypt_helper(decryption_materials, # type: DecryptionMaterials :rtype decryption_materials: aws_encryption_sdk.materials_managers.DecryptionMaterials """ # Create a keyring trace - keyring_trace = KeyringTrace( - wrapping_key=key_provider, - flags=set() - ) + keyring_trace = KeyringTrace(wrapping_key=key_provider, flags=set()) # Check if plaintext data key exists if decryption_materials.data_key: @@ -163,14 +158,12 @@ def on_decrypt_helper(decryption_materials, # type: DecryptionMaterials encrypted_wrapped_data_key=encrypted_wrapped_key, encryption_context=decryption_materials.encryption_context ) except Exception as error: - logging.ERROR(error.__class__.__name__, ':', str(error)) + logging.ERROR(error.__class__.__name__, ":", str(error)) return decryption_materials # Update decryption materials data_encryption_key = RawDataKey( - key_provider=MasterKeyInfo(provider_id=key_provider.provider_id, - key_info=key_name), - data_key=plaintext_data_key + key_provider=MasterKeyInfo(provider_id=key_provider.provider_id, key_info=key_name), data_key=plaintext_data_key ) decryption_materials.add_data_encryption_key(data_encryption_key, keyring_trace) @@ -199,14 +192,15 @@ def __attrs_post_init__(self): """Prepares initial values not handled by attrs.""" self._key_provider = MasterKeyInfo(provider_id=self.key_namespace, key_info=self.key_name) - self._key_info_prefix = get_key_info_prefix(key_namespace=self.key_namespace, - key_name=self.key_name, - wrapping_key=WrappingKey( - wrapping_algorithm=self._wrapping_algorithm, - wrapping_key=self._wrapping_key, - wrapping_key_type=EncryptionKeyType.SYMMETRIC - ) - ) + self._key_info_prefix = get_key_info_prefix( + key_namespace=self.key_namespace, + key_name=self.key_name, + wrapping_key=WrappingKey( + wrapping_algorithm=self._wrapping_algorithm, + wrapping_key=self._wrapping_key, + wrapping_key_type=EncryptionKeyType.SYMMETRIC, + ), + ) def on_encrypt(self, encryption_materials): # type: (EncryptionMaterials) -> EncryptionMaterials @@ -218,9 +212,11 @@ def on_encrypt(self, encryption_materials): :rtype: aws_encryption_sdk.materials_managers.EncryptionMaterials """ encryption_materials = on_encrypt_helper( - encryption_materials=encryption_materials, key_provider=self._key_provider, - wrapping_key=self._wrapping_key, wrapping_algorithm=self._wrapping_algorithm, - key_name=self.key_name + encryption_materials=encryption_materials, + key_provider=self._key_provider, + wrapping_key=self._wrapping_key, + wrapping_algorithm=self._wrapping_algorithm, + key_name=self.key_name, ) return encryption_materials @@ -239,14 +235,18 @@ def on_decrypt(self, decryption_materials, encrypted_data_keys): # Decrypt data key expected_key_info_len = len(self._key_info_prefix) + self._wrapping_algorithm.algorithm.iv_len for key in encrypted_data_keys: - if (key.key_provider.provider_id == self._key_provider.provider_id + if ( + key.key_provider.provider_id == self._key_provider.provider_id and len(key.key_provider.key_info) == expected_key_info_len and key.key_provider.key_info.startswith(self._key_info_prefix) ): decryption_materials = on_decrypt_helper( - decryption_materials=decryption_materials, key_provider=self._key_provider, - wrapping_key=self._wrapping_key, wrapping_algorithm=self._wrapping_algorithm, - key_name=self.key_name, encrypted_data_key=key + decryption_materials=decryption_materials, + key_provider=self._key_provider, + wrapping_key=self._wrapping_key, + wrapping_algorithm=self._wrapping_algorithm, + key_name=self.key_name, + encrypted_data_key=key, ) if decryption_materials.data_key: return decryption_materials @@ -287,9 +287,11 @@ def on_encrypt(self, encryption_materials): :rtype: aws_encryption_sdk.materials_managers.EncryptionMaterials """ encryption_materials = on_encrypt_helper( - encryption_materials=encryption_materials, key_provider=self._key_provider, - wrapping_key=self._wrapping_key, wrapping_algorithm=self._wrapping_algorithm, - key_name=self.key_name + encryption_materials=encryption_materials, + key_provider=self._key_provider, + wrapping_key=self._wrapping_key, + wrapping_algorithm=self._wrapping_algorithm, + key_name=self.key_name, ) return encryption_materials @@ -309,9 +311,12 @@ def on_decrypt(self, decryption_materials, encrypted_data_keys): for key in encrypted_data_keys: if key.key_provider == self._key_provider: decryption_materials = on_decrypt_helper( - decryption_materials=decryption_materials, key_provider=self._key_provider, - wrapping_key=self._wrapping_key, wrapping_algorithm=self._wrapping_algorithm, - key_name=self.key_name, encrypted_data_key=key + decryption_materials=decryption_materials, + key_provider=self._key_provider, + wrapping_key=self._wrapping_key, + wrapping_algorithm=self._wrapping_algorithm, + key_name=self.key_name, + encrypted_data_key=key, ) return decryption_materials From f7c951b248adcda6bd7c37c9c0218e528074c5dc Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Thu, 11 Jul 2019 14:15:08 -0700 Subject: [PATCH 26/61] Changes in error conditions for multi keyrings --- src/aws_encryption_sdk/keyring/multi_keyring.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/aws_encryption_sdk/keyring/multi_keyring.py b/src/aws_encryption_sdk/keyring/multi_keyring.py index ce2ddcc8c..b17250bbb 100644 --- a/src/aws_encryption_sdk/keyring/multi_keyring.py +++ b/src/aws_encryption_sdk/keyring/multi_keyring.py @@ -47,8 +47,8 @@ def on_encrypt(self, encryption_materials): :rtype: aws_encryption_sdk.materials_managers.EncryptionMaterials :raises EncryptKeyError: if unable to encrypt data key. """ - # Check if generator keyring is provided - if not self.generator: + # Check if generator keyring is not provided and data key is not generated + if not self.generator and not encryption_materials.data_encryption_key: raise EncryptKeyError("Generator keyring not provided.") # Check if generator keyring is provided and data key is generated From 21a129007d27e8d087c1a5f3eced95361e199ae1 Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Fri, 12 Jul 2019 17:35:25 -0700 Subject: [PATCH 27/61] Made all suggested changes in multi-keyrings --- .../keyring/multi_keyring.py | 39 ++++++++++++------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/src/aws_encryption_sdk/keyring/multi_keyring.py b/src/aws_encryption_sdk/keyring/multi_keyring.py index b17250bbb..465a18d50 100644 --- a/src/aws_encryption_sdk/keyring/multi_keyring.py +++ b/src/aws_encryption_sdk/keyring/multi_keyring.py @@ -12,6 +12,7 @@ # language governing permissions and limitations under the License. """Resources required for Multi Keyrings.""" import attr +from attr.validators import deep_iterable, deep_mapping, instance_of, optional from aws_encryption_sdk.exceptions import EncryptKeyError from aws_encryption_sdk.keyring.base import Keyring @@ -27,14 +28,20 @@ class MultiKeyring(Keyring): """Public class for Multi Keyring. - :param generator: Generator keyring used to generate data encryption key + :param generator: Generator keyring used to generate data encryption key (optional) :type generator: Keyring - :param list children: List of keyrings used to encrypt the data encryption key + :param list children: List of keyrings used to encrypt the data encryption key (optional) :raises EncryptKeyError: if encryption of data key fails for any reason """ - generator = attr.ib(validator=attr.validators.instance_of(Keyring)) - children = attr.ib(validator=attr.validators.instance_of(list)) + children = attr.ib(validator=optional(deep_iterable(member_validator=instance_of(Keyring), + iterable_validator=instance_of(list)))) + generator = attr.ib(default=None, validator=optional(instance_of(Keyring))) + + def __attrs_post_init__(self): + neither_generator_nor_children_set = self.generator is None and self.children is None + if neither_generator_nor_children_set: + raise TypeError("At least one of generator or children should be provided") def on_encrypt(self, encryption_materials): # type: (EncryptionMaterials) -> EncryptionMaterials @@ -48,15 +55,13 @@ def on_encrypt(self, encryption_materials): :raises EncryptKeyError: if unable to encrypt data key. """ # Check if generator keyring is not provided and data key is not generated - if not self.generator and not encryption_materials.data_encryption_key: - raise EncryptKeyError("Generator keyring not provided.") - - # Check if generator keyring is provided and data key is generated - if self.generator and encryption_materials.data_encryption_key: - raise EncryptKeyError("Data encryption key already exists.") + if self.generator is None and not encryption_materials.data_encryption_key: + raise EncryptKeyError("Generator keyring not provided " + "and encryption materials do not already contain a plaintext data key.") - # Call on_encrypt on the generator keyring - encryption_materials = self.generator.on_encrypt(encryption_materials) + # Call on_encrypt on the generator keyring if it is provided + if self.generator is not None: + encryption_materials = self.generator.on_encrypt(encryption_materials) # Check if data key is generated if not encryption_materials.data_encryption_key: @@ -80,13 +85,19 @@ def on_decrypt(self, decryption_materials, encrypted_data_keys): :rtype: aws_encryption_sdk.materials_managers.DecryptionMaterials """ # Check if plaintext data key exists - if decryption_materials.data_key: + if decryption_materials.data_encryption_key: return decryption_materials + # Call on_decrypt on generator keyring if it is provided + if self.generator is not None: + decryption_materials = self.generator.on_decrypt(decryption_materials, encrypted_data_keys) + if decryption_materials.data_encryption_key: + return decryption_materials + # Call on_decrypt on all keyrings till decryption is successful for keyring in self.children: decryption_materials = keyring.on_decrypt(decryption_materials, encrypted_data_keys) - if decryption_materials.data_key: + if decryption_materials.data_encryption_key: return decryption_materials return decryption_materials From d7ca059bf0d78c0d557f5041b043af8e14e2782b Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Sat, 13 Jul 2019 18:45:27 -0700 Subject: [PATCH 28/61] Corrected tox errors --- src/aws_encryption_sdk/keyring/multi_keyring.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/aws_encryption_sdk/keyring/multi_keyring.py b/src/aws_encryption_sdk/keyring/multi_keyring.py index 465a18d50..225922ac6 100644 --- a/src/aws_encryption_sdk/keyring/multi_keyring.py +++ b/src/aws_encryption_sdk/keyring/multi_keyring.py @@ -12,10 +12,12 @@ # language governing permissions and limitations under the License. """Resources required for Multi Keyrings.""" import attr -from attr.validators import deep_iterable, deep_mapping, instance_of, optional +from attr.validators import deep_iterable, instance_of, optional from aws_encryption_sdk.exceptions import EncryptKeyError from aws_encryption_sdk.keyring.base import Keyring +from aws_encryption_sdk.materials_managers import DecryptionMaterials, EncryptionMaterials +from aws_encryption_sdk.structures import EncryptedDataKey try: # Python 3.5.0 and 3.5.1 have incompatible typing modules from typing import Iterable # noqa pylint: disable=unused-import From 33d95e5f3cd00af37b49f66d3c2577c321daa503 Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Sat, 13 Jul 2019 21:56:26 -0700 Subject: [PATCH 29/61] Added docstring to __attrs_post_init__ --- src/aws_encryption_sdk/keyring/multi_keyring.py | 6 ++++-- src/aws_encryption_sdk/keyring/raw_keyring.py | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/aws_encryption_sdk/keyring/multi_keyring.py b/src/aws_encryption_sdk/keyring/multi_keyring.py index 225922ac6..8ad4a1b98 100644 --- a/src/aws_encryption_sdk/keyring/multi_keyring.py +++ b/src/aws_encryption_sdk/keyring/multi_keyring.py @@ -41,8 +41,10 @@ class MultiKeyring(Keyring): generator = attr.ib(default=None, validator=optional(instance_of(Keyring))) def __attrs_post_init__(self): - neither_generator_nor_children_set = self.generator is None and self.children is None - if neither_generator_nor_children_set: + # type: () -> None + """Prepares initial values not handled by attrs.""" + neither_generator_nor_children_defined = self.generator is None and self.children is None + if neither_generator_nor_children_defined: raise TypeError("At least one of generator or children should be provided") def on_encrypt(self, encryption_materials): diff --git a/src/aws_encryption_sdk/keyring/raw_keyring.py b/src/aws_encryption_sdk/keyring/raw_keyring.py index 0831dc757..bd9ab3e00 100644 --- a/src/aws_encryption_sdk/keyring/raw_keyring.py +++ b/src/aws_encryption_sdk/keyring/raw_keyring.py @@ -85,7 +85,7 @@ def on_encrypt_helper( # Check if data key is generated if not plaintext_data_key: - return EncryptKeyError("Unable to generate data encryption key.") + raise EncryptKeyError("Unable to generate data encryption key.") # plaintext_data_key to RawDataKey data_encryption_key = RawDataKey(key_provider=key_provider, data_key=plaintext_data_key) From 8761985c8cf3a0a728c5fbabde25599dc4672b59 Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Mon, 15 Jul 2019 09:32:14 -0700 Subject: [PATCH 30/61] Changed variable name neither_generator_nor_children_defined to neither_generator_nor_children --- src/aws_encryption_sdk/keyring/multi_keyring.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/aws_encryption_sdk/keyring/multi_keyring.py b/src/aws_encryption_sdk/keyring/multi_keyring.py index 8ad4a1b98..84cbb713d 100644 --- a/src/aws_encryption_sdk/keyring/multi_keyring.py +++ b/src/aws_encryption_sdk/keyring/multi_keyring.py @@ -43,8 +43,8 @@ class MultiKeyring(Keyring): def __attrs_post_init__(self): # type: () -> None """Prepares initial values not handled by attrs.""" - neither_generator_nor_children_defined = self.generator is None and self.children is None - if neither_generator_nor_children_defined: + neither_generator_nor_children = self.generator is None and self.children is None + if neither_generator_nor_children: raise TypeError("At least one of generator or children should be provided") def on_encrypt(self, encryption_materials): From 606c8f5f77da0e536163297b72c62c4188112839 Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Mon, 15 Jul 2019 10:49:21 -0700 Subject: [PATCH 31/61] Changed raw keyrings --- src/aws_encryption_sdk/keyring/raw_keyring.py | 29 +++++++++++++++---- 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/src/aws_encryption_sdk/keyring/raw_keyring.py b/src/aws_encryption_sdk/keyring/raw_keyring.py index bd9ab3e00..4bdef0d7a 100644 --- a/src/aws_encryption_sdk/keyring/raw_keyring.py +++ b/src/aws_encryption_sdk/keyring/raw_keyring.py @@ -19,12 +19,12 @@ import six from aws_encryption_sdk.exceptions import EncryptKeyError -from aws_encryption_sdk.identifiers import EncryptionKeyType, WrappingAlgorithm +from aws_encryption_sdk.identifiers import EncryptionKeyType, WrappingAlgorithm, KeyringTraceFlag from aws_encryption_sdk.internal.crypto.wrapping_keys import WrappingKey from aws_encryption_sdk.internal.formatting.deserialize import deserialize_wrapped_key +from aws_encryption_sdk.keyring.base import Keyring from aws_encryption_sdk.internal.formatting.serialize import serialize_raw_master_key_prefix, serialize_wrapped_key from aws_encryption_sdk.key_providers.raw import RawMasterKey -from aws_encryption_sdk.keyring.base import Keyring from aws_encryption_sdk.materials_managers import DecryptionMaterials, EncryptionMaterials from aws_encryption_sdk.structures import EncryptedDataKey, KeyringTrace, MasterKeyInfo, RawDataKey @@ -74,8 +74,6 @@ def on_encrypt_helper( :return: Optionally modified encryption materials. :rtype encryption_materials: aws_encryption_sdk.materials_managers.EncryptionMaterials """ - # Create a keyring trace - keyring_trace = KeyringTrace(wrapping_key=key_provider, flags=set()) # Check if data key already exists if not encryption_materials.data_encryption_key: @@ -87,6 +85,10 @@ def on_encrypt_helper( if not plaintext_data_key: raise EncryptKeyError("Unable to generate data encryption key.") + # Create a keyring trace + keyring_trace = KeyringTrace(wrapping_key=key_provider, + flags={KeyringTraceFlag.WRAPPING_KEY_GENERATED_DATA_KEY}) + # plaintext_data_key to RawDataKey data_encryption_key = RawDataKey(key_provider=key_provider, data_key=plaintext_data_key) @@ -95,6 +97,7 @@ def on_encrypt_helper( else: plaintext_data_key = encryption_materials.data_encryption_key + keyring_trace = encryption_materials.keyring_trace # Encrypt data key encrypted_wrapped_key = wrapping_key.encrypt( @@ -109,6 +112,15 @@ def on_encrypt_helper( encrypted_wrapped_key=encrypted_wrapped_key, ) + # Update Keyring Trace + if encrypted_data_key: + keyring_trace.wrapping_key = encrypted_data_key.key_provider + keyring_trace.flags.add(KeyringTraceFlag.WRAPPING_KEY_ENCRYPTED_DATA_KEY) + + # Add encrypted data key to encryption_materials + encryption_materials.add_encrypted_data_key(encrypted_data_key=encrypted_data_key, + keyring_trace=keyring_trace) + # Add encrypted data key to encryption_materials encryption_materials.add_encrypted_data_key(encrypted_data_key, keyring_trace) @@ -140,8 +152,6 @@ def on_decrypt_helper( :return: Optionally modified decryption materials. :rtype decryption_materials: aws_encryption_sdk.materials_managers.DecryptionMaterials """ - # Create a keyring trace - keyring_trace = KeyringTrace(wrapping_key=key_provider, flags=set()) # Check if plaintext data key exists if decryption_materials.data_key: @@ -157,10 +167,16 @@ def on_decrypt_helper( plaintext_data_key = wrapping_key.decrypt( encrypted_wrapped_data_key=encrypted_wrapped_key, encryption_context=decryption_materials.encryption_context ) + except Exception as error: logging.ERROR(error.__class__.__name__, ":", str(error)) return decryption_materials + if plaintext_data_key: + # Create a keyring trace + keyring_trace = KeyringTrace(wrapping_key=key_provider, + flags={KeyringTraceFlag.WRAPPING_KEY_DECRYPTED_DATA_KEY}) + # Update decryption materials data_encryption_key = RawDataKey( key_provider=MasterKeyInfo(provider_id=key_provider.provider_id, key_info=key_name), data_key=plaintext_data_key @@ -254,6 +270,7 @@ def on_decrypt(self, decryption_materials, encrypted_data_keys): return decryption_materials +@attr.s class RawRSAKeyring(Keyring): """Public class for Raw RSA Keyring. From 89e1c82b8b02944ba563e532e77ad842cb258d34 Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Mon, 15 Jul 2019 13:29:56 -0700 Subject: [PATCH 32/61] Corrected tox errors --- .../keyring/multi_keyring.py | 11 +++++++---- src/aws_encryption_sdk/keyring/raw_keyring.py | 19 +++++++++---------- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/src/aws_encryption_sdk/keyring/multi_keyring.py b/src/aws_encryption_sdk/keyring/multi_keyring.py index 84cbb713d..966c6fc2f 100644 --- a/src/aws_encryption_sdk/keyring/multi_keyring.py +++ b/src/aws_encryption_sdk/keyring/multi_keyring.py @@ -36,8 +36,9 @@ class MultiKeyring(Keyring): :raises EncryptKeyError: if encryption of data key fails for any reason """ - children = attr.ib(validator=optional(deep_iterable(member_validator=instance_of(Keyring), - iterable_validator=instance_of(list)))) + children = attr.ib( + validator=optional(deep_iterable(member_validator=instance_of(Keyring), iterable_validator=instance_of(list))) + ) generator = attr.ib(default=None, validator=optional(instance_of(Keyring))) def __attrs_post_init__(self): @@ -60,8 +61,10 @@ def on_encrypt(self, encryption_materials): """ # Check if generator keyring is not provided and data key is not generated if self.generator is None and not encryption_materials.data_encryption_key: - raise EncryptKeyError("Generator keyring not provided " - "and encryption materials do not already contain a plaintext data key.") + raise EncryptKeyError( + "Generator keyring not provided " + "and encryption materials do not already contain a plaintext data key." + ) # Call on_encrypt on the generator keyring if it is provided if self.generator is not None: diff --git a/src/aws_encryption_sdk/keyring/raw_keyring.py b/src/aws_encryption_sdk/keyring/raw_keyring.py index 4bdef0d7a..cde70945f 100644 --- a/src/aws_encryption_sdk/keyring/raw_keyring.py +++ b/src/aws_encryption_sdk/keyring/raw_keyring.py @@ -19,12 +19,12 @@ import six from aws_encryption_sdk.exceptions import EncryptKeyError -from aws_encryption_sdk.identifiers import EncryptionKeyType, WrappingAlgorithm, KeyringTraceFlag +from aws_encryption_sdk.identifiers import EncryptionKeyType, KeyringTraceFlag, WrappingAlgorithm from aws_encryption_sdk.internal.crypto.wrapping_keys import WrappingKey from aws_encryption_sdk.internal.formatting.deserialize import deserialize_wrapped_key -from aws_encryption_sdk.keyring.base import Keyring from aws_encryption_sdk.internal.formatting.serialize import serialize_raw_master_key_prefix, serialize_wrapped_key from aws_encryption_sdk.key_providers.raw import RawMasterKey +from aws_encryption_sdk.keyring.base import Keyring from aws_encryption_sdk.materials_managers import DecryptionMaterials, EncryptionMaterials from aws_encryption_sdk.structures import EncryptedDataKey, KeyringTrace, MasterKeyInfo, RawDataKey @@ -74,7 +74,6 @@ def on_encrypt_helper( :return: Optionally modified encryption materials. :rtype encryption_materials: aws_encryption_sdk.materials_managers.EncryptionMaterials """ - # Check if data key already exists if not encryption_materials.data_encryption_key: @@ -86,8 +85,9 @@ def on_encrypt_helper( raise EncryptKeyError("Unable to generate data encryption key.") # Create a keyring trace - keyring_trace = KeyringTrace(wrapping_key=key_provider, - flags={KeyringTraceFlag.WRAPPING_KEY_GENERATED_DATA_KEY}) + keyring_trace = KeyringTrace( + wrapping_key=key_provider, flags={KeyringTraceFlag.WRAPPING_KEY_GENERATED_DATA_KEY} + ) # plaintext_data_key to RawDataKey data_encryption_key = RawDataKey(key_provider=key_provider, data_key=plaintext_data_key) @@ -118,8 +118,7 @@ def on_encrypt_helper( keyring_trace.flags.add(KeyringTraceFlag.WRAPPING_KEY_ENCRYPTED_DATA_KEY) # Add encrypted data key to encryption_materials - encryption_materials.add_encrypted_data_key(encrypted_data_key=encrypted_data_key, - keyring_trace=keyring_trace) + encryption_materials.add_encrypted_data_key(encrypted_data_key=encrypted_data_key, keyring_trace=keyring_trace) # Add encrypted data key to encryption_materials encryption_materials.add_encrypted_data_key(encrypted_data_key, keyring_trace) @@ -152,7 +151,6 @@ def on_decrypt_helper( :return: Optionally modified decryption materials. :rtype decryption_materials: aws_encryption_sdk.materials_managers.DecryptionMaterials """ - # Check if plaintext data key exists if decryption_materials.data_key: return decryption_materials @@ -174,8 +172,9 @@ def on_decrypt_helper( if plaintext_data_key: # Create a keyring trace - keyring_trace = KeyringTrace(wrapping_key=key_provider, - flags={KeyringTraceFlag.WRAPPING_KEY_DECRYPTED_DATA_KEY}) + keyring_trace = KeyringTrace( + wrapping_key=key_provider, flags={KeyringTraceFlag.WRAPPING_KEY_DECRYPTED_DATA_KEY} + ) # Update decryption materials data_encryption_key = RawDataKey( From 0813372eb01836c50efdd03a11de00f52d0da276 Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Mon, 15 Jul 2019 14:54:24 -0700 Subject: [PATCH 33/61] Updated raw keyrings --- src/aws_encryption_sdk/keyring/raw_keyring.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/aws_encryption_sdk/keyring/raw_keyring.py b/src/aws_encryption_sdk/keyring/raw_keyring.py index cde70945f..8233cba28 100644 --- a/src/aws_encryption_sdk/keyring/raw_keyring.py +++ b/src/aws_encryption_sdk/keyring/raw_keyring.py @@ -152,7 +152,7 @@ def on_decrypt_helper( :rtype decryption_materials: aws_encryption_sdk.materials_managers.DecryptionMaterials """ # Check if plaintext data key exists - if decryption_materials.data_key: + if decryption_materials.data_encryption_key: return decryption_materials # Wrapped EncryptedDataKey to deserialized EncryptedData @@ -167,7 +167,8 @@ def on_decrypt_helper( ) except Exception as error: - logging.ERROR(error.__class__.__name__, ":", str(error)) + logger = logging.getLogger() + logger.error(error.__class__.__name__, ":", str(error)) return decryption_materials if plaintext_data_key: @@ -176,11 +177,12 @@ def on_decrypt_helper( wrapping_key=key_provider, flags={KeyringTraceFlag.WRAPPING_KEY_DECRYPTED_DATA_KEY} ) - # Update decryption materials - data_encryption_key = RawDataKey( - key_provider=MasterKeyInfo(provider_id=key_provider.provider_id, key_info=key_name), data_key=plaintext_data_key - ) - decryption_materials.add_data_encryption_key(data_encryption_key, keyring_trace) + # Update decryption materials + data_encryption_key = RawDataKey( + key_provider=MasterKeyInfo(provider_id=key_provider.provider_id, key_info=key_name), + data_key=plaintext_data_key, + ) + decryption_materials.add_data_encryption_key(data_encryption_key, keyring_trace) return decryption_materials From db696d6ca4002918036e727a0b6c39430dc489e9 Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Tue, 16 Jul 2019 14:21:13 -0700 Subject: [PATCH 34/61] Updated raw keyrings and functional test for multi keyrings --- src/aws_encryption_sdk/keyring/raw_keyring.py | 17 +++++++---------- test/functional/test_f_multi_keyring.py | 13 +++++++++++++ 2 files changed, 20 insertions(+), 10 deletions(-) create mode 100644 test/functional/test_f_multi_keyring.py diff --git a/src/aws_encryption_sdk/keyring/raw_keyring.py b/src/aws_encryption_sdk/keyring/raw_keyring.py index 8233cba28..b498c61f8 100644 --- a/src/aws_encryption_sdk/keyring/raw_keyring.py +++ b/src/aws_encryption_sdk/keyring/raw_keyring.py @@ -96,8 +96,7 @@ def on_encrypt_helper( encryption_materials.add_data_encryption_key(data_encryption_key, keyring_trace) else: - plaintext_data_key = encryption_materials.data_encryption_key - keyring_trace = encryption_materials.keyring_trace + plaintext_data_key = encryption_materials.data_encryption_key.data_key # Encrypt data key encrypted_wrapped_key = wrapping_key.encrypt( @@ -114,14 +113,12 @@ def on_encrypt_helper( # Update Keyring Trace if encrypted_data_key: - keyring_trace.wrapping_key = encrypted_data_key.key_provider - keyring_trace.flags.add(KeyringTraceFlag.WRAPPING_KEY_ENCRYPTED_DATA_KEY) - - # Add encrypted data key to encryption_materials - encryption_materials.add_encrypted_data_key(encrypted_data_key=encrypted_data_key, keyring_trace=keyring_trace) + keyring_trace = KeyringTrace( + wrapping_key=encrypted_data_key.key_provider, flags={KeyringTraceFlag.WRAPPING_KEY_ENCRYPTED_DATA_KEY} + ) - # Add encrypted data key to encryption_materials - encryption_materials.add_encrypted_data_key(encrypted_data_key, keyring_trace) + # Add encrypted data key to encryption_materials + encryption_materials.add_encrypted_data_key(encrypted_data_key=encrypted_data_key, keyring_trace=keyring_trace) return encryption_materials @@ -166,7 +163,7 @@ def on_decrypt_helper( encrypted_wrapped_data_key=encrypted_wrapped_key, encryption_context=decryption_materials.encryption_context ) - except Exception as error: + except (ValueError, Exception) as error: logger = logging.getLogger() logger.error(error.__class__.__name__, ":", str(error)) return decryption_materials diff --git a/test/functional/test_f_multi_keyring.py b/test/functional/test_f_multi_keyring.py new file mode 100644 index 000000000..f9cf216e8 --- /dev/null +++ b/test/functional/test_f_multi_keyring.py @@ -0,0 +1,13 @@ +# Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"). You +# may not use this file except in compliance with the License. A copy of +# the License is located at +# +# http://aws.amazon.com/apache2.0/ +# +# or in the "license" file accompanying this file. This file is +# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF +# ANY KIND, either express or implied. See the License for the specific +# language governing permissions and limitations under the License. +"""Functional test suite for aws_encryption_sdk.kms_thick_client""" \ No newline at end of file From de03efadc36ae59bcbbfe1391b54e787b4a8e760 Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Tue, 16 Jul 2019 15:39:53 -0700 Subject: [PATCH 35/61] Functional tests for multi-keyrings work --- .../keyring/multi_keyring.py | 9 +- .../materials_managers/__init__.py | 4 +- test/functional/test_f_multi_keyring.py | 208 +++++++++++++++++- 3 files changed, 215 insertions(+), 6 deletions(-) diff --git a/src/aws_encryption_sdk/keyring/multi_keyring.py b/src/aws_encryption_sdk/keyring/multi_keyring.py index 966c6fc2f..4945c1009 100644 --- a/src/aws_encryption_sdk/keyring/multi_keyring.py +++ b/src/aws_encryption_sdk/keyring/multi_keyring.py @@ -37,7 +37,9 @@ class MultiKeyring(Keyring): """ children = attr.ib( - validator=optional(deep_iterable(member_validator=instance_of(Keyring), iterable_validator=instance_of(list))) + default=None, + validator=optional(deep_iterable(member_validator=instance_of(Keyring), + iterable_validator=instance_of(list))) ) generator = attr.ib(default=None, validator=optional(instance_of(Keyring))) @@ -75,8 +77,9 @@ def on_encrypt(self, encryption_materials): raise EncryptKeyError("Unable to generate data encryption key.") # Call on_encrypt on all other keyrings - for keyring in self.children: - encryption_materials = keyring.on_encrypt(encryption_materials) + if self.children is not None: + for keyring in self.children: + encryption_materials = keyring.on_encrypt(encryption_materials) return encryption_materials diff --git a/src/aws_encryption_sdk/materials_managers/__init__.py b/src/aws_encryption_sdk/materials_managers/__init__.py index a1947b100..0a6dcd2f0 100644 --- a/src/aws_encryption_sdk/materials_managers/__init__.py +++ b/src/aws_encryption_sdk/materials_managers/__init__.py @@ -191,7 +191,7 @@ class EncryptionMaterials(CryptographicMaterials): Most parameters are now optional. :param Algorithm algorithm: Algorithm to use for encrypting message - :param DataKey data_encryption_key: Plaintext data key to use for encrypting message (optional) + :param RawDataKey data_encryption_key: Plaintext data key to use for encrypting message (optional) :param encrypted_data_keys: List of encrypted data keys (optional) :type encrypted_data_keys: list of :class:`EncryptedDataKey` :param dict encryption_context: Encryption context tied to `encrypted_data_keys` @@ -370,7 +370,7 @@ class DecryptionMaterials(CryptographicMaterials): All parameters are now optional. :param Algorithm algorithm: Algorithm to use for encrypting message (optional) - :param DataKey data_encryption_key: Plaintext data key to use for encrypting message (optional) + :param RawDataKey data_encryption_key: Plaintext data key to use for encrypting message (optional) :param dict encryption_context: Encryption context tied to `encrypted_data_keys` (optional) :param bytes verification_key: Raw signature verification key (optional) :param keyring_trace: Any KeyRing trace entries (optional) diff --git a/test/functional/test_f_multi_keyring.py b/test/functional/test_f_multi_keyring.py index f9cf216e8..b98de9b94 100644 --- a/test/functional/test_f_multi_keyring.py +++ b/test/functional/test_f_multi_keyring.py @@ -10,4 +10,210 @@ # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF # ANY KIND, either express or implied. See the License for the specific # language governing permissions and limitations under the License. -"""Functional test suite for aws_encryption_sdk.kms_thick_client""" \ No newline at end of file +"""Functional tests for Multi keyring encryption decryption path.""" + +import pytest + +from aws_encryption_sdk.identifiers import Algorithm, EncryptionKeyType, WrappingAlgorithm, KeyringTraceFlag +from aws_encryption_sdk.keyring.multi_keyring import MultiKeyring +from aws_encryption_sdk.keyring.raw_keyring import RawAESKeyring, RawRSAKeyring, WrappingKey +from aws_encryption_sdk.materials_managers import DecryptionMaterials, EncryptionMaterials +from aws_encryption_sdk.structures import RawDataKey, EncryptedDataKey, MasterKeyInfo, KeyringTrace + +pytestmark = [pytest.mark.functional, pytest.mark.local] + +_ENCRYPTION_CONTEXT = {"encryption": "context", "values": "here"} +_PROVIDER_ID = "Random Raw Keys" +_KEY_ID = b"5325b043-5843-4629-869c-64794af77ada" +_WRAPPING_KEY_AES = b"\xeby-\x80A6\x15rA8\x83#,\xe4\xab\xac`\xaf\x99Z\xc1\xce\xdb\xb6\x0f\xb7\x805\xb2\x14J3" + +_WRAPPING_KEY_RSA1 = ( + b"-----BEGIN RSA PRIVATE KEY-----\n" + b"MIIEowIBAAKCAQEAo8uCyhiO4JUGZV+rtNq5DBA9Lm4xkw5kTA3v6EPybs8bVXL2\n" + b"ZE6jkbo+xT4Jg/bKzUpnp1fE+T1ruGPtsPdoEmhY/P64LDNIs3sRq5U4QV9IETU1\n" + b"vIcbNNkgGhRjV8J87YNY0tV0H7tuWuZRpqnS+gjV6V9lUMkbvjMCc5IBqQc3heut\n" + b"/+fH4JwpGlGxOVXI8QAapnSy1XpCr3+PT29kydVJnIMuAoFrurojRpOQbOuVvhtA\n" + b"gARhst1Ji4nfROGYkj6eZhvkz2Bkud4/+3lGvVU5LO1vD8oY7WoGtpin3h50VcWe\n" + b"aBT4kejx4s9/G9C4R24lTH09J9HO2UUsuCqZYQIDAQABAoIBAQCfC90bCk+qaWqF\n" + b"gymC+qOWwCn4bM28gswHQb1D5r6AtKBRD8mKywVvWs7azguFVV3Fi8sspkBA2FBC\n" + b"At5p6ULoJOTL/TauzLl6djVJTCMM701WUDm2r+ZOIctXJ5bzP4n5Q4I7b0NMEL7u\n" + b"ixib4elYGr5D1vrVQAKtZHCr8gmkqyx8Mz7wkJepzBP9EeVzETCHsmiQDd5WYlO1\n" + b"C2IQYgw6MJzgM4entJ0V/GPytkodblGY95ORVK7ZhyNtda+r5BZ6/jeMW+hA3VoK\n" + b"tHSWjHt06ueVCCieZIATmYzBNt+zEz5UA2l7ksg3eWfVORJQS7a6Ef4VvbJLM9Ca\n" + b"m1kdsjelAoGBANKgvRf39i3bSuvm5VoyJuqinSb/23IH3Zo7XOZ5G164vh49E9Cq\n" + b"dOXXVxox74ppj/kbGUoOk+AvaB48zzfzNvac0a7lRHExykPH2kVrI/NwH/1OcT/x\n" + b"2e2DnFYocXcb4gbdZQ+m6X3zkxOYcONRzPVW1uMrFTWHcJveMUm4PGx7AoGBAMcU\n" + b"IRvrT6ye5se0s27gHnPweV+3xjsNtXZcK82N7duXyHmNjxrwOAv0SOhUmTkRXArM\n" + b"6aN5D8vyZBSWma2TgUKwpQYFTI+4Sp7sdkkyojGAEixJ+c5TZJNxZFrUe0FwAoic\n" + b"c2kb7ntaiEj5G+qHvykJJro5hy6uLnjiMVbAiJDTAoGAKb67241EmHAXGEwp9sdr\n" + b"2SMjnIAnQSF39UKAthkYqJxa6elXDQtLoeYdGE7/V+J2K3wIdhoPiuY6b4vD0iX9\n" + b"JcGM+WntN7YTjX2FsC588JmvbWfnoDHR7HYiPR1E58N597xXdFOzgUgORVr4PMWQ\n" + b"pqtwaZO3X2WZlvrhr+e46hMCgYBfdIdrm6jYXFjL6RkgUNZJQUTxYGzsY+ZemlNm\n" + b"fGdQo7a8kePMRuKY2MkcnXPaqTg49YgRmjq4z8CtHokRcWjJUWnPOTs8rmEZUshk\n" + b"0KJ0mbQdCFt/Uv0mtXgpFTkEZ3DPkDTGcV4oR4CRfOCl0/EU/A5VvL/U4i/mRo7h\n" + b"ye+xgQKBgD58b+9z+PR5LAJm1tZHIwb4tnyczP28PzwknxFd2qylR4ZNgvAUqGtU\n" + b"xvpUDpzMioz6zUH9YV43YNtt+5Xnzkqj+u9Mr27/H2v9XPwORGfwQ5XPwRJz/2oC\n" + b"EnPmP1SZoY9lXKUpQXHXSpDZ2rE2Klt3RHMUMHt8Zpy36E8Vwx8o\n" + b"-----END RSA PRIVATE KEY-----\n" +) +_WRAPPING_KEY_RSA2 = ( + b"-----BEGIN RSA PRIVATE KEY-----" + b"MIICXgIBAAKBgQCUjhI8YRPXV8Gfofbg/" + b"PLjWw2AzowQTPErLU2z3+xGqElMdzdiC4Ta43DFWZg34Eg0X8kQPAeoe8h3cRSMo" + b"77eSOHt2dPo7OfTfZqsH8766fivHIKVxBYPX8SZYIUhMtRnlg3uqch9BksfRop+h" + b"f8h/H3lfervJoevS2CXYB9/iwIDAQABAoGBAIqeGzQOHbaGI51yQ2zjez1dPDdiB" + b"F49fZideHEM1GuGIodgguRQ/VJGgncUSC5zcMy2SGaGrVqwznltohAtxy4rZp0eh" + b"2O3aHYi9Wehd0SPLh+qwu7mJDuh0z15hmCOue070FnUtyuSwhXLwDrbot2+5HbmF" + b"9clJLI5tv92gvIpAkEA+Bv5i8XJNPN1rao31aQFoi9bFIOEclk3b1RbLX6mpZBFS" + b"U9CNUy0RQNC0+H3KZ5CTvsyFGpMfTdiFc/Qdesk3QJBAJlHjrvoadP+PU3zXYrWR" + b"D5EryyTxaP1bOjrp9xLuQBeU8x7EVJdpoul9OmwcT3NrAqvxDE9okjha2tjCI6O2" + b"4cCQQDMyOJPYL/zaaPO5LlTKB/SPv4RT4BplYPw6xKa2XeZHhxiJv5B2f7NG6T0G" + b"AWWn16hrCoouZhKngTidfXc7motAkA/KiTgvKr3yHp86AAxWZDv1CAYD6FPqrDB3" + b"3LiLnZDd5uy1ThTJ/Kc87vUnXhdDqeKE9qWrB53SCWbMElzbd17AkEA4DMp+6ngM" + b"o6sS0dY1X6nTLqgvK3B0z5GCAdSEy3Y8jh995Lrl+hy88HzuwUkQwwPlZkFhUNCx" + b"edrC6cTKE5xLA==" + b"-----END RSA PRIVATE KEY-----" +) +_SIGNING_KEY = b"aws-crypto-public-key" + +_ENCRYPTION_MATERIALS = [ + EncryptionMaterials( + algorithm=Algorithm.AES_256_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384, + encryption_context=_ENCRYPTION_CONTEXT, + signing_key=_SIGNING_KEY, + ), + EncryptionMaterials( + algorithm=Algorithm.AES_256_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384, + data_encryption_key=RawDataKey( + key_provider=MasterKeyInfo(provider_id=_PROVIDER_ID, key_info=_KEY_ID), + data_key=b'*!\xa1"^-(\xf3\x105\x05i@B\xc2\xa2\xb7\xdd\xd5\xd5\xa9\xddm\xfae\xa8\\$\xf9d\x1e(', + ), + encryption_context=_ENCRYPTION_CONTEXT, + signing_key=_SIGNING_KEY, + keyring_trace=[ + KeyringTrace( + wrapping_key=MasterKeyInfo(provider_id=_PROVIDER_ID, key_info=_KEY_ID), + flags={KeyringTraceFlag.WRAPPING_KEY_GENERATED_DATA_KEY}, + ) + ], + ), + EncryptionMaterials( + algorithm=Algorithm.AES_256_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384, + data_encryption_key=RawDataKey( + key_provider=MasterKeyInfo(provider_id=_PROVIDER_ID, key_info=_KEY_ID), + data_key=b'*!\xa1"^-(\xf3\x105\x05i@B\xc2\xa2\xb7\xdd\xd5\xd5\xa9\xddm\xfae\xa8\\$\xf9d\x1e(', + ), + encrypted_data_keys=[ + EncryptedDataKey( + key_provider=MasterKeyInfo(provider_id=_PROVIDER_ID, key_info=_KEY_ID), + encrypted_data_key=b"\xde^\x97\x7f\x84\xe9\x9e\x98\xd0\xe2\xf8\xd5\xcb\xe9\x7f.}\x87\x16,\x11n#\xc8p" + b"\xdb\xbf\x94\x86*Q\x06\xd2\xf5\xdah\x08\xa4p\x81\xf7\xf4G\x07FzE\xde", + ) + ], + encryption_context=_ENCRYPTION_CONTEXT, + signing_key=_SIGNING_KEY, + keyring_trace=[ + KeyringTrace( + wrapping_key=MasterKeyInfo(provider_id=_PROVIDER_ID, key_info=_KEY_ID), + flags={ + KeyringTraceFlag.WRAPPING_KEY_GENERATED_DATA_KEY, + KeyringTraceFlag.WRAPPING_KEY_ENCRYPTED_DATA_KEY, + }, + ), + ] + ) +] + +_MULTI_KEYRINGS = [ + MultiKeyring( + generator=RawAESKeyring( + key_namespace=_PROVIDER_ID, + key_name=_KEY_ID, + wrapping_algorithm=WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING, + wrapping_key=WrappingKey( + wrapping_algorithm=WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING, + wrapping_key=_WRAPPING_KEY_AES, + wrapping_key_type=EncryptionKeyType.SYMMETRIC, + ) + ), + children=[ + RawRSAKeyring( + key_namespace=_PROVIDER_ID, + key_name=_KEY_ID, + wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, + wrapping_key=WrappingKey( + wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, + wrapping_key=_WRAPPING_KEY_RSA1, + wrapping_key_type=EncryptionKeyType.PRIVATE, + ) + ), + RawRSAKeyring( + key_namespace=_PROVIDER_ID, + key_name=_KEY_ID, + wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, + wrapping_key=WrappingKey( + wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, + wrapping_key=_WRAPPING_KEY_RSA1, + wrapping_key_type=EncryptionKeyType.PRIVATE, + ) + ) + ] + ), + MultiKeyring( + generator=RawRSAKeyring( + key_namespace=_PROVIDER_ID, + key_name=_KEY_ID, + wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, + wrapping_key=WrappingKey( + wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, + wrapping_key=_WRAPPING_KEY_RSA1, + wrapping_key_type=EncryptionKeyType.PRIVATE, + ) + ) + ), + MultiKeyring( + children=[ + RawRSAKeyring( + key_namespace=_PROVIDER_ID, + key_name=_KEY_ID, + wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, + wrapping_key=WrappingKey( + wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, + wrapping_key=_WRAPPING_KEY_RSA1, + wrapping_key_type=EncryptionKeyType.PRIVATE, + ) + ), + RawAESKeyring( + key_namespace=_PROVIDER_ID, + key_name=_KEY_ID, + wrapping_algorithm=WrappingAlgorithm.AES_128_GCM_IV12_TAG16_NO_PADDING, + wrapping_key=WrappingKey( + wrapping_algorithm=WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING, + wrapping_key=_WRAPPING_KEY_AES, + wrapping_key_type=EncryptionKeyType.SYMMETRIC, + ) + ) + ] + ) +] + + +@pytest.mark.parametrize("multi_keyring",_MULTI_KEYRINGS) +def test_multi_keyring_encryption_decryption(multi_keyring): + for i in range(len(_ENCRYPTION_MATERIALS)): + # Call on_encrypt function for the keyring + encryption_materials = multi_keyring.on_encrypt(_ENCRYPTION_MATERIALS[i]) + + # Generate decryption materials + decryption_materials = DecryptionMaterials( + algorithm=Algorithm.AES_256_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384, verification_key=b"ex_verification_key" + ) + + # Call on_decrypt function for the keyring + decryption_materials = multi_keyring.on_decrypt( + decryption_materials=decryption_materials, encrypted_data_keys=encryption_materials.encrypted_data_keys + ) + + if decryption_materials.data_encryption_key: + # Check if the data keys match + assert encryption_materials.data_encryption_key == decryption_materials.data_encryption_key From afa9ebc36d657f8d66fae1444f001497844bdd94 Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Tue, 16 Jul 2019 15:49:13 -0700 Subject: [PATCH 36/61] Autoformat errors corrected and changed Exception to BaseException to solve broad exception error --- .../keyring/multi_keyring.py | 3 +- src/aws_encryption_sdk/keyring/raw_keyring.py | 2 +- test/functional/test_f_multi_keyring.py | 148 +++++++++--------- 3 files changed, 76 insertions(+), 77 deletions(-) diff --git a/src/aws_encryption_sdk/keyring/multi_keyring.py b/src/aws_encryption_sdk/keyring/multi_keyring.py index 4945c1009..6eb38e7ec 100644 --- a/src/aws_encryption_sdk/keyring/multi_keyring.py +++ b/src/aws_encryption_sdk/keyring/multi_keyring.py @@ -38,8 +38,7 @@ class MultiKeyring(Keyring): children = attr.ib( default=None, - validator=optional(deep_iterable(member_validator=instance_of(Keyring), - iterable_validator=instance_of(list))) + validator=optional(deep_iterable(member_validator=instance_of(Keyring), iterable_validator=instance_of(list))), ) generator = attr.ib(default=None, validator=optional(instance_of(Keyring))) diff --git a/src/aws_encryption_sdk/keyring/raw_keyring.py b/src/aws_encryption_sdk/keyring/raw_keyring.py index b498c61f8..3380fbad3 100644 --- a/src/aws_encryption_sdk/keyring/raw_keyring.py +++ b/src/aws_encryption_sdk/keyring/raw_keyring.py @@ -163,7 +163,7 @@ def on_decrypt_helper( encrypted_wrapped_data_key=encrypted_wrapped_key, encryption_context=decryption_materials.encryption_context ) - except (ValueError, Exception) as error: + except BaseException as error: logger = logging.getLogger() logger.error(error.__class__.__name__, ":", str(error)) return decryption_materials diff --git a/test/functional/test_f_multi_keyring.py b/test/functional/test_f_multi_keyring.py index b98de9b94..435d83e88 100644 --- a/test/functional/test_f_multi_keyring.py +++ b/test/functional/test_f_multi_keyring.py @@ -14,11 +14,11 @@ import pytest -from aws_encryption_sdk.identifiers import Algorithm, EncryptionKeyType, WrappingAlgorithm, KeyringTraceFlag +from aws_encryption_sdk.identifiers import Algorithm, EncryptionKeyType, KeyringTraceFlag, WrappingAlgorithm from aws_encryption_sdk.keyring.multi_keyring import MultiKeyring from aws_encryption_sdk.keyring.raw_keyring import RawAESKeyring, RawRSAKeyring, WrappingKey from aws_encryption_sdk.materials_managers import DecryptionMaterials, EncryptionMaterials -from aws_encryption_sdk.structures import RawDataKey, EncryptedDataKey, MasterKeyInfo, KeyringTrace +from aws_encryption_sdk.structures import EncryptedDataKey, KeyringTrace, MasterKeyInfo, RawDataKey pytestmark = [pytest.mark.functional, pytest.mark.local] @@ -77,51 +77,51 @@ _SIGNING_KEY = b"aws-crypto-public-key" _ENCRYPTION_MATERIALS = [ - EncryptionMaterials( - algorithm=Algorithm.AES_256_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384, - encryption_context=_ENCRYPTION_CONTEXT, - signing_key=_SIGNING_KEY, + EncryptionMaterials( + algorithm=Algorithm.AES_256_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384, + encryption_context=_ENCRYPTION_CONTEXT, + signing_key=_SIGNING_KEY, + ), + EncryptionMaterials( + algorithm=Algorithm.AES_256_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384, + data_encryption_key=RawDataKey( + key_provider=MasterKeyInfo(provider_id=_PROVIDER_ID, key_info=_KEY_ID), + data_key=b'*!\xa1"^-(\xf3\x105\x05i@B\xc2\xa2\xb7\xdd\xd5\xd5\xa9\xddm\xfae\xa8\\$\xf9d\x1e(', ), - EncryptionMaterials( - algorithm=Algorithm.AES_256_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384, - data_encryption_key=RawDataKey( - key_provider=MasterKeyInfo(provider_id=_PROVIDER_ID, key_info=_KEY_ID), - data_key=b'*!\xa1"^-(\xf3\x105\x05i@B\xc2\xa2\xb7\xdd\xd5\xd5\xa9\xddm\xfae\xa8\\$\xf9d\x1e(', - ), - encryption_context=_ENCRYPTION_CONTEXT, - signing_key=_SIGNING_KEY, - keyring_trace=[ - KeyringTrace( - wrapping_key=MasterKeyInfo(provider_id=_PROVIDER_ID, key_info=_KEY_ID), - flags={KeyringTraceFlag.WRAPPING_KEY_GENERATED_DATA_KEY}, - ) - ], - ), - EncryptionMaterials( - algorithm=Algorithm.AES_256_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384, - data_encryption_key=RawDataKey( + encryption_context=_ENCRYPTION_CONTEXT, + signing_key=_SIGNING_KEY, + keyring_trace=[ + KeyringTrace( + wrapping_key=MasterKeyInfo(provider_id=_PROVIDER_ID, key_info=_KEY_ID), + flags={KeyringTraceFlag.WRAPPING_KEY_GENERATED_DATA_KEY}, + ) + ], + ), + EncryptionMaterials( + algorithm=Algorithm.AES_256_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384, + data_encryption_key=RawDataKey( + key_provider=MasterKeyInfo(provider_id=_PROVIDER_ID, key_info=_KEY_ID), + data_key=b'*!\xa1"^-(\xf3\x105\x05i@B\xc2\xa2\xb7\xdd\xd5\xd5\xa9\xddm\xfae\xa8\\$\xf9d\x1e(', + ), + encrypted_data_keys=[ + EncryptedDataKey( key_provider=MasterKeyInfo(provider_id=_PROVIDER_ID, key_info=_KEY_ID), - data_key=b'*!\xa1"^-(\xf3\x105\x05i@B\xc2\xa2\xb7\xdd\xd5\xd5\xa9\xddm\xfae\xa8\\$\xf9d\x1e(', - ), - encrypted_data_keys=[ - EncryptedDataKey( - key_provider=MasterKeyInfo(provider_id=_PROVIDER_ID, key_info=_KEY_ID), - encrypted_data_key=b"\xde^\x97\x7f\x84\xe9\x9e\x98\xd0\xe2\xf8\xd5\xcb\xe9\x7f.}\x87\x16,\x11n#\xc8p" - b"\xdb\xbf\x94\x86*Q\x06\xd2\xf5\xdah\x08\xa4p\x81\xf7\xf4G\x07FzE\xde", - ) - ], - encryption_context=_ENCRYPTION_CONTEXT, - signing_key=_SIGNING_KEY, - keyring_trace=[ - KeyringTrace( - wrapping_key=MasterKeyInfo(provider_id=_PROVIDER_ID, key_info=_KEY_ID), - flags={ - KeyringTraceFlag.WRAPPING_KEY_GENERATED_DATA_KEY, - KeyringTraceFlag.WRAPPING_KEY_ENCRYPTED_DATA_KEY, - }, - ), - ] - ) + encrypted_data_key=b"\xde^\x97\x7f\x84\xe9\x9e\x98\xd0\xe2\xf8\xd5\xcb\xe9\x7f.}\x87\x16,\x11n#\xc8p" + b"\xdb\xbf\x94\x86*Q\x06\xd2\xf5\xdah\x08\xa4p\x81\xf7\xf4G\x07FzE\xde", + ) + ], + encryption_context=_ENCRYPTION_CONTEXT, + signing_key=_SIGNING_KEY, + keyring_trace=[ + KeyringTrace( + wrapping_key=MasterKeyInfo(provider_id=_PROVIDER_ID, key_info=_KEY_ID), + flags={ + KeyringTraceFlag.WRAPPING_KEY_GENERATED_DATA_KEY, + KeyringTraceFlag.WRAPPING_KEY_ENCRYPTED_DATA_KEY, + }, + ) + ], + ), ] _MULTI_KEYRINGS = [ @@ -131,10 +131,10 @@ key_name=_KEY_ID, wrapping_algorithm=WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING, wrapping_key=WrappingKey( - wrapping_algorithm=WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING, - wrapping_key=_WRAPPING_KEY_AES, - wrapping_key_type=EncryptionKeyType.SYMMETRIC, - ) + wrapping_algorithm=WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING, + wrapping_key=_WRAPPING_KEY_AES, + wrapping_key_type=EncryptionKeyType.SYMMETRIC, + ), ), children=[ RawRSAKeyring( @@ -142,22 +142,22 @@ key_name=_KEY_ID, wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, wrapping_key=WrappingKey( - wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, - wrapping_key=_WRAPPING_KEY_RSA1, - wrapping_key_type=EncryptionKeyType.PRIVATE, - ) + wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, + wrapping_key=_WRAPPING_KEY_RSA1, + wrapping_key_type=EncryptionKeyType.PRIVATE, + ), ), RawRSAKeyring( key_namespace=_PROVIDER_ID, key_name=_KEY_ID, wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, wrapping_key=WrappingKey( - wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, - wrapping_key=_WRAPPING_KEY_RSA1, - wrapping_key_type=EncryptionKeyType.PRIVATE, - ) - ) - ] + wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, + wrapping_key=_WRAPPING_KEY_RSA1, + wrapping_key_type=EncryptionKeyType.PRIVATE, + ), + ), + ], ), MultiKeyring( generator=RawRSAKeyring( @@ -165,10 +165,10 @@ key_name=_KEY_ID, wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, wrapping_key=WrappingKey( - wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, - wrapping_key=_WRAPPING_KEY_RSA1, - wrapping_key_type=EncryptionKeyType.PRIVATE, - ) + wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, + wrapping_key=_WRAPPING_KEY_RSA1, + wrapping_key_type=EncryptionKeyType.PRIVATE, + ), ) ), MultiKeyring( @@ -178,27 +178,27 @@ key_name=_KEY_ID, wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, wrapping_key=WrappingKey( - wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, - wrapping_key=_WRAPPING_KEY_RSA1, - wrapping_key_type=EncryptionKeyType.PRIVATE, - ) + wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, + wrapping_key=_WRAPPING_KEY_RSA1, + wrapping_key_type=EncryptionKeyType.PRIVATE, + ), ), RawAESKeyring( key_namespace=_PROVIDER_ID, key_name=_KEY_ID, wrapping_algorithm=WrappingAlgorithm.AES_128_GCM_IV12_TAG16_NO_PADDING, wrapping_key=WrappingKey( - wrapping_algorithm=WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING, - wrapping_key=_WRAPPING_KEY_AES, - wrapping_key_type=EncryptionKeyType.SYMMETRIC, - ) - ) + wrapping_algorithm=WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING, + wrapping_key=_WRAPPING_KEY_AES, + wrapping_key_type=EncryptionKeyType.SYMMETRIC, + ), + ), ] - ) + ), ] -@pytest.mark.parametrize("multi_keyring",_MULTI_KEYRINGS) +@pytest.mark.parametrize("multi_keyring", _MULTI_KEYRINGS) def test_multi_keyring_encryption_decryption(multi_keyring): for i in range(len(_ENCRYPTION_MATERIALS)): # Call on_encrypt function for the keyring From a1cdb256965391d1ff7b448cb262edb587260849 Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Tue, 16 Jul 2019 17:47:56 -0700 Subject: [PATCH 37/61] Added pylint disable broad except to raw keyrings and added multi parametrize to multi keyrings functional test --- src/aws_encryption_sdk/keyring/raw_keyring.py | 2 +- test/functional/test_f_multi_keyring.py | 30 +++++++++---------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/aws_encryption_sdk/keyring/raw_keyring.py b/src/aws_encryption_sdk/keyring/raw_keyring.py index 3380fbad3..16158a727 100644 --- a/src/aws_encryption_sdk/keyring/raw_keyring.py +++ b/src/aws_encryption_sdk/keyring/raw_keyring.py @@ -163,7 +163,7 @@ def on_decrypt_helper( encrypted_wrapped_data_key=encrypted_wrapped_key, encryption_context=decryption_materials.encryption_context ) - except BaseException as error: + except Exception as error: # pylint: disable=broad-except logger = logging.getLogger() logger.error(error.__class__.__name__, ":", str(error)) return decryption_materials diff --git a/test/functional/test_f_multi_keyring.py b/test/functional/test_f_multi_keyring.py index 435d83e88..63cb62f8e 100644 --- a/test/functional/test_f_multi_keyring.py +++ b/test/functional/test_f_multi_keyring.py @@ -199,21 +199,21 @@ @pytest.mark.parametrize("multi_keyring", _MULTI_KEYRINGS) -def test_multi_keyring_encryption_decryption(multi_keyring): - for i in range(len(_ENCRYPTION_MATERIALS)): - # Call on_encrypt function for the keyring - encryption_materials = multi_keyring.on_encrypt(_ENCRYPTION_MATERIALS[i]) +@pytest.mark.parametrize("encryption_materials", _ENCRYPTION_MATERIALS) +def test_multi_keyring_encryption_decryption(multi_keyring, encryption_materials): + # Call on_encrypt function for the keyring + encryption_materials = multi_keyring.on_encrypt(encryption_materials) - # Generate decryption materials - decryption_materials = DecryptionMaterials( - algorithm=Algorithm.AES_256_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384, verification_key=b"ex_verification_key" - ) + # Generate decryption materials + decryption_materials = DecryptionMaterials( + algorithm=Algorithm.AES_256_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384, verification_key=b"ex_verification_key" + ) - # Call on_decrypt function for the keyring - decryption_materials = multi_keyring.on_decrypt( - decryption_materials=decryption_materials, encrypted_data_keys=encryption_materials.encrypted_data_keys - ) + # Call on_decrypt function for the keyring + decryption_materials = multi_keyring.on_decrypt( + decryption_materials=decryption_materials, encrypted_data_keys=encryption_materials.encrypted_data_keys + ) - if decryption_materials.data_encryption_key: - # Check if the data keys match - assert encryption_materials.data_encryption_key == decryption_materials.data_encryption_key + if decryption_materials.data_encryption_key: + # Check if the data keys match + assert encryption_materials.data_encryption_key == decryption_materials.data_encryption_key From 2469b3aa0c6c74f9351479cdb6d9732eeedc2c5d Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Tue, 16 Jul 2019 17:58:09 -0700 Subject: [PATCH 38/61] Removed duplicate import statements --- src/aws_encryption_sdk/keyring/multi_keyring.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/aws_encryption_sdk/keyring/multi_keyring.py b/src/aws_encryption_sdk/keyring/multi_keyring.py index 6eb38e7ec..039e83389 100644 --- a/src/aws_encryption_sdk/keyring/multi_keyring.py +++ b/src/aws_encryption_sdk/keyring/multi_keyring.py @@ -15,9 +15,7 @@ from attr.validators import deep_iterable, instance_of, optional from aws_encryption_sdk.exceptions import EncryptKeyError -from aws_encryption_sdk.keyring.base import Keyring -from aws_encryption_sdk.materials_managers import DecryptionMaterials, EncryptionMaterials -from aws_encryption_sdk.structures import EncryptedDataKey +from aws_encryption_sdk.keyring.base import DecryptionMaterials, EncryptedDataKey, EncryptionMaterials, Keyring try: # Python 3.5.0 and 3.5.1 have incompatible typing modules from typing import Iterable # noqa pylint: disable=unused-import From 80d58d48b782ef2b0333deccf985b64f049419af Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Wed, 17 Jul 2019 18:41:02 -0700 Subject: [PATCH 39/61] Changes in functional test for multi keyrings according to change in raw keyrings --- src/aws_encryption_sdk/keyring/raw_keyring.py | 260 ++++++++++-------- test/functional/test_f_multi_keyring.py | 66 ++--- 2 files changed, 164 insertions(+), 162 deletions(-) diff --git a/src/aws_encryption_sdk/keyring/raw_keyring.py b/src/aws_encryption_sdk/keyring/raw_keyring.py index 16158a727..93d6fd080 100644 --- a/src/aws_encryption_sdk/keyring/raw_keyring.py +++ b/src/aws_encryption_sdk/keyring/raw_keyring.py @@ -17,10 +17,12 @@ import attr import six +from cryptography.hazmat.primitives.asymmetric.padding import OAEP +from cryptography.hazmat.primitives.asymmetric.rsa import RSAPrivateKey, RSAPublicKey from aws_encryption_sdk.exceptions import EncryptKeyError from aws_encryption_sdk.identifiers import EncryptionKeyType, KeyringTraceFlag, WrappingAlgorithm -from aws_encryption_sdk.internal.crypto.wrapping_keys import WrappingKey +from aws_encryption_sdk.internal.crypto.wrapping_keys import EncryptedData, WrappingKey from aws_encryption_sdk.internal.formatting.deserialize import deserialize_wrapped_key from aws_encryption_sdk.internal.formatting.serialize import serialize_raw_master_key_prefix, serialize_wrapped_key from aws_encryption_sdk.key_providers.raw import RawMasterKey @@ -55,24 +57,15 @@ def get_key_info_prefix(key_namespace, key_name, wrapping_key): def on_encrypt_helper( encryption_materials, # type: EncryptionMaterials key_provider, # type: MasterKeyInfo - wrapping_key, # type: WrappingKey - wrapping_algorithm, # type: WrappingAlgorithm - key_name, # type: bytes ): - # type: (...) -> EncryptionMaterials + # type: (...) -> bytes """Helper function for the on_encrypt function of keyring. :param encryption_materials: Encryption materials for the keyring to modify. :type encryption_materials: aws_encryption_sdk.materials_managers.EncryptionMaterials :param key_provider: Information about the key in the keyring. :type key_provider: MasterKeyInfo - :param wrapping_key: Encryption key with which to wrap plaintext data key. - :type wrapping_key: WrappingKey - :param wrapping_algorithm: Wrapping Algorithm with which to wrap plaintext data key. - :type wrapping_algorithm: WrappingAlgorithm - :param bytes key_name: Key ID. - :return: Optionally modified encryption materials. - :rtype encryption_materials: aws_encryption_sdk.materials_managers.EncryptionMaterials + :return bytes: Plaintext data key """ # Check if data key already exists if not encryption_materials.data_encryption_key: @@ -98,90 +91,32 @@ def on_encrypt_helper( else: plaintext_data_key = encryption_materials.data_encryption_key.data_key - # Encrypt data key - encrypted_wrapped_key = wrapping_key.encrypt( - plaintext_data_key=plaintext_data_key, encryption_context=encryption_materials.encryption_context - ) - - # EncryptedData to EncryptedDataKey - encrypted_data_key = serialize_wrapped_key( - key_provider=key_provider, - wrapping_algorithm=wrapping_algorithm, - wrapping_key_id=key_name, - encrypted_wrapped_key=encrypted_wrapped_key, - ) - - # Update Keyring Trace - if encrypted_data_key: - keyring_trace = KeyringTrace( - wrapping_key=encrypted_data_key.key_provider, flags={KeyringTraceFlag.WRAPPING_KEY_ENCRYPTED_DATA_KEY} - ) - - # Add encrypted data key to encryption_materials - encryption_materials.add_encrypted_data_key(encrypted_data_key=encrypted_data_key, keyring_trace=keyring_trace) - - return encryption_materials + return plaintext_data_key def on_decrypt_helper( - decryption_materials, # type: DecryptionMaterials - key_provider, # type: MasterKeyInfo - wrapping_key, # type: WrappingKey wrapping_algorithm, # type: WrappingAlgorithm key_name, # type: bytes encrypted_data_key, # type: EncryptedDataKey ): - # type: (...) -> DecryptionMaterials + # type: (...) -> EncryptedData """Helper function for the on_decrypt function of keyring. - :param decryption_materials: Decryption materials for the keyring to modify. - :type decryption_materials: aws_encryption_sdk.materials_managers.DecryptionMaterials - :param key_provider: Information about the key in the keyring. - :type key_provider: MasterKeyInfo - :param wrapping_key: Encryption key with which to wrap plaintext data key. - :type wrapping_key: WrappingKey :param wrapping_algorithm: Wrapping Algorithm with which to wrap plaintext data key. :type wrapping_algorithm: WrappingAlgorithm :param bytes key_name: Key ID. :param encrypted_data_key: Data key encrypted with a wrapping key. :type encrypted_data_key: aws_encryption_sdk.structures.EncryptedDataKey - :return: Optionally modified decryption materials. - :rtype decryption_materials: aws_encryption_sdk.materials_managers.DecryptionMaterials + :return encrypted_wrapped_key: Encrypted, wrapped, data key + :rtype encrypted_wrapped_key: EncryptedData """ - # Check if plaintext data key exists - if decryption_materials.data_encryption_key: - return decryption_materials # Wrapped EncryptedDataKey to deserialized EncryptedData encrypted_wrapped_key = deserialize_wrapped_key( wrapping_algorithm=wrapping_algorithm, wrapping_key_id=key_name, wrapped_encrypted_key=encrypted_data_key ) - # EncryptedData to raw key string - try: - plaintext_data_key = wrapping_key.decrypt( - encrypted_wrapped_data_key=encrypted_wrapped_key, encryption_context=decryption_materials.encryption_context - ) - - except Exception as error: # pylint: disable=broad-except - logger = logging.getLogger() - logger.error(error.__class__.__name__, ":", str(error)) - return decryption_materials - - if plaintext_data_key: - # Create a keyring trace - keyring_trace = KeyringTrace( - wrapping_key=key_provider, flags={KeyringTraceFlag.WRAPPING_KEY_DECRYPTED_DATA_KEY} - ) - - # Update decryption materials - data_encryption_key = RawDataKey( - key_provider=MasterKeyInfo(provider_id=key_provider.provider_id, key_info=key_name), - data_key=plaintext_data_key, - ) - decryption_materials.add_data_encryption_key(data_encryption_key, keyring_trace) - - return decryption_materials + return encrypted_wrapped_key @attr.s @@ -190,15 +125,14 @@ class RawAESKeyring(Keyring): :param str key_namespace: String defining the keyring. :param bytes key_name: Key ID - :param wrapping_key: Encryption key with which to wrap plaintext data key. - :type wrapping_key: WrappingKey + :param bytes wrapping_key: Encryption key with which to wrap plaintext data key. :param wrapping_algorithm: Wrapping Algorithm with which to wrap plaintext data key. :type wrapping_algorithm: WrappingAlgorithm """ key_namespace = attr.ib(validator=attr.validators.instance_of(six.string_types)) key_name = attr.ib(validator=attr.validators.instance_of(six.binary_type)) - _wrapping_key = attr.ib(repr=False, validator=attr.validators.instance_of(WrappingKey)) + _wrapping_key = attr.ib(repr=False, validator=attr.validators.instance_of(six.binary_type)) _wrapping_algorithm = attr.ib(repr=False, validator=attr.validators.instance_of(WrappingAlgorithm)) def __attrs_post_init__(self): @@ -206,46 +140,68 @@ def __attrs_post_init__(self): """Prepares initial values not handled by attrs.""" self._key_provider = MasterKeyInfo(provider_id=self.key_namespace, key_info=self.key_name) + self._wrapping_key_structure = WrappingKey( + wrapping_algorithm=self._wrapping_algorithm, + wrapping_key=self._wrapping_key, + wrapping_key_type=EncryptionKeyType.SYMMETRIC, + ) + self._key_info_prefix = get_key_info_prefix( - key_namespace=self.key_namespace, - key_name=self.key_name, - wrapping_key=WrappingKey( - wrapping_algorithm=self._wrapping_algorithm, - wrapping_key=self._wrapping_key, - wrapping_key_type=EncryptionKeyType.SYMMETRIC, - ), + key_namespace=self.key_namespace, key_name=self.key_name, wrapping_key=self._wrapping_key_structure ) def on_encrypt(self, encryption_materials): # type: (EncryptionMaterials) -> EncryptionMaterials - """Generate a data key if not present and encrypt it using any available wrapping key. + """Generate a data key if not present and encrypt it using any available wrapping key - :param encryption_materials: Encryption materials for the keyring to modify. + :param encryption_materials: Encryption materials for the keyring to modify :type encryption_materials: aws_encryption_sdk.materials_managers.EncryptionMaterials - :returns: Optionally modified encryption materials. + :returns: Optionally modified encryption materials :rtype: aws_encryption_sdk.materials_managers.EncryptionMaterials """ - encryption_materials = on_encrypt_helper( - encryption_materials=encryption_materials, + plaintext_data_key = on_encrypt_helper( + encryption_materials=encryption_materials, key_provider=self._key_provider + ) + + # Encrypt data key + encrypted_wrapped_key = self._wrapping_key_structure.encrypt( + plaintext_data_key=plaintext_data_key, encryption_context=encryption_materials.encryption_context + ) + + # EncryptedData to EncryptedDataKey + encrypted_data_key = serialize_wrapped_key( key_provider=self._key_provider, - wrapping_key=self._wrapping_key, wrapping_algorithm=self._wrapping_algorithm, - key_name=self.key_name, + wrapping_key_id=self.key_name, + encrypted_wrapped_key=encrypted_wrapped_key, ) + # Update Keyring Trace + if encrypted_data_key: + keyring_trace = KeyringTrace( + wrapping_key=encrypted_data_key.key_provider, flags={KeyringTraceFlag.WRAPPING_KEY_ENCRYPTED_DATA_KEY} + ) + + # Add encrypted data key to encryption_materials + encryption_materials.add_encrypted_data_key( + encrypted_data_key=encrypted_data_key, keyring_trace=keyring_trace + ) return encryption_materials def on_decrypt(self, decryption_materials, encrypted_data_keys): # type: (DecryptionMaterials, Iterable[EncryptedDataKey]) -> DecryptionMaterials """Attempt to decrypt the encrypted data keys. - :param decryption_materials: Decryption materials for the keyring to modify. + :param decryption_materials: Decryption materials for the keyring to modify :type decryption_materials: aws_encryption_sdk.materials_managers.DecryptionMaterials - :param encrypted_data_keys: List of encrypted data keys. + :param encrypted_data_keys: List of encrypted data keys :type: List of `aws_encryption_sdk.structures.EncryptedDataKey` - :returns: Optionally modified decryption materials. + :returns: Optionally modified decryption materials :rtype: aws_encryption_sdk.materials_managers.DecryptionMaterials """ + if decryption_materials.data_encryption_key: + return decryption_materials + # Decrypt data key expected_key_info_len = len(self._key_info_prefix) + self._wrapping_algorithm.algorithm.iv_len for key in encrypted_data_keys: @@ -254,14 +210,34 @@ def on_decrypt(self, decryption_materials, encrypted_data_keys): and len(key.key_provider.key_info) == expected_key_info_len and key.key_provider.key_info.startswith(self._key_info_prefix) ): - decryption_materials = on_decrypt_helper( - decryption_materials=decryption_materials, - key_provider=self._key_provider, - wrapping_key=self._wrapping_key, - wrapping_algorithm=self._wrapping_algorithm, - key_name=self.key_name, - encrypted_data_key=key, + encrypted_wrapped_key = on_decrypt_helper( + wrapping_algorithm=self._wrapping_algorithm, key_name=self.key_name, encrypted_data_key=key ) + # EncryptedData to raw key string + try: + plaintext_data_key = wrapping_key.decrypt( + encrypted_wrapped_data_key=encrypted_wrapped_key, + encryption_context=decryption_materials.encryption_context, + ) + + except Exception as error: # pylint: disable=broad-except + logger = logging.getLogger() + logger.error(error.__class__.__name__, ":", str(error)) + return decryption_materials + + if plaintext_data_key: + # Create a keyring trace + keyring_trace = KeyringTrace( + wrapping_key=key_provider, flags={KeyringTraceFlag.WRAPPING_KEY_DECRYPTED_DATA_KEY} + ) + + # Update decryption materials + data_encryption_key = RawDataKey( + key_provider=MasterKeyInfo(provider_id=key_provider.provider_id, key_info=key_name), + data_key=plaintext_data_key, + ) + decryption_materials.add_data_encryption_key(data_encryption_key, keyring_trace) + if decryption_materials.data_key: return decryption_materials @@ -275,7 +251,7 @@ class RawRSAKeyring(Keyring): :param str key_namespace: String defining the keyring ID :param bytes key_name: Key ID :param wrapping_key: Encryption key with which to wrap plaintext data key - :type wrapping_key: WrappingKey + :type wrapping_key: object :param wrapping_algorithm: Wrapping Algorithm with which to wrap plaintext data key :type wrapping_algorithm: WrappingAlgorithm :param key_provider: Complete information about the key in the keyring @@ -284,7 +260,7 @@ class RawRSAKeyring(Keyring): key_namespace = attr.ib(validator=attr.validators.instance_of(six.string_types)) key_name = attr.ib(validator=attr.validators.instance_of(six.binary_type)) - _wrapping_key = attr.ib(repr=False, validator=attr.validators.instance_of(WrappingKey)) + _wrapping_key = attr.ib(repr=False, validator=attr.validators.instance_of(object)) _wrapping_algorithm = attr.ib(repr=False, validator=attr.validators.instance_of(WrappingAlgorithm)) def __attrs_post_init__(self): @@ -301,13 +277,36 @@ def on_encrypt(self, encryption_materials): :returns: Optionally modified encryption materials. :rtype: aws_encryption_sdk.materials_managers.EncryptionMaterials """ - encryption_materials = on_encrypt_helper( - encryption_materials=encryption_materials, - key_provider=self._key_provider, - wrapping_key=self._wrapping_key, - wrapping_algorithm=self._wrapping_algorithm, - key_name=self.key_name, - ) + if isinstance(self._wrapping_key, RSAPublicKey): + + plaintext_data_key = on_encrypt_helper( + encryption_materials=encryption_materials, key_provider=self._key_provider + ) + + # Encrypt data key + encrypted_wrapped_key = EncryptedData( + iv=None, ciphertext=self._wrapping_key.encrypt(plaintext=plaintext_data_key, padding=OAEP), tag=None + ) + + # EncryptedData to EncryptedDataKey + encrypted_data_key = serialize_wrapped_key( + key_provider=key_provider, + wrapping_algorithm=wrapping_algorithm, + wrapping_key_id=key_name, + encrypted_wrapped_key=encrypted_wrapped_key, + ) + + # Update Keyring Trace + if encrypted_data_key: + keyring_trace = KeyringTrace( + wrapping_key=encrypted_data_key.key_provider, + flags={KeyringTraceFlag.WRAPPING_KEY_ENCRYPTED_DATA_KEY}, + ) + + # Add encrypted data key to encryption_materials + encryption_materials.add_encrypted_data_key( + encrypted_data_key=encrypted_data_key, keyring_trace=keyring_trace + ) return encryption_materials @@ -322,16 +321,33 @@ def on_decrypt(self, decryption_materials, encrypted_data_keys): :returns: Optionally modified decryption materials. :rtype: aws_encryption_sdk.materials_managers.DecryptionMaterials """ - # Decrypt data key - for key in encrypted_data_keys: - if key.key_provider == self._key_provider: - decryption_materials = on_decrypt_helper( - decryption_materials=decryption_materials, - key_provider=self._key_provider, - wrapping_key=self._wrapping_key, - wrapping_algorithm=self._wrapping_algorithm, - key_name=self.key_name, - encrypted_data_key=key, - ) + if isinstance(self._wrapping_key, RSAPrivateKey): + # Decrypt data key + for key in encrypted_data_keys: + if key.key_provider == self._key_provider: + encrypted_wrapped_key = on_decrypt_helper( + wrapping_algorithm=self._wrapping_algorithm, key_name=self.key_name, encrypted_data_key=key + ) + try: + plaintext_data_key = self._wrapping_key.decrypt( + ciphertext=encrypted_wrapped_key.ciphertext, padding=OAEP + ) + except Exception as error: # pylint: disable=broad-except + logger = logging.getLogger() + logger.error(error.__class__.__name__, ":", str(error)) + return decryption_materials + + if plaintext_data_key: + # Create a keyring trace + keyring_trace = KeyringTrace( + wrapping_key=key_provider, flags={KeyringTraceFlag.WRAPPING_KEY_DECRYPTED_DATA_KEY} + ) + + # Update decryption materials + data_encryption_key = RawDataKey( + key_provider=MasterKeyInfo(provider_id=key_provider.provider_id, key_info=key_name), + data_key=plaintext_data_key, + ) + decryption_materials.add_data_encryption_key(data_encryption_key, keyring_trace) return decryption_materials diff --git a/test/functional/test_f_multi_keyring.py b/test/functional/test_f_multi_keyring.py index 63cb62f8e..135cea8ac 100644 --- a/test/functional/test_f_multi_keyring.py +++ b/test/functional/test_f_multi_keyring.py @@ -13,6 +13,8 @@ """Functional tests for Multi keyring encryption decryption path.""" import pytest +from cryptography.hazmat.backends import default_backend +from cryptography.hazmat.primitives import serialization from aws_encryption_sdk.identifiers import Algorithm, EncryptionKeyType, KeyringTraceFlag, WrappingAlgorithm from aws_encryption_sdk.keyring.multi_keyring import MultiKeyring @@ -59,20 +61,20 @@ _WRAPPING_KEY_RSA2 = ( b"-----BEGIN RSA PRIVATE KEY-----" b"MIICXgIBAAKBgQCUjhI8YRPXV8Gfofbg/" - b"PLjWw2AzowQTPErLU2z3+xGqElMdzdiC4Ta43DFWZg34Eg0X8kQPAeoe8h3cRSMo" - b"77eSOHt2dPo7OfTfZqsH8766fivHIKVxBYPX8SZYIUhMtRnlg3uqch9BksfRop+h" - b"f8h/H3lfervJoevS2CXYB9/iwIDAQABAoGBAIqeGzQOHbaGI51yQ2zjez1dPDdiB" - b"F49fZideHEM1GuGIodgguRQ/VJGgncUSC5zcMy2SGaGrVqwznltohAtxy4rZp0eh" - b"2O3aHYi9Wehd0SPLh+qwu7mJDuh0z15hmCOue070FnUtyuSwhXLwDrbot2+5HbmF" - b"9clJLI5tv92gvIpAkEA+Bv5i8XJNPN1rao31aQFoi9bFIOEclk3b1RbLX6mpZBFS" - b"U9CNUy0RQNC0+H3KZ5CTvsyFGpMfTdiFc/Qdesk3QJBAJlHjrvoadP+PU3zXYrWR" - b"D5EryyTxaP1bOjrp9xLuQBeU8x7EVJdpoul9OmwcT3NrAqvxDE9okjha2tjCI6O2" - b"4cCQQDMyOJPYL/zaaPO5LlTKB/SPv4RT4BplYPw6xKa2XeZHhxiJv5B2f7NG6T0G" - b"AWWn16hrCoouZhKngTidfXc7motAkA/KiTgvKr3yHp86AAxWZDv1CAYD6FPqrDB3" - b"3LiLnZDd5uy1ThTJ/Kc87vUnXhdDqeKE9qWrB53SCWbMElzbd17AkEA4DMp+6ngM" - b"o6sS0dY1X6nTLqgvK3B0z5GCAdSEy3Y8jh995Lrl+hy88HzuwUkQwwPlZkFhUNCx" - b"edrC6cTKE5xLA==" - b"-----END RSA PRIVATE KEY-----" + b"PLjWw2AzowQTPErLU2z3+xGqElMdzdiC4Ta43DFWZg34Eg0X8kQPAeoe8h3cRSMo\n" + b"77eSOHt2dPo7OfTfZqsH8766fivHIKVxBYPX8SZYIUhMtRnlg3uqch9BksfRop+h\n" + b"f8h/H3lfervJoevS2CXYB9/iwIDAQABAoGBAIqeGzQOHbaGI51yQ2zjez1dPDdiB\n" + b"F49fZideHEM1GuGIodgguRQ/VJGgncUSC5zcMy2SGaGrVqwznltohAtxy4rZp0eh\n" + b"2O3aHYi9Wehd0SPLh+qwu7mJDuh0z15hmCOue070FnUtyuSwhXLwDrbot2+5HbmF\n" + b"9clJLI5tv92gvIpAkEA+Bv5i8XJNPN1rao31aQFoi9bFIOEclk3b1RbLX6mpZBFS\n" + b"U9CNUy0RQNC0+H3KZ5CTvsyFGpMfTdiFc/Qdesk3QJBAJlHjrvoadP+PU3zXYrWR\n" + b"D5EryyTxaP1bOjrp9xLuQBeU8x7EVJdpoul9OmwcT3NrAqvxDE9okjha2tjCI6O2\n" + b"4cCQQDMyOJPYL/zaaPO5LlTKB/SPv4RT4BplYPw6xKa2XeZHhxiJv5B2f7NG6T0G\n" + b"AWWn16hrCoouZhKngTidfXc7motAkA/KiTgvKr3yHp86AAxWZDv1CAYD6FPqrDB3\n" + b"3LiLnZDd5uy1ThTJ/Kc87vUnXhdDqeKE9qWrB53SCWbMElzbd17AkEA4DMp+6ngM\n" + b"o6sS0dY1X6nTLqgvK3B0z5GCAdSEy3Y8jh995Lrl+hy88HzuwUkQwwPlZkFhUNCx\n" + b"edrC6cTKE5xLA==\n" + b"-----END RSA PRIVATE KEY-----\n" ) _SIGNING_KEY = b"aws-crypto-public-key" @@ -130,31 +132,23 @@ key_namespace=_PROVIDER_ID, key_name=_KEY_ID, wrapping_algorithm=WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING, - wrapping_key=WrappingKey( - wrapping_algorithm=WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING, - wrapping_key=_WRAPPING_KEY_AES, - wrapping_key_type=EncryptionKeyType.SYMMETRIC, - ), + wrapping_key=_WRAPPING_KEY_AES ), children=[ RawRSAKeyring( key_namespace=_PROVIDER_ID, key_name=_KEY_ID, wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, - wrapping_key=WrappingKey( - wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, - wrapping_key=_WRAPPING_KEY_RSA1, - wrapping_key_type=EncryptionKeyType.PRIVATE, + wrapping_key=serialization.load_pem_private_key( + data=_WRAPPING_KEY_RSA1, password=None, backend=default_backend() ), ), RawRSAKeyring( key_namespace=_PROVIDER_ID, key_name=_KEY_ID, wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, - wrapping_key=WrappingKey( - wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, - wrapping_key=_WRAPPING_KEY_RSA1, - wrapping_key_type=EncryptionKeyType.PRIVATE, + wrapping_key=serialization.load_pem_private_key( + data=_WRAPPING_KEY_RSA2, password=None, backend=default_backend() ), ), ], @@ -164,10 +158,8 @@ key_namespace=_PROVIDER_ID, key_name=_KEY_ID, wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, - wrapping_key=WrappingKey( - wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, - wrapping_key=_WRAPPING_KEY_RSA1, - wrapping_key_type=EncryptionKeyType.PRIVATE, + wrapping_key=serialization.load_pem_private_key( + data=_WRAPPING_KEY_RSA1, password=None, backend=default_backend() ), ) ), @@ -177,21 +169,15 @@ key_namespace=_PROVIDER_ID, key_name=_KEY_ID, wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, - wrapping_key=WrappingKey( - wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, - wrapping_key=_WRAPPING_KEY_RSA1, - wrapping_key_type=EncryptionKeyType.PRIVATE, + wrapping_key=serialization.load_pem_private_key( + data=_WRAPPING_KEY_RSA1, password=None, backend=default_backend() ), ), RawAESKeyring( key_namespace=_PROVIDER_ID, key_name=_KEY_ID, wrapping_algorithm=WrappingAlgorithm.AES_128_GCM_IV12_TAG16_NO_PADDING, - wrapping_key=WrappingKey( - wrapping_algorithm=WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING, - wrapping_key=_WRAPPING_KEY_AES, - wrapping_key_type=EncryptionKeyType.SYMMETRIC, - ), + wrapping_key=_WRAPPING_KEY_AES ), ] ), From b4a34d707d9543e0832f28c477b98dc81e88ba6d Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Wed, 17 Jul 2019 22:48:53 -0700 Subject: [PATCH 40/61] Changed RSA key structure to RSAPublicKey/RSAPrivateKey and functional test passes --- .../keyring/multi_keyring.py | 9 +- src/aws_encryption_sdk/keyring/raw_keyring.py | 7 +- test/functional/test_f_multi_keyring.py | 122 +++++++++--------- 3 files changed, 66 insertions(+), 72 deletions(-) diff --git a/src/aws_encryption_sdk/keyring/multi_keyring.py b/src/aws_encryption_sdk/keyring/multi_keyring.py index 039e83389..54b36d641 100644 --- a/src/aws_encryption_sdk/keyring/multi_keyring.py +++ b/src/aws_encryption_sdk/keyring/multi_keyring.py @@ -102,9 +102,10 @@ def on_decrypt(self, decryption_materials, encrypted_data_keys): return decryption_materials # Call on_decrypt on all keyrings till decryption is successful - for keyring in self.children: - decryption_materials = keyring.on_decrypt(decryption_materials, encrypted_data_keys) - if decryption_materials.data_encryption_key: - return decryption_materials + if self.children is not None: + for keyring in self.children: + decryption_materials = keyring.on_decrypt(decryption_materials, encrypted_data_keys) + if decryption_materials.data_encryption_key: + return decryption_materials return decryption_materials diff --git a/src/aws_encryption_sdk/keyring/raw_keyring.py b/src/aws_encryption_sdk/keyring/raw_keyring.py index 93d6fd080..f3c7de88a 100644 --- a/src/aws_encryption_sdk/keyring/raw_keyring.py +++ b/src/aws_encryption_sdk/keyring/raw_keyring.py @@ -277,12 +277,11 @@ def on_encrypt(self, encryption_materials): :returns: Optionally modified encryption materials. :rtype: aws_encryption_sdk.materials_managers.EncryptionMaterials """ + plaintext_data_key = on_encrypt_helper( + encryption_materials=encryption_materials, key_provider=self._key_provider + ) if isinstance(self._wrapping_key, RSAPublicKey): - plaintext_data_key = on_encrypt_helper( - encryption_materials=encryption_materials, key_provider=self._key_provider - ) - # Encrypt data key encrypted_wrapped_key = EncryptedData( iv=None, ciphertext=self._wrapping_key.encrypt(plaintext=plaintext_data_key, padding=OAEP), tag=None diff --git a/test/functional/test_f_multi_keyring.py b/test/functional/test_f_multi_keyring.py index 135cea8ac..4ff611bf4 100644 --- a/test/functional/test_f_multi_keyring.py +++ b/test/functional/test_f_multi_keyring.py @@ -14,11 +14,11 @@ import pytest from cryptography.hazmat.backends import default_backend -from cryptography.hazmat.primitives import serialization +from cryptography.hazmat.primitives.asymmetric import rsa -from aws_encryption_sdk.identifiers import Algorithm, EncryptionKeyType, KeyringTraceFlag, WrappingAlgorithm +from aws_encryption_sdk.identifiers import Algorithm, KeyringTraceFlag, WrappingAlgorithm from aws_encryption_sdk.keyring.multi_keyring import MultiKeyring -from aws_encryption_sdk.keyring.raw_keyring import RawAESKeyring, RawRSAKeyring, WrappingKey +from aws_encryption_sdk.keyring.raw_keyring import RawAESKeyring, RawRSAKeyring from aws_encryption_sdk.materials_managers import DecryptionMaterials, EncryptionMaterials from aws_encryption_sdk.structures import EncryptedDataKey, KeyringTrace, MasterKeyInfo, RawDataKey @@ -29,53 +29,55 @@ _KEY_ID = b"5325b043-5843-4629-869c-64794af77ada" _WRAPPING_KEY_AES = b"\xeby-\x80A6\x15rA8\x83#,\xe4\xab\xac`\xaf\x99Z\xc1\xce\xdb\xb6\x0f\xb7\x805\xb2\x14J3" -_WRAPPING_KEY_RSA1 = ( - b"-----BEGIN RSA PRIVATE KEY-----\n" - b"MIIEowIBAAKCAQEAo8uCyhiO4JUGZV+rtNq5DBA9Lm4xkw5kTA3v6EPybs8bVXL2\n" - b"ZE6jkbo+xT4Jg/bKzUpnp1fE+T1ruGPtsPdoEmhY/P64LDNIs3sRq5U4QV9IETU1\n" - b"vIcbNNkgGhRjV8J87YNY0tV0H7tuWuZRpqnS+gjV6V9lUMkbvjMCc5IBqQc3heut\n" - b"/+fH4JwpGlGxOVXI8QAapnSy1XpCr3+PT29kydVJnIMuAoFrurojRpOQbOuVvhtA\n" - b"gARhst1Ji4nfROGYkj6eZhvkz2Bkud4/+3lGvVU5LO1vD8oY7WoGtpin3h50VcWe\n" - b"aBT4kejx4s9/G9C4R24lTH09J9HO2UUsuCqZYQIDAQABAoIBAQCfC90bCk+qaWqF\n" - b"gymC+qOWwCn4bM28gswHQb1D5r6AtKBRD8mKywVvWs7azguFVV3Fi8sspkBA2FBC\n" - b"At5p6ULoJOTL/TauzLl6djVJTCMM701WUDm2r+ZOIctXJ5bzP4n5Q4I7b0NMEL7u\n" - b"ixib4elYGr5D1vrVQAKtZHCr8gmkqyx8Mz7wkJepzBP9EeVzETCHsmiQDd5WYlO1\n" - b"C2IQYgw6MJzgM4entJ0V/GPytkodblGY95ORVK7ZhyNtda+r5BZ6/jeMW+hA3VoK\n" - b"tHSWjHt06ueVCCieZIATmYzBNt+zEz5UA2l7ksg3eWfVORJQS7a6Ef4VvbJLM9Ca\n" - b"m1kdsjelAoGBANKgvRf39i3bSuvm5VoyJuqinSb/23IH3Zo7XOZ5G164vh49E9Cq\n" - b"dOXXVxox74ppj/kbGUoOk+AvaB48zzfzNvac0a7lRHExykPH2kVrI/NwH/1OcT/x\n" - b"2e2DnFYocXcb4gbdZQ+m6X3zkxOYcONRzPVW1uMrFTWHcJveMUm4PGx7AoGBAMcU\n" - b"IRvrT6ye5se0s27gHnPweV+3xjsNtXZcK82N7duXyHmNjxrwOAv0SOhUmTkRXArM\n" - b"6aN5D8vyZBSWma2TgUKwpQYFTI+4Sp7sdkkyojGAEixJ+c5TZJNxZFrUe0FwAoic\n" - b"c2kb7ntaiEj5G+qHvykJJro5hy6uLnjiMVbAiJDTAoGAKb67241EmHAXGEwp9sdr\n" - b"2SMjnIAnQSF39UKAthkYqJxa6elXDQtLoeYdGE7/V+J2K3wIdhoPiuY6b4vD0iX9\n" - b"JcGM+WntN7YTjX2FsC588JmvbWfnoDHR7HYiPR1E58N597xXdFOzgUgORVr4PMWQ\n" - b"pqtwaZO3X2WZlvrhr+e46hMCgYBfdIdrm6jYXFjL6RkgUNZJQUTxYGzsY+ZemlNm\n" - b"fGdQo7a8kePMRuKY2MkcnXPaqTg49YgRmjq4z8CtHokRcWjJUWnPOTs8rmEZUshk\n" - b"0KJ0mbQdCFt/Uv0mtXgpFTkEZ3DPkDTGcV4oR4CRfOCl0/EU/A5VvL/U4i/mRo7h\n" - b"ye+xgQKBgD58b+9z+PR5LAJm1tZHIwb4tnyczP28PzwknxFd2qylR4ZNgvAUqGtU\n" - b"xvpUDpzMioz6zUH9YV43YNtt+5Xnzkqj+u9Mr27/H2v9XPwORGfwQ5XPwRJz/2oC\n" - b"EnPmP1SZoY9lXKUpQXHXSpDZ2rE2Klt3RHMUMHt8Zpy36E8Vwx8o\n" - b"-----END RSA PRIVATE KEY-----\n" -) -_WRAPPING_KEY_RSA2 = ( - b"-----BEGIN RSA PRIVATE KEY-----" - b"MIICXgIBAAKBgQCUjhI8YRPXV8Gfofbg/" - b"PLjWw2AzowQTPErLU2z3+xGqElMdzdiC4Ta43DFWZg34Eg0X8kQPAeoe8h3cRSMo\n" - b"77eSOHt2dPo7OfTfZqsH8766fivHIKVxBYPX8SZYIUhMtRnlg3uqch9BksfRop+h\n" - b"f8h/H3lfervJoevS2CXYB9/iwIDAQABAoGBAIqeGzQOHbaGI51yQ2zjez1dPDdiB\n" - b"F49fZideHEM1GuGIodgguRQ/VJGgncUSC5zcMy2SGaGrVqwznltohAtxy4rZp0eh\n" - b"2O3aHYi9Wehd0SPLh+qwu7mJDuh0z15hmCOue070FnUtyuSwhXLwDrbot2+5HbmF\n" - b"9clJLI5tv92gvIpAkEA+Bv5i8XJNPN1rao31aQFoi9bFIOEclk3b1RbLX6mpZBFS\n" - b"U9CNUy0RQNC0+H3KZ5CTvsyFGpMfTdiFc/Qdesk3QJBAJlHjrvoadP+PU3zXYrWR\n" - b"D5EryyTxaP1bOjrp9xLuQBeU8x7EVJdpoul9OmwcT3NrAqvxDE9okjha2tjCI6O2\n" - b"4cCQQDMyOJPYL/zaaPO5LlTKB/SPv4RT4BplYPw6xKa2XeZHhxiJv5B2f7NG6T0G\n" - b"AWWn16hrCoouZhKngTidfXc7motAkA/KiTgvKr3yHp86AAxWZDv1CAYD6FPqrDB3\n" - b"3LiLnZDd5uy1ThTJ/Kc87vUnXhdDqeKE9qWrB53SCWbMElzbd17AkEA4DMp+6ngM\n" - b"o6sS0dY1X6nTLqgvK3B0z5GCAdSEy3Y8jh995Lrl+hy88HzuwUkQwwPlZkFhUNCx\n" - b"edrC6cTKE5xLA==\n" - b"-----END RSA PRIVATE KEY-----\n" -) +# _WRAPPING_KEY_RSA1 = ( +# b"-----BEGIN RSA PRIVATE KEY-----\n" +# b"MIIEowIBAAKCAQEAo8uCyhiO4JUGZV+rtNq5DBA9Lm4xkw5kTA3v6EPybs8bVXL2\n" +# b"ZE6jkbo+xT4Jg/bKzUpnp1fE+T1ruGPtsPdoEmhY/P64LDNIs3sRq5U4QV9IETU1\n" +# b"vIcbNNkgGhRjV8J87YNY0tV0H7tuWuZRpqnS+gjV6V9lUMkbvjMCc5IBqQc3heut\n" +# b"/+fH4JwpGlGxOVXI8QAapnSy1XpCr3+PT29kydVJnIMuAoFrurojRpOQbOuVvhtA\n" +# b"gARhst1Ji4nfROGYkj6eZhvkz2Bkud4/+3lGvVU5LO1vD8oY7WoGtpin3h50VcWe\n" +# b"aBT4kejx4s9/G9C4R24lTH09J9HO2UUsuCqZYQIDAQABAoIBAQCfC90bCk+qaWqF\n" +# b"gymC+qOWwCn4bM28gswHQb1D5r6AtKBRD8mKywVvWs7azguFVV3Fi8sspkBA2FBC\n" +# b"At5p6ULoJOTL/TauzLl6djVJTCMM701WUDm2r+ZOIctXJ5bzP4n5Q4I7b0NMEL7u\n" +# b"ixib4elYGr5D1vrVQAKtZHCr8gmkqyx8Mz7wkJepzBP9EeVzETCHsmiQDd5WYlO1\n" +# b"C2IQYgw6MJzgM4entJ0V/GPytkodblGY95ORVK7ZhyNtda+r5BZ6/jeMW+hA3VoK\n" +# b"tHSWjHt06ueVCCieZIATmYzBNt+zEz5UA2l7ksg3eWfVORJQS7a6Ef4VvbJLM9Ca\n" +# b"m1kdsjelAoGBANKgvRf39i3bSuvm5VoyJuqinSb/23IH3Zo7XOZ5G164vh49E9Cq\n" +# b"dOXXVxox74ppj/kbGUoOk+AvaB48zzfzNvac0a7lRHExykPH2kVrI/NwH/1OcT/x\n" +# b"2e2DnFYocXcb4gbdZQ+m6X3zkxOYcONRzPVW1uMrFTWHcJveMUm4PGx7AoGBAMcU\n" +# b"IRvrT6ye5se0s27gHnPweV+3xjsNtXZcK82N7duXyHmNjxrwOAv0SOhUmTkRXArM\n" +# b"6aN5D8vyZBSWma2TgUKwpQYFTI+4Sp7sdkkyojGAEixJ+c5TZJNxZFrUe0FwAoic\n" +# b"c2kb7ntaiEj5G+qHvykJJro5hy6uLnjiMVbAiJDTAoGAKb67241EmHAXGEwp9sdr\n" +# b"2SMjnIAnQSF39UKAthkYqJxa6elXDQtLoeYdGE7/V+J2K3wIdhoPiuY6b4vD0iX9\n" +# b"JcGM+WntN7YTjX2FsC588JmvbWfnoDHR7HYiPR1E58N597xXdFOzgUgORVr4PMWQ\n" +# b"pqtwaZO3X2WZlvrhr+e46hMCgYBfdIdrm6jYXFjL6RkgUNZJQUTxYGzsY+ZemlNm\n" +# b"fGdQo7a8kePMRuKY2MkcnXPaqTg49YgRmjq4z8CtHokRcWjJUWnPOTs8rmEZUshk\n" +# b"0KJ0mbQdCFt/Uv0mtXgpFTkEZ3DPkDTGcV4oR4CRfOCl0/EU/A5VvL/U4i/mRo7h\n" +# b"ye+xgQKBgD58b+9z+PR5LAJm1tZHIwb4tnyczP28PzwknxFd2qylR4ZNgvAUqGtU\n" +# b"xvpUDpzMioz6zUH9YV43YNtt+5Xnzkqj+u9Mr27/H2v9XPwORGfwQ5XPwRJz/2oC\n" +# b"EnPmP1SZoY9lXKUpQXHXSpDZ2rE2Klt3RHMUMHt8Zpy36E8Vwx8o\n" +# b"-----END RSA PRIVATE KEY-----\n" +# ) +# +# _WRAPPING_KEY_RSA2 = ( +# b"-----BEGIN RSA PRIVATE KEY-----" +# b"MIICXgIBAAKBgQCUjhI8YRPXV8Gfofbg/" +# b"PLjWw2AzowQTPErLU2z3+xGqElMdzdiC4Ta43DFWZg34Eg0X8kQPAeoe8h3cRSMo\n" +# b"77eSOHt2dPo7OfTfZqsH8766fivHIKVxBYPX8SZYIUhMtRnlg3uqch9BksfRop+h\n" +# b"f8h/H3lfervJoevS2CXYB9/iwIDAQABAoGBAIqeGzQOHbaGI51yQ2zjez1dPDdiB\n" +# b"F49fZideHEM1GuGIodgguRQ/VJGgncUSC5zcMy2SGaGrVqwznltohAtxy4rZp0eh\n" +# b"2O3aHYi9Wehd0SPLh+qwu7mJDuh0z15hmCOue070FnUtyuSwhXLwDrbot2+5HbmF\n" +# b"9clJLI5tv92gvIpAkEA+Bv5i8XJNPN1rao31aQFoi9bFIOEclk3b1RbLX6mpZBFS\n" +# b"U9CNUy0RQNC0+H3KZ5CTvsyFGpMfTdiFc/Qdesk3QJBAJlHjrvoadP+PU3zXYrWR\n" +# b"D5EryyTxaP1bOjrp9xLuQBeU8x7EVJdpoul9OmwcT3NrAqvxDE9okjha2tjCI6O2\n" +# b"4cCQQDMyOJPYL/zaaPO5LlTKB/SPv4RT4BplYPw6xKa2XeZHhxiJv5B2f7NG6T0G\n" +# b"AWWn16hrCoouZhKngTidfXc7motAkA/KiTgvKr3yHp86AAxWZDv1CAYD6FPqrDB3\n" +# b"3LiLnZDd5uy1ThTJ/Kc87vUnXhdDqeKE9qWrB53SCWbMElzbd17AkEA4DMp+6ngM\n" +# b"o6sS0dY1X6nTLqgvK3B0z5GCAdSEy3Y8jh995Lrl+hy88HzuwUkQwwPlZkFhUNCx\n" +# b"edrC6cTKE5xLA==\n" +# b"-----END RSA PRIVATE KEY-----\n" +# ) + _SIGNING_KEY = b"aws-crypto-public-key" _ENCRYPTION_MATERIALS = [ @@ -132,24 +134,20 @@ key_namespace=_PROVIDER_ID, key_name=_KEY_ID, wrapping_algorithm=WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING, - wrapping_key=_WRAPPING_KEY_AES + wrapping_key=_WRAPPING_KEY_AES, ), children=[ RawRSAKeyring( key_namespace=_PROVIDER_ID, key_name=_KEY_ID, wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, - wrapping_key=serialization.load_pem_private_key( - data=_WRAPPING_KEY_RSA1, password=None, backend=default_backend() - ), + wrapping_key=rsa.generate_private_key(public_exponent=65537, key_size=2048, backend=default_backend()), ), RawRSAKeyring( key_namespace=_PROVIDER_ID, key_name=_KEY_ID, wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, - wrapping_key=serialization.load_pem_private_key( - data=_WRAPPING_KEY_RSA2, password=None, backend=default_backend() - ), + wrapping_key=rsa.generate_private_key(public_exponent=65537, key_size=2048, backend=default_backend()), ), ], ), @@ -158,9 +156,7 @@ key_namespace=_PROVIDER_ID, key_name=_KEY_ID, wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, - wrapping_key=serialization.load_pem_private_key( - data=_WRAPPING_KEY_RSA1, password=None, backend=default_backend() - ), + wrapping_key=rsa.generate_private_key(public_exponent=65537, key_size=2048, backend=default_backend()), ) ), MultiKeyring( @@ -169,15 +165,13 @@ key_namespace=_PROVIDER_ID, key_name=_KEY_ID, wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, - wrapping_key=serialization.load_pem_private_key( - data=_WRAPPING_KEY_RSA1, password=None, backend=default_backend() - ), + wrapping_key=rsa.generate_private_key(public_exponent=65537, key_size=2048, backend=default_backend()), ), RawAESKeyring( key_namespace=_PROVIDER_ID, key_name=_KEY_ID, wrapping_algorithm=WrappingAlgorithm.AES_128_GCM_IV12_TAG16_NO_PADDING, - wrapping_key=_WRAPPING_KEY_AES + wrapping_key=_WRAPPING_KEY_AES, ), ] ), From caf799e7774bbf377a96b45d29fbde303659eb12 Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Wed, 17 Jul 2019 22:51:08 -0700 Subject: [PATCH 41/61] Removed unwanted commented lines from test --- test/functional/test_f_multi_keyring.py | 49 ------------------------- 1 file changed, 49 deletions(-) diff --git a/test/functional/test_f_multi_keyring.py b/test/functional/test_f_multi_keyring.py index 4ff611bf4..ab1e0c25f 100644 --- a/test/functional/test_f_multi_keyring.py +++ b/test/functional/test_f_multi_keyring.py @@ -29,55 +29,6 @@ _KEY_ID = b"5325b043-5843-4629-869c-64794af77ada" _WRAPPING_KEY_AES = b"\xeby-\x80A6\x15rA8\x83#,\xe4\xab\xac`\xaf\x99Z\xc1\xce\xdb\xb6\x0f\xb7\x805\xb2\x14J3" -# _WRAPPING_KEY_RSA1 = ( -# b"-----BEGIN RSA PRIVATE KEY-----\n" -# b"MIIEowIBAAKCAQEAo8uCyhiO4JUGZV+rtNq5DBA9Lm4xkw5kTA3v6EPybs8bVXL2\n" -# b"ZE6jkbo+xT4Jg/bKzUpnp1fE+T1ruGPtsPdoEmhY/P64LDNIs3sRq5U4QV9IETU1\n" -# b"vIcbNNkgGhRjV8J87YNY0tV0H7tuWuZRpqnS+gjV6V9lUMkbvjMCc5IBqQc3heut\n" -# b"/+fH4JwpGlGxOVXI8QAapnSy1XpCr3+PT29kydVJnIMuAoFrurojRpOQbOuVvhtA\n" -# b"gARhst1Ji4nfROGYkj6eZhvkz2Bkud4/+3lGvVU5LO1vD8oY7WoGtpin3h50VcWe\n" -# b"aBT4kejx4s9/G9C4R24lTH09J9HO2UUsuCqZYQIDAQABAoIBAQCfC90bCk+qaWqF\n" -# b"gymC+qOWwCn4bM28gswHQb1D5r6AtKBRD8mKywVvWs7azguFVV3Fi8sspkBA2FBC\n" -# b"At5p6ULoJOTL/TauzLl6djVJTCMM701WUDm2r+ZOIctXJ5bzP4n5Q4I7b0NMEL7u\n" -# b"ixib4elYGr5D1vrVQAKtZHCr8gmkqyx8Mz7wkJepzBP9EeVzETCHsmiQDd5WYlO1\n" -# b"C2IQYgw6MJzgM4entJ0V/GPytkodblGY95ORVK7ZhyNtda+r5BZ6/jeMW+hA3VoK\n" -# b"tHSWjHt06ueVCCieZIATmYzBNt+zEz5UA2l7ksg3eWfVORJQS7a6Ef4VvbJLM9Ca\n" -# b"m1kdsjelAoGBANKgvRf39i3bSuvm5VoyJuqinSb/23IH3Zo7XOZ5G164vh49E9Cq\n" -# b"dOXXVxox74ppj/kbGUoOk+AvaB48zzfzNvac0a7lRHExykPH2kVrI/NwH/1OcT/x\n" -# b"2e2DnFYocXcb4gbdZQ+m6X3zkxOYcONRzPVW1uMrFTWHcJveMUm4PGx7AoGBAMcU\n" -# b"IRvrT6ye5se0s27gHnPweV+3xjsNtXZcK82N7duXyHmNjxrwOAv0SOhUmTkRXArM\n" -# b"6aN5D8vyZBSWma2TgUKwpQYFTI+4Sp7sdkkyojGAEixJ+c5TZJNxZFrUe0FwAoic\n" -# b"c2kb7ntaiEj5G+qHvykJJro5hy6uLnjiMVbAiJDTAoGAKb67241EmHAXGEwp9sdr\n" -# b"2SMjnIAnQSF39UKAthkYqJxa6elXDQtLoeYdGE7/V+J2K3wIdhoPiuY6b4vD0iX9\n" -# b"JcGM+WntN7YTjX2FsC588JmvbWfnoDHR7HYiPR1E58N597xXdFOzgUgORVr4PMWQ\n" -# b"pqtwaZO3X2WZlvrhr+e46hMCgYBfdIdrm6jYXFjL6RkgUNZJQUTxYGzsY+ZemlNm\n" -# b"fGdQo7a8kePMRuKY2MkcnXPaqTg49YgRmjq4z8CtHokRcWjJUWnPOTs8rmEZUshk\n" -# b"0KJ0mbQdCFt/Uv0mtXgpFTkEZ3DPkDTGcV4oR4CRfOCl0/EU/A5VvL/U4i/mRo7h\n" -# b"ye+xgQKBgD58b+9z+PR5LAJm1tZHIwb4tnyczP28PzwknxFd2qylR4ZNgvAUqGtU\n" -# b"xvpUDpzMioz6zUH9YV43YNtt+5Xnzkqj+u9Mr27/H2v9XPwORGfwQ5XPwRJz/2oC\n" -# b"EnPmP1SZoY9lXKUpQXHXSpDZ2rE2Klt3RHMUMHt8Zpy36E8Vwx8o\n" -# b"-----END RSA PRIVATE KEY-----\n" -# ) -# -# _WRAPPING_KEY_RSA2 = ( -# b"-----BEGIN RSA PRIVATE KEY-----" -# b"MIICXgIBAAKBgQCUjhI8YRPXV8Gfofbg/" -# b"PLjWw2AzowQTPErLU2z3+xGqElMdzdiC4Ta43DFWZg34Eg0X8kQPAeoe8h3cRSMo\n" -# b"77eSOHt2dPo7OfTfZqsH8766fivHIKVxBYPX8SZYIUhMtRnlg3uqch9BksfRop+h\n" -# b"f8h/H3lfervJoevS2CXYB9/iwIDAQABAoGBAIqeGzQOHbaGI51yQ2zjez1dPDdiB\n" -# b"F49fZideHEM1GuGIodgguRQ/VJGgncUSC5zcMy2SGaGrVqwznltohAtxy4rZp0eh\n" -# b"2O3aHYi9Wehd0SPLh+qwu7mJDuh0z15hmCOue070FnUtyuSwhXLwDrbot2+5HbmF\n" -# b"9clJLI5tv92gvIpAkEA+Bv5i8XJNPN1rao31aQFoi9bFIOEclk3b1RbLX6mpZBFS\n" -# b"U9CNUy0RQNC0+H3KZ5CTvsyFGpMfTdiFc/Qdesk3QJBAJlHjrvoadP+PU3zXYrWR\n" -# b"D5EryyTxaP1bOjrp9xLuQBeU8x7EVJdpoul9OmwcT3NrAqvxDE9okjha2tjCI6O2\n" -# b"4cCQQDMyOJPYL/zaaPO5LlTKB/SPv4RT4BplYPw6xKa2XeZHhxiJv5B2f7NG6T0G\n" -# b"AWWn16hrCoouZhKngTidfXc7motAkA/KiTgvKr3yHp86AAxWZDv1CAYD6FPqrDB3\n" -# b"3LiLnZDd5uy1ThTJ/Kc87vUnXhdDqeKE9qWrB53SCWbMElzbd17AkEA4DMp+6ngM\n" -# b"o6sS0dY1X6nTLqgvK3B0z5GCAdSEy3Y8jh995Lrl+hy88HzuwUkQwwPlZkFhUNCx\n" -# b"edrC6cTKE5xLA==\n" -# b"-----END RSA PRIVATE KEY-----\n" -# ) - _SIGNING_KEY = b"aws-crypto-public-key" _ENCRYPTION_MATERIALS = [ From b93d4ed9889693d19c049351cc8f0b00fa7a5aec Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Wed, 17 Jul 2019 23:14:00 -0700 Subject: [PATCH 42/61] Pylint errors --- src/aws_encryption_sdk/keyring/raw_keyring.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/aws_encryption_sdk/keyring/raw_keyring.py b/src/aws_encryption_sdk/keyring/raw_keyring.py index f3c7de88a..0288a3a23 100644 --- a/src/aws_encryption_sdk/keyring/raw_keyring.py +++ b/src/aws_encryption_sdk/keyring/raw_keyring.py @@ -110,7 +110,6 @@ def on_decrypt_helper( :return encrypted_wrapped_key: Encrypted, wrapped, data key :rtype encrypted_wrapped_key: EncryptedData """ - # Wrapped EncryptedDataKey to deserialized EncryptedData encrypted_wrapped_key = deserialize_wrapped_key( wrapping_algorithm=wrapping_algorithm, wrapping_key_id=key_name, wrapped_encrypted_key=encrypted_data_key @@ -215,7 +214,7 @@ def on_decrypt(self, decryption_materials, encrypted_data_keys): ) # EncryptedData to raw key string try: - plaintext_data_key = wrapping_key.decrypt( + plaintext_data_key = self._wrapping_key_structure.decrypt( encrypted_wrapped_data_key=encrypted_wrapped_key, encryption_context=decryption_materials.encryption_context, ) @@ -228,12 +227,12 @@ def on_decrypt(self, decryption_materials, encrypted_data_keys): if plaintext_data_key: # Create a keyring trace keyring_trace = KeyringTrace( - wrapping_key=key_provider, flags={KeyringTraceFlag.WRAPPING_KEY_DECRYPTED_DATA_KEY} + wrapping_key=self._key_provider, flags={KeyringTraceFlag.WRAPPING_KEY_DECRYPTED_DATA_KEY} ) # Update decryption materials data_encryption_key = RawDataKey( - key_provider=MasterKeyInfo(provider_id=key_provider.provider_id, key_info=key_name), + key_provider=MasterKeyInfo(provider_id=self._key_provider.provider_id, key_info=self.key_name), data_key=plaintext_data_key, ) decryption_materials.add_data_encryption_key(data_encryption_key, keyring_trace) From aa9145fa4f3bff9e9725371e6f87e40ce246c9d9 Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Wed, 17 Jul 2019 23:25:57 -0700 Subject: [PATCH 43/61] More pylint errors --- src/aws_encryption_sdk/keyring/raw_keyring.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/aws_encryption_sdk/keyring/raw_keyring.py b/src/aws_encryption_sdk/keyring/raw_keyring.py index 0288a3a23..f50d96618 100644 --- a/src/aws_encryption_sdk/keyring/raw_keyring.py +++ b/src/aws_encryption_sdk/keyring/raw_keyring.py @@ -288,9 +288,9 @@ def on_encrypt(self, encryption_materials): # EncryptedData to EncryptedDataKey encrypted_data_key = serialize_wrapped_key( - key_provider=key_provider, - wrapping_algorithm=wrapping_algorithm, - wrapping_key_id=key_name, + key_provider=self._key_provider, + wrapping_algorithm=self._wrapping_algorithm, + wrapping_key_id=self._key_name, encrypted_wrapped_key=encrypted_wrapped_key, ) @@ -338,12 +338,14 @@ def on_decrypt(self, decryption_materials, encrypted_data_keys): if plaintext_data_key: # Create a keyring trace keyring_trace = KeyringTrace( - wrapping_key=key_provider, flags={KeyringTraceFlag.WRAPPING_KEY_DECRYPTED_DATA_KEY} + wrapping_key=self._key_provider, flags={KeyringTraceFlag.WRAPPING_KEY_DECRYPTED_DATA_KEY} ) # Update decryption materials data_encryption_key = RawDataKey( - key_provider=MasterKeyInfo(provider_id=key_provider.provider_id, key_info=key_name), + key_provider=MasterKeyInfo( + provider_id=self._key_provider.provider_id, key_info=self.key_name + ), data_key=plaintext_data_key, ) decryption_materials.add_data_encryption_key(data_encryption_key, keyring_trace) From 7645d79cff0c1e55b2ddc1b8a7830350464b5ebc Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Thu, 18 Jul 2019 18:54:35 -0700 Subject: [PATCH 44/61] Made suggested changes in multi keyring --- .../keyring/multi_keyring.py | 34 ++++++++----------- test/unit/test_multi_keyrings.py | 0 2 files changed, 15 insertions(+), 19 deletions(-) create mode 100644 test/unit/test_multi_keyrings.py diff --git a/src/aws_encryption_sdk/keyring/multi_keyring.py b/src/aws_encryption_sdk/keyring/multi_keyring.py index 54b36d641..12756eb62 100644 --- a/src/aws_encryption_sdk/keyring/multi_keyring.py +++ b/src/aws_encryption_sdk/keyring/multi_keyring.py @@ -11,10 +11,12 @@ # ANY KIND, either express or implied. See the License for the specific # language governing permissions and limitations under the License. """Resources required for Multi Keyrings.""" +import itertools + import attr from attr.validators import deep_iterable, instance_of, optional -from aws_encryption_sdk.exceptions import EncryptKeyError +from aws_encryption_sdk.exceptions import EncryptKeyError, GenerateKeyError from aws_encryption_sdk.keyring.base import DecryptionMaterials, EncryptedDataKey, EncryptionMaterials, Keyring try: # Python 3.5.0 and 3.5.1 have incompatible typing modules @@ -35,17 +37,19 @@ class MultiKeyring(Keyring): """ children = attr.ib( - default=None, - validator=optional(deep_iterable(member_validator=instance_of(Keyring), iterable_validator=instance_of(list))), + default=attr.Factory(tuple), validator=optional(deep_iterable(member_validator=instance_of(Keyring))) ) generator = attr.ib(default=None, validator=optional(instance_of(Keyring))) def __attrs_post_init__(self): # type: () -> None """Prepares initial values not handled by attrs.""" - neither_generator_nor_children = self.generator is None and self.children is None + neither_generator_nor_children = self.generator is None and not self.children if neither_generator_nor_children: - raise TypeError("At least one of generator or children should be provided") + raise TypeError("At least one of generator or children must be provided") + + _generator = (self.generator,) if self.generator is not None else () + self._decryption_keyrings = itertools.chain(_generator, self.children) def on_encrypt(self, encryption_materials): # type: (EncryptionMaterials) -> EncryptionMaterials @@ -71,12 +75,11 @@ def on_encrypt(self, encryption_materials): # Check if data key is generated if not encryption_materials.data_encryption_key: - raise EncryptKeyError("Unable to generate data encryption key.") + raise GenerateKeyError("Unable to generate data encryption key.") # Call on_encrypt on all other keyrings - if self.children is not None: - for keyring in self.children: - encryption_materials = keyring.on_encrypt(encryption_materials) + for keyring in self.children: + encryption_materials = keyring.on_encrypt(encryption_materials) return encryption_materials @@ -95,17 +98,10 @@ def on_decrypt(self, decryption_materials, encrypted_data_keys): if decryption_materials.data_encryption_key: return decryption_materials - # Call on_decrypt on generator keyring if it is provided - if self.generator is not None: - decryption_materials = self.generator.on_decrypt(decryption_materials, encrypted_data_keys) + # Call on_decrypt on all keyrings till decryption is successful + for keyring in self._decryption_keyrings: + decryption_materials = keyring.on_decrypt(decryption_materials, encrypted_data_keys) if decryption_materials.data_encryption_key: return decryption_materials - # Call on_decrypt on all keyrings till decryption is successful - if self.children is not None: - for keyring in self.children: - decryption_materials = keyring.on_decrypt(decryption_materials, encrypted_data_keys) - if decryption_materials.data_encryption_key: - return decryption_materials - return decryption_materials diff --git a/test/unit/test_multi_keyrings.py b/test/unit/test_multi_keyrings.py new file mode 100644 index 000000000..e69de29bb From 83d07a65116bea22b4734a459e2a0b53bcbebe71 Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Thu, 18 Jul 2019 18:55:20 -0700 Subject: [PATCH 45/61] Multi keyring unit tests --- test/unit/test_multi_keyrings.py | 148 +++++++++++++++++++++++++++++++ 1 file changed, 148 insertions(+) diff --git a/test/unit/test_multi_keyrings.py b/test/unit/test_multi_keyrings.py index e69de29bb..4d04552ec 100644 --- a/test/unit/test_multi_keyrings.py +++ b/test/unit/test_multi_keyrings.py @@ -0,0 +1,148 @@ +# Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"). You +# may not use this file except in compliance with the License. A copy of +# the License is located at +# +# http://aws.amazon.com/apache2.0/ +# +# or in the "license" file accompanying this file. This file is +# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF +# ANY KIND, either express or implied. See the License for the specific +# language governing permissions and limitations under the License. +"""Unit tests for Multi keyring.""" + +import pytest +from cryptography.hazmat.backends import default_backend +from cryptography.hazmat.primitives.asymmetric import rsa + +from aws_encryption_sdk.identifiers import WrappingAlgorithm +from aws_encryption_sdk.keyring.multi_keyring import MultiKeyring +from aws_encryption_sdk.keyring.raw_keyring import RawAESKeyring, RawRSAKeyring + +pytestmark = [pytest.mark.unit, pytest.mark.local] + +_ENCRYPTION_CONTEXT = {"encryption": "context", "values": "here"} +_PROVIDER_ID = "Random Raw Keys" +_KEY_ID = b"5325b043-5843-4629-869c-64794af77ada" +_WRAPPING_KEY_AES = b"\xeby-\x80A6\x15rA8\x83#,\xe4\xab\xac`\xaf\x99Z\xc1\xce\xdb\xb6\x0f\xb7\x805\xb2\x14J3" + +_SIGNING_KEY = b"aws-crypto-public-key" + +_raw_rsa_keyring_1 = RawRSAKeyring( + key_namespace=_PROVIDER_ID, + key_name=_KEY_ID, + wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, + wrapping_key=rsa.generate_private_key(public_exponent=65537, key_size=2048, backend=default_backend()), +) + +_raw_rsa_keyring_2 = RawRSAKeyring( + key_namespace=_PROVIDER_ID, + key_name=_KEY_ID, + wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, + wrapping_key=rsa.generate_private_key(public_exponent=65537, key_size=2048, backend=default_backend()), +) + +_raw_aes_keyring = RawAESKeyring( + key_namespace=_PROVIDER_ID, + key_name=_KEY_ID, + wrapping_algorithm=WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING, + wrapping_key=_WRAPPING_KEY_AES, +) + +_multi_keyring_no_children = MultiKeyring( + generator=RawRSAKeyring( + key_namespace=_PROVIDER_ID, + key_name=_KEY_ID, + wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, + wrapping_key=rsa.generate_private_key(public_exponent=65537, key_size=2048, backend=default_backend()), + ) +) + +_multi_keyring_no_generator = MultiKeyring( + children=[ + RawRSAKeyring( + key_namespace=_PROVIDER_ID, + key_name=_KEY_ID, + wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, + wrapping_key=rsa.generate_private_key(public_exponent=65537, key_size=2048, backend=default_backend()), + ), + RawAESKeyring( + key_namespace=_PROVIDER_ID, + key_name=_KEY_ID, + wrapping_algorithm=WrappingAlgorithm.AES_128_GCM_IV12_TAG16_NO_PADDING, + wrapping_key=_WRAPPING_KEY_AES, + ), + ] +) + +_multi_keyring = MultiKeyring( + generator=RawAESKeyring( + key_namespace=_PROVIDER_ID, + key_name=_KEY_ID, + wrapping_algorithm=WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING, + wrapping_key=_WRAPPING_KEY_AES, + ), + children=[ + RawRSAKeyring( + key_namespace=_PROVIDER_ID, + key_name=_KEY_ID, + wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, + wrapping_key=rsa.generate_private_key(public_exponent=65537, key_size=2048, backend=default_backend()), + ), + RawRSAKeyring( + key_namespace=_PROVIDER_ID, + key_name=_KEY_ID, + wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, + wrapping_key=rsa.generate_private_key(public_exponent=65537, key_size=2048, backend=default_backend()), + ), + ], +) + +# _multi_keyring_null = MultiKeyring() + +# _multi_keyring_children_not_keyrings = MultiKeyring( +# generator=RawAESKeyring( +# key_namespace=_PROVIDER_ID, +# key_name=_KEY_ID, +# wrapping_algorithm=WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING, +# wrapping_key=_WRAPPING_KEY_AES, +# ), +# children=[ +# RawRSAKeyring( +# key_namespace=_PROVIDER_ID, +# key_name=_KEY_ID, +# wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, +# wrapping_key=rsa.generate_private_key(public_exponent=65537, key_size=2048, backend=default_backend()), +# ), +# WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, +# ], +# ) + + +# def test_null_multi_keyring(): +# class NullMultiKeyring(_multi_keyring_null): +# assert pytest.raises(TypeError) + +# with pytest.raises(TypeError) as exc_info: +# NullMultiKeyring() +# assert exc_info.match("At least one of generator or children must be provided") + + +# def test_no_generator_multi_keyring(): +# class NoGeneratorKeyring(_multi_keyring_no_generator): +# assert not pytest.raises(TypeError) +# +# +# def test_no_children_multi_keyring(): +# class NoChildrenKeyring(_multi_keyring_no_children): +# assert not pytest.raises(TypeError) + + +# def test_children_not_keyrings(): +# class ChildrenNotKeyrings(_multi_keyring_children_not_keyrings): +# pass +# +# with pytest.raises(TypeError) as exc_info: +# ChildrenNotKeyrings() +# assert exc_info.match("Children must me a keyring") From f0dd30a248b8e6c7deb25e2559660485687988d6 Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Mon, 22 Jul 2019 13:19:49 -0700 Subject: [PATCH 46/61] Optimized loop for decryption keyring --- src/aws_encryption_sdk/keyring/multi_keyring.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/aws_encryption_sdk/keyring/multi_keyring.py b/src/aws_encryption_sdk/keyring/multi_keyring.py index 12756eb62..c1b40b680 100644 --- a/src/aws_encryption_sdk/keyring/multi_keyring.py +++ b/src/aws_encryption_sdk/keyring/multi_keyring.py @@ -63,7 +63,7 @@ def on_encrypt(self, encryption_materials): :raises EncryptKeyError: if unable to encrypt data key. """ # Check if generator keyring is not provided and data key is not generated - if self.generator is None and not encryption_materials.data_encryption_key: + if self.generator is None and encryption_materials.data_encryption_key is None: raise EncryptKeyError( "Generator keyring not provided " "and encryption materials do not already contain a plaintext data key." @@ -94,14 +94,10 @@ def on_decrypt(self, decryption_materials, encrypted_data_keys): :returns: Optionally modified decryption materials. :rtype: aws_encryption_sdk.materials_managers.DecryptionMaterials """ - # Check if plaintext data key exists - if decryption_materials.data_encryption_key: - return decryption_materials - # Call on_decrypt on all keyrings till decryption is successful for keyring in self._decryption_keyrings: - decryption_materials = keyring.on_decrypt(decryption_materials, encrypted_data_keys) if decryption_materials.data_encryption_key: return decryption_materials + decryption_materials = keyring.on_decrypt(decryption_materials, encrypted_data_keys) return decryption_materials From 5bc2384f456c314f844fc0bbc7bd5b2f67da9fe4 Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Mon, 22 Jul 2019 17:35:25 -0700 Subject: [PATCH 47/61] Unit tests for multi keyrings and added sample encryption materials and multi keyrings in test_utils --- test/unit/test_keyring_multi.py | 84 +++++++++++++++++++ test/unit/test_utils.py | 139 +++++++++++++++++++++++++++++++- 2 files changed, 222 insertions(+), 1 deletion(-) create mode 100644 test/unit/test_keyring_multi.py diff --git a/test/unit/test_keyring_multi.py b/test/unit/test_keyring_multi.py new file mode 100644 index 000000000..1ed5ca413 --- /dev/null +++ b/test/unit/test_keyring_multi.py @@ -0,0 +1,84 @@ +# Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"). You +# may not use this file except in compliance with the License. A copy of +# the License is located at +# +# http://aws.amazon.com/apache2.0/ +# +# or in the "license" file accompanying this file. This file is +# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF +# ANY KIND, either express or implied. See the License for the specific +# language governing permissions and limitations under the License. +"""Unit tests for Multi keyring.""" + +import pytest +import six +from mock import MagicMock, patch, sentinel + +from aws_encryption_sdk.exceptions import GenerateKeyError, EncryptKeyError +from aws_encryption_sdk.identifiers import Algorithm, KeyringTraceFlag, WrappingAlgorithm +from aws_encryption_sdk.keyring.base import EncryptedDataKey, Keyring +from aws_encryption_sdk.keyring.multi_keyring import MultiKeyring +from aws_encryption_sdk.materials_managers import DecryptionMaterials, EncryptionMaterials +from aws_encryption_sdk.structures import KeyringTrace, MasterKeyInfo, RawDataKey + +from .test_utils import _MULTI_KEYRING_WITH_NO_GENERATOR, _ENCRYPTION_MATERIALS_WITHOUT_DATA_KEY, \ + _MULTI_KEYRING, _ENCRYPTION_MATERIALS_WITH_DATA_KEY + +try: # Python 3.5.0 and 3.5.1 have incompatible typing modules + from typing import Iterable # noqa pylint: disable=unused-import +except ImportError: # pragma: no cover + # We only actually need these imports when running the mypy checks + pass + +pytestmark = [pytest.mark.unit, pytest.mark.local] + +_ENCRYPTION_CONTEXT = {"encryption": "context", "values": "here"} +_PROVIDER_ID = "Random Raw Keys" +_KEY_ID = b"5325b043-5843-4629-869c-64794af77ada" +_WRAPPING_KEY = b"\xeby-\x80A6\x15rA8\x83#,\xe4\xab\xac`\xaf\x99Z\xc1\xce\xdb\xb6\x0f\xb7\x805\xb2\x14J3" +_SIGNING_KEY = b"aws-crypto-public-key" + + +class TestMultiKeyring(object): + + def test_parent(self): + assert issubclass(MultiKeyring, Keyring) + + def test_keyring_with_no_generator_no_children(self): + with pytest.raises(TypeError) as exc_info: + MultiKeyring() + assert exc_info.match("At least one of generator or children must be provided") + + def test_children_not_keyrings(self): + with pytest.raises(TypeError): + MultiKeyring( + children=[ + WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING + ] + ) + + def test_no_generator_no_data_encryption_key(self): + test_multi_keyring = _MULTI_KEYRING_WITH_NO_GENERATOR + with pytest.raises(EncryptKeyError) as exc_info: + test_multi_keyring.on_encrypt(encryption_materials=_ENCRYPTION_MATERIALS_WITHOUT_DATA_KEY) + assert exc_info.match("Generator keyring not provided and encryption materials do not already " + "contain a plaintext data key.") + + @patch("aws_encryption_sdk.keyring.raw_keyring.generate_data_key") + def test_data_key_not_generated(self, mock_generate): + mock_generate.return_value = None + test_multi_keyring = _MULTI_KEYRING + with pytest.raises(GenerateKeyError) as exc_info: + test_multi_keyring.on_encrypt(encryption_materials=_ENCRYPTION_MATERIALS_WITHOUT_DATA_KEY) + assert exc_info.match("Unable to generate data encryption key") + + # def test_number_of_encrypted_data_keys(self): + # test_multi_keyring = _MULTI_KEYRING + # test = test_multi_keyring.on_encrypt(encryption_materials=_ENCRYPTION_MATERIALS_WITH_DATA_KEY) + # assert len(test.encrypted_data_keys) == (len(test_multi_keyring.children) + 1) + # test_multi_keyring_no_generator = _MULTI_KEYRING_WITH_NO_GENERATOR + # test_no_generator = test_multi_keyring_no_generator.on_encrypt( + # encryption_materials=_MULTI_KEYRING_WITH_NO_GENERATOR) + # assert len(test_no_generator.encrypted_data_keys) == len(test_multi_keyring_no_generator.children) diff --git a/test/unit/test_utils.py b/test/unit/test_utils.py index b1374a09d..2d412c4a3 100644 --- a/test/unit/test_utils.py +++ b/test/unit/test_utils.py @@ -17,11 +17,18 @@ import pytest from mock import MagicMock, patch, sentinel +from cryptography.hazmat.backends import default_backend +from cryptography.hazmat.primitives.asymmetric import rsa + import aws_encryption_sdk.identifiers import aws_encryption_sdk.internal.utils from aws_encryption_sdk.exceptions import InvalidDataKeyError, SerializationError, UnknownIdentityError from aws_encryption_sdk.internal.defaults import MAX_FRAME_SIZE, MESSAGE_ID_LENGTH -from aws_encryption_sdk.structures import DataKey, EncryptedDataKey, MasterKeyInfo, RawDataKey +from aws_encryption_sdk.structures import DataKey, EncryptedDataKey, MasterKeyInfo, RawDataKey, KeyringTrace +from aws_encryption_sdk.keyring.raw_keyring import RawRSAKeyring, RawAESKeyring +from aws_encryption_sdk.keyring.multi_keyring import MultiKeyring +from aws_encryption_sdk.identifiers import Algorithm, KeyringTraceFlag, WrappingAlgorithm +from aws_encryption_sdk.materials_managers import DecryptionMaterials, EncryptionMaterials from .test_values import VALUES from .unit_test_utils import assert_prepped_stream_identity @@ -29,6 +36,136 @@ pytestmark = [pytest.mark.unit, pytest.mark.local] +_ENCRYPTION_CONTEXT = {"encryption": "context", "values": "here"} +_PROVIDER_ID = "Random Raw Keys" +_KEY_ID = b"5325b043-5843-4629-869c-64794af77ada" +_WRAPPING_KEY = b"\xeby-\x80A6\x15rA8\x83#,\xe4\xab\xac`\xaf\x99Z\xc1\xce\xdb\xb6\x0f\xb7\x805\xb2\x14J3" +_SIGNING_KEY = b"aws-crypto-public-key" +_DATA_KEY = ( + b"\x00\xfa\x8c\xdd\x08Au\xc6\x92_4\xc5\xfb\x90\xaf\x8f\xa1D\xaf\xcc\xd25" b"\xa8\x0b\x0b\x16\x92\x91W\x01\xb7\x84" +) +_WRAPPING_KEY_AES = b"\xeby-\x80A6\x15rA8\x83#,\xe4\xab\xac`\xaf\x99Z\xc1\xce\xdb\xb6\x0f\xb7\x805\xb2\x14J3" + + +_ENCRYPTION_MATERIALS_WITH_DATA_KEY = EncryptionMaterials( + algorithm=Algorithm.AES_256_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384, + data_encryption_key=RawDataKey( + key_provider=MasterKeyInfo(provider_id=_PROVIDER_ID, key_info=_KEY_ID), + data_key=b'*!\xa1"^-(\xf3\x105\x05i@B\xc2\xa2\xb7\xdd\xd5\xd5\xa9\xddm\xfae\xa8\\$\xf9d\x1e(', + ), + encryption_context=_ENCRYPTION_CONTEXT, + signing_key=_SIGNING_KEY, + keyring_trace=[ + KeyringTrace( + wrapping_key=MasterKeyInfo(provider_id=_PROVIDER_ID, key_info=_KEY_ID), + flags={KeyringTraceFlag.WRAPPING_KEY_GENERATED_DATA_KEY}, + ) + ], +) + + +_ENCRYPTION_MATERIALS_WITHOUT_DATA_KEY = EncryptionMaterials( + algorithm=Algorithm.AES_256_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384, + encryption_context=_ENCRYPTION_CONTEXT, + signing_key=_SIGNING_KEY, +) + + +_ENCRYPTION_MATERIALS_WITH_ENCRYPTED_DATA_KEY = EncryptionMaterials( + algorithm=Algorithm.AES_256_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384, + data_encryption_key=RawDataKey( + key_provider=MasterKeyInfo(provider_id=_PROVIDER_ID, key_info=_KEY_ID), + data_key=b'*!\xa1"^-(\xf3\x105\x05i@B\xc2\xa2\xb7\xdd\xd5\xd5\xa9\xddm\xfae\xa8\\$\xf9d\x1e(', + ), + encrypted_data_keys=[ + EncryptedDataKey( + key_provider=MasterKeyInfo(provider_id=_PROVIDER_ID, key_info=_KEY_ID), + encrypted_data_key=b"\xde^\x97\x7f\x84\xe9\x9e\x98\xd0\xe2\xf8\xd5\xcb\xe9\x7f.}\x87\x16,\x11n#\xc8p" + b"\xdb\xbf\x94\x86*Q\x06\xd2\xf5\xdah\x08\xa4p\x81\xf7\xf4G\x07FzE\xde", + ) + ], + encryption_context=_ENCRYPTION_CONTEXT, + signing_key=_SIGNING_KEY, + keyring_trace=[ + KeyringTrace( + wrapping_key=MasterKeyInfo(provider_id=_PROVIDER_ID, key_info=_KEY_ID), + flags={KeyringTraceFlag.WRAPPING_KEY_GENERATED_DATA_KEY, KeyringTraceFlag.WRAPPING_KEY_ENCRYPTED_DATA_KEY}, + ) + ], +) + + +_DECRYPTION_MATERIALS_WITH_DATA_KEY = DecryptionMaterials( + algorithm=Algorithm.AES_256_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384, + data_encryption_key=RawDataKey( + key_provider=MasterKeyInfo(provider_id=_PROVIDER_ID, key_info=_KEY_ID), + data_key=b'*!\xa1"^-(\xf3\x105\x05i@B\xc2\xa2\xb7\xdd\xd5\xd5\xa9\xddm\xfae\xa8\\$\xf9d\x1e(', + ), + encryption_context=_ENCRYPTION_CONTEXT, + verification_key=b"ex_verification_key", + keyring_trace=[KeyringTrace( + wrapping_key=MasterKeyInfo(provider_id=_PROVIDER_ID, key_info=_KEY_ID), + flags={KeyringTraceFlag.WRAPPING_KEY_DECRYPTED_DATA_KEY} + )] +) + + +_DECRYPTION_MATERIALS_WITHOUT_DATA_KEY = DecryptionMaterials( + verification_key=b"ex_verification_key", +) + +_MULTI_KEYRING = MultiKeyring( + generator=RawAESKeyring( + key_namespace=_PROVIDER_ID, + key_name=_KEY_ID, + wrapping_algorithm=WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING, + wrapping_key=_WRAPPING_KEY_AES, + ), + children=[ + RawRSAKeyring( + key_namespace=_PROVIDER_ID, + key_name=_KEY_ID, + wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, + wrapping_key=rsa.generate_private_key(public_exponent=65537, key_size=2048, backend=default_backend()), + ), + RawRSAKeyring( + key_namespace=_PROVIDER_ID, + key_name=_KEY_ID, + wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, + wrapping_key=rsa.generate_private_key(public_exponent=65537, key_size=2048, backend=default_backend()), + ), + ], + ) + +_MULTI_KEYRING_WITH_NO_CHILDREN = MultiKeyring( + generator=RawRSAKeyring( + key_namespace=_PROVIDER_ID, + key_name=_KEY_ID, + wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, + wrapping_key=rsa.generate_private_key(public_exponent=65537, key_size=2048, backend=default_backend()), + ) + ) + +_MULTI_KEYRING_WITH_NO_GENERATOR = MultiKeyring( + children=[ + RawRSAKeyring( + key_namespace=_PROVIDER_ID, + key_name=_KEY_ID, + wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, + wrapping_key=rsa.generate_private_key(public_exponent=65537, key_size=2048, backend=default_backend()), + ), + RawAESKeyring( + key_namespace=_PROVIDER_ID, + key_name=_KEY_ID, + wrapping_algorithm=WrappingAlgorithm.AES_128_GCM_IV12_TAG16_NO_PADDING, + wrapping_key=_WRAPPING_KEY_AES, + ), + ] + ) + +# _MULTI_KEYRING_WITH_NO_GENERATOR_NO_CHILDREN = MultiKeyring() + + def test_prep_stream_data_passthrough(): test = aws_encryption_sdk.internal.utils.prep_stream_data(io.BytesIO(b"some data")) From b1c9aaae482a7e24da6eec2c48a7d3030fa94b40 Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Mon, 22 Jul 2019 20:40:42 -0700 Subject: [PATCH 48/61] Multi keyrings unit tests --- .../keyring/multi_keyring.py | 8 +- src/aws_encryption_sdk/keyring/raw_keyring.py | 205 +++++++++++------- test/unit/test_keyring_multi.py | 17 +- 3 files changed, 136 insertions(+), 94 deletions(-) diff --git a/src/aws_encryption_sdk/keyring/multi_keyring.py b/src/aws_encryption_sdk/keyring/multi_keyring.py index c1b40b680..901fd17b3 100644 --- a/src/aws_encryption_sdk/keyring/multi_keyring.py +++ b/src/aws_encryption_sdk/keyring/multi_keyring.py @@ -71,7 +71,7 @@ def on_encrypt(self, encryption_materials): # Call on_encrypt on the generator keyring if it is provided if self.generator is not None: - encryption_materials = self.generator.on_encrypt(encryption_materials) + encryption_materials = self.generator.on_encrypt(encryption_materials=encryption_materials) # Check if data key is generated if not encryption_materials.data_encryption_key: @@ -79,7 +79,7 @@ def on_encrypt(self, encryption_materials): # Call on_encrypt on all other keyrings for keyring in self.children: - encryption_materials = keyring.on_encrypt(encryption_materials) + encryption_materials = keyring.on_encrypt(encryption_materials=encryption_materials) return encryption_materials @@ -98,6 +98,6 @@ def on_decrypt(self, decryption_materials, encrypted_data_keys): for keyring in self._decryption_keyrings: if decryption_materials.data_encryption_key: return decryption_materials - decryption_materials = keyring.on_decrypt(decryption_materials, encrypted_data_keys) - + decryption_materials = keyring.on_decrypt(decryption_materials=decryption_materials, + encrypted_data_keys=encrypted_data_keys) return decryption_materials diff --git a/src/aws_encryption_sdk/keyring/raw_keyring.py b/src/aws_encryption_sdk/keyring/raw_keyring.py index f50d96618..3cfdf9c21 100644 --- a/src/aws_encryption_sdk/keyring/raw_keyring.py +++ b/src/aws_encryption_sdk/keyring/raw_keyring.py @@ -17,10 +17,11 @@ import attr import six -from cryptography.hazmat.primitives.asymmetric.padding import OAEP -from cryptography.hazmat.primitives.asymmetric.rsa import RSAPrivateKey, RSAPublicKey +from cryptography.hazmat.backends import default_backend +from cryptography.hazmat.primitives import serialization +from cryptography.hazmat.primitives.asymmetric import padding, rsa -from aws_encryption_sdk.exceptions import EncryptKeyError +from aws_encryption_sdk.exceptions import GenerateKeyError from aws_encryption_sdk.identifiers import EncryptionKeyType, KeyringTraceFlag, WrappingAlgorithm from aws_encryption_sdk.internal.crypto.wrapping_keys import EncryptedData, WrappingKey from aws_encryption_sdk.internal.formatting.deserialize import deserialize_wrapped_key @@ -31,7 +32,7 @@ from aws_encryption_sdk.structures import EncryptedDataKey, KeyringTrace, MasterKeyInfo, RawDataKey try: # Python 3.5.0 and 3.5.1 have incompatible typing modules - from typing import Iterable # noqa pylint: disable=unused-import + from typing import Iterable, Union # noqa pylint: disable=unused-import except ImportError: # pragma: no cover # We only actually need these imports when running the mypy checks pass @@ -54,12 +55,12 @@ def get_key_info_prefix(key_namespace, key_name, wrapping_key): return key_info_prefix -def on_encrypt_helper( +def generate_data_key( encryption_materials, # type: EncryptionMaterials key_provider, # type: MasterKeyInfo ): # type: (...) -> bytes - """Helper function for the on_encrypt function of keyring. + """Generates plaintext data key for the keyring. :param encryption_materials: Encryption materials for the keyring to modify. :type encryption_materials: aws_encryption_sdk.materials_managers.EncryptionMaterials @@ -67,57 +68,25 @@ def on_encrypt_helper( :type key_provider: MasterKeyInfo :return bytes: Plaintext data key """ - # Check if data key already exists - if not encryption_materials.data_encryption_key: + # Generate data key + plaintext_data_key = os.urandom(encryption_materials.algorithm.kdf_input_len) - # Generate data key - plaintext_data_key = os.urandom(encryption_materials.algorithm.kdf_input_len) + # Check if data key is generated + if not plaintext_data_key or plaintext_data_key is None: + raise GenerateKeyError("Unable to generate data encryption key.") - # Check if data key is generated - if not plaintext_data_key: - raise EncryptKeyError("Unable to generate data encryption key.") + # Create a keyring trace + keyring_trace = KeyringTrace(wrapping_key=key_provider, flags={KeyringTraceFlag.WRAPPING_KEY_GENERATED_DATA_KEY}) - # Create a keyring trace - keyring_trace = KeyringTrace( - wrapping_key=key_provider, flags={KeyringTraceFlag.WRAPPING_KEY_GENERATED_DATA_KEY} - ) - - # plaintext_data_key to RawDataKey - data_encryption_key = RawDataKey(key_provider=key_provider, data_key=plaintext_data_key) - - # Add generated data key to encryption_materials - encryption_materials.add_data_encryption_key(data_encryption_key, keyring_trace) + # plaintext_data_key to RawDataKey + data_encryption_key = RawDataKey(key_provider=key_provider, data_key=plaintext_data_key) - else: - plaintext_data_key = encryption_materials.data_encryption_key.data_key + # Add generated data key to encryption_materials + encryption_materials.add_data_encryption_key(data_encryption_key, keyring_trace) return plaintext_data_key -def on_decrypt_helper( - wrapping_algorithm, # type: WrappingAlgorithm - key_name, # type: bytes - encrypted_data_key, # type: EncryptedDataKey -): - # type: (...) -> EncryptedData - """Helper function for the on_decrypt function of keyring. - - :param wrapping_algorithm: Wrapping Algorithm with which to wrap plaintext data key. - :type wrapping_algorithm: WrappingAlgorithm - :param bytes key_name: Key ID. - :param encrypted_data_key: Data key encrypted with a wrapping key. - :type encrypted_data_key: aws_encryption_sdk.structures.EncryptedDataKey - :return encrypted_wrapped_key: Encrypted, wrapped, data key - :rtype encrypted_wrapped_key: EncryptedData - """ - # Wrapped EncryptedDataKey to deserialized EncryptedData - encrypted_wrapped_key = deserialize_wrapped_key( - wrapping_algorithm=wrapping_algorithm, wrapping_key_id=key_name, wrapped_encrypted_key=encrypted_data_key - ) - - return encrypted_wrapped_key - - @attr.s class RawAESKeyring(Keyring): """Public class for Raw AES Keyring. @@ -158,9 +127,16 @@ def on_encrypt(self, encryption_materials): :returns: Optionally modified encryption materials :rtype: aws_encryption_sdk.materials_managers.EncryptionMaterials """ - plaintext_data_key = on_encrypt_helper( - encryption_materials=encryption_materials, key_provider=self._key_provider - ) + if not encryption_materials.data_encryption_key: + plaintext_data_key = generate_data_key( + encryption_materials=encryption_materials, key_provider=self._key_provider + ) + else: + plaintext_data_key = encryption_materials.data_encryption_key.data_key + + # Check if data key exists + if not plaintext_data_key or plaintext_data_key is None: + raise GenerateKeyError("Unable to generate data encryption key.") # Encrypt data key encrypted_wrapped_key = self._wrapping_key_structure.encrypt( @@ -209,8 +185,11 @@ def on_decrypt(self, decryption_materials, encrypted_data_keys): and len(key.key_provider.key_info) == expected_key_info_len and key.key_provider.key_info.startswith(self._key_info_prefix) ): - encrypted_wrapped_key = on_decrypt_helper( - wrapping_algorithm=self._wrapping_algorithm, key_name=self.key_name, encrypted_data_key=key + # Wrapped EncryptedDataKey to deserialized EncryptedData + encrypted_wrapped_key = deserialize_wrapped_key( + wrapping_algorithm=self._wrapping_algorithm, + wrapping_key_id=self.key_name, + wrapped_encrypted_key=key, ) # EncryptedData to raw key string try: @@ -220,7 +199,7 @@ def on_decrypt(self, decryption_materials, encrypted_data_keys): ) except Exception as error: # pylint: disable=broad-except - logger = logging.getLogger() + logger = logging.getLogger(__name__) logger.error(error.__class__.__name__, ":", str(error)) return decryption_materials @@ -237,7 +216,7 @@ def on_decrypt(self, decryption_materials, encrypted_data_keys): ) decryption_materials.add_data_encryption_key(data_encryption_key, keyring_trace) - if decryption_materials.data_key: + if decryption_materials.data_encryption_key: return decryption_materials return decryption_materials @@ -259,9 +238,51 @@ class RawRSAKeyring(Keyring): key_namespace = attr.ib(validator=attr.validators.instance_of(six.string_types)) key_name = attr.ib(validator=attr.validators.instance_of(six.binary_type)) + # _wrapping_key = attr.ib(repr=False, validator=attr.validators.in_([rsa.RSAPrivateKey, rsa.RSAPublicKey])) + # ----- need to figure out how to do this correctly _wrapping_key = attr.ib(repr=False, validator=attr.validators.instance_of(object)) _wrapping_algorithm = attr.ib(repr=False, validator=attr.validators.instance_of(WrappingAlgorithm)) + @classmethod + def fromPEMEncoding(cls, key_namespace, key_name, encoded_key, password, wrapping_algorithm): + # key_namespace = attr.ib(validator=attr.validators.instance_of(six.string_types)) + # key_name = attr.ib(validator=attr.validators.instance_of(six.binary_type)) + # _encoded_key = attr.ib(validator=attr.validators.instance_of(six.binary_type)) + # _password = attr.ib(validator=attr.validators.optional(attr.validators.instance_of(six.binary_type))) + # _wrapping_algorithm = attr.ib(repr=False, validator=attr.validators.instance_of(WrappingAlgorithm)) + if password: + loaded_wrapping_key = serialization.load_pem_private_key( + data=encoded_key, password=password, backend=default_backend() + ) + else: + loaded_wrapping_key = serialization.load_pem_public_key(data=encoded_key, backend=default_backend()) + return cls( + key_namespace=key_namespace, + key_name=key_name, + wrapping_key=loaded_wrapping_key, + wrapping_algorithm=wrapping_algorithm, + ) + + @classmethod + def fromDEREncoding(cls, key_namespace, key_name, encoded_key, password, wrapping_algorithm): + # key_namespace = attr.ib(validator=attr.validators.instance_of(six.string_types)) + # key_name = attr.ib(validator=attr.validators.instance_of(six.binary_type)) + # _encoded_key = attr.ib(validator=attr.validators.instance_of(six.binary_type)) + # _password = attr.ib(validator=attr.validators.optional(attr.validators.instance_of(six.binary_type))) + # _wrapping_algorithm = attr.ib(repr=False, validator=attr.validators.instance_of(WrappingAlgorithm)) + if password: + loaded_wrapping_key = serialization.load_der_private_key( + data=encoded_key, password=password, backend=default_backend() + ) + else: + loaded_wrapping_key = serialization.load_der_public_key(data=encoded_key, backend=default_backend()) + return cls( + key_namespace=key_namespace, + key_name=key_name, + wrapping_key=loaded_wrapping_key, + wrapping_algorithm=wrapping_algorithm, + ) + def __attrs_post_init__(self): # type: () -> None """Prepares initial values not handled by attrs.""" @@ -276,35 +297,50 @@ def on_encrypt(self, encryption_materials): :returns: Optionally modified encryption materials. :rtype: aws_encryption_sdk.materials_managers.EncryptionMaterials """ - plaintext_data_key = on_encrypt_helper( - encryption_materials=encryption_materials, key_provider=self._key_provider - ) - if isinstance(self._wrapping_key, RSAPublicKey): + if not encryption_materials.data_encryption_key: + plaintext_data_key = generate_data_key( + encryption_materials=encryption_materials, key_provider=self._key_provider + ) + else: + plaintext_data_key = encryption_materials.data_encryption_key.data_key + if isinstance(self._wrapping_key, rsa.RSAPublicKey): # Encrypt data key encrypted_wrapped_key = EncryptedData( - iv=None, ciphertext=self._wrapping_key.encrypt(plaintext=plaintext_data_key, padding=OAEP), tag=None + iv=None, + ciphertext=self._wrapping_key.encrypt( + plaintext=plaintext_data_key, padding=self._wrapping_algorithm.padding + ), + tag=None, ) - - # EncryptedData to EncryptedDataKey - encrypted_data_key = serialize_wrapped_key( - key_provider=self._key_provider, - wrapping_algorithm=self._wrapping_algorithm, - wrapping_key_id=self._key_name, - encrypted_wrapped_key=encrypted_wrapped_key, + else: + # Encrypt data key + encrypted_wrapped_key = EncryptedData( + iv=None, + ciphertext=self._wrapping_key.public_key().encrypt( + plaintext=plaintext_data_key, padding=self._wrapping_algorithm.padding + ), + tag=None, ) - # Update Keyring Trace - if encrypted_data_key: - keyring_trace = KeyringTrace( - wrapping_key=encrypted_data_key.key_provider, - flags={KeyringTraceFlag.WRAPPING_KEY_ENCRYPTED_DATA_KEY}, - ) + # EncryptedData to EncryptedDataKey + encrypted_data_key = serialize_wrapped_key( + key_provider=self._key_provider, + wrapping_algorithm=self._wrapping_algorithm, + wrapping_key_id=self.key_name, + encrypted_wrapped_key=encrypted_wrapped_key, + ) - # Add encrypted data key to encryption_materials - encryption_materials.add_encrypted_data_key( - encrypted_data_key=encrypted_data_key, keyring_trace=keyring_trace - ) + # Update Keyring Trace + if encrypted_data_key: + keyring_trace = KeyringTrace( + wrapping_key=encrypted_data_key.key_provider, flags={KeyringTraceFlag.WRAPPING_KEY_ENCRYPTED_DATA_KEY} + ) + + # Add encrypted data key to encryption_materials + encryption_materials.add_encrypted_data_key( + encrypted_data_key=encrypted_data_key, keyring_trace=keyring_trace + ) return encryption_materials @@ -319,16 +355,19 @@ def on_decrypt(self, decryption_materials, encrypted_data_keys): :returns: Optionally modified decryption materials. :rtype: aws_encryption_sdk.materials_managers.DecryptionMaterials """ - if isinstance(self._wrapping_key, RSAPrivateKey): + if isinstance(self._wrapping_key, rsa.RSAPrivateKey): # Decrypt data key for key in encrypted_data_keys: if key.key_provider == self._key_provider: - encrypted_wrapped_key = on_decrypt_helper( - wrapping_algorithm=self._wrapping_algorithm, key_name=self.key_name, encrypted_data_key=key + # Wrapped EncryptedDataKey to deserialized EncryptedData + encrypted_wrapped_key = deserialize_wrapped_key( + wrapping_algorithm=self._wrapping_algorithm, + wrapping_key_id=self.key_name, + wrapped_encrypted_key=key, ) try: plaintext_data_key = self._wrapping_key.decrypt( - ciphertext=encrypted_wrapped_key.ciphertext, padding=OAEP + ciphertext=encrypted_wrapped_key.ciphertext, padding=self._wrapping_algorithm.padding ) except Exception as error: # pylint: disable=broad-except logger = logging.getLogger() @@ -349,5 +388,7 @@ def on_decrypt(self, decryption_materials, encrypted_data_keys): data_key=plaintext_data_key, ) decryption_materials.add_data_encryption_key(data_encryption_key, keyring_trace) + if decryption_materials.data_encryption_key: + return decryption_materials return decryption_materials diff --git a/test/unit/test_keyring_multi.py b/test/unit/test_keyring_multi.py index 1ed5ca413..262047c57 100644 --- a/test/unit/test_keyring_multi.py +++ b/test/unit/test_keyring_multi.py @@ -74,11 +74,12 @@ def test_data_key_not_generated(self, mock_generate): test_multi_keyring.on_encrypt(encryption_materials=_ENCRYPTION_MATERIALS_WITHOUT_DATA_KEY) assert exc_info.match("Unable to generate data encryption key") - # def test_number_of_encrypted_data_keys(self): - # test_multi_keyring = _MULTI_KEYRING - # test = test_multi_keyring.on_encrypt(encryption_materials=_ENCRYPTION_MATERIALS_WITH_DATA_KEY) - # assert len(test.encrypted_data_keys) == (len(test_multi_keyring.children) + 1) - # test_multi_keyring_no_generator = _MULTI_KEYRING_WITH_NO_GENERATOR - # test_no_generator = test_multi_keyring_no_generator.on_encrypt( - # encryption_materials=_MULTI_KEYRING_WITH_NO_GENERATOR) - # assert len(test_no_generator.encrypted_data_keys) == len(test_multi_keyring_no_generator.children) + def test_number_of_encrypted_data_keys_without_generator(self): + test_multi_keyring = _MULTI_KEYRING_WITH_NO_GENERATOR + test = test_multi_keyring.on_encrypt(encryption_materials=_ENCRYPTION_MATERIALS_WITH_DATA_KEY) + assert len(test.encrypted_data_keys) == len(test_multi_keyring.children) + + def test_number_of_encrypted_data_keys_with_generator(self): + test_multi_keyring = _MULTI_KEYRING + test = test_multi_keyring.on_encrypt(encryption_materials=_ENCRYPTION_MATERIALS_WITH_DATA_KEY) + assert len(test.encrypted_data_keys) == len(test_multi_keyring.children) + 1 From 42f92c1ed0c619463808009cf42e035705a4202a Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Fri, 26 Jul 2019 14:41:51 -0700 Subject: [PATCH 49/61] Making changes in tests and API --- .../keyring/multi_keyring.py | 4 +- test/unit/test_keyring_multi.py | 97 +++++++++++-------- 2 files changed, 57 insertions(+), 44 deletions(-) diff --git a/src/aws_encryption_sdk/keyring/multi_keyring.py b/src/aws_encryption_sdk/keyring/multi_keyring.py index 901fd17b3..88e98068c 100644 --- a/src/aws_encryption_sdk/keyring/multi_keyring.py +++ b/src/aws_encryption_sdk/keyring/multi_keyring.py @@ -74,7 +74,7 @@ def on_encrypt(self, encryption_materials): encryption_materials = self.generator.on_encrypt(encryption_materials=encryption_materials) # Check if data key is generated - if not encryption_materials.data_encryption_key: + if encryption_materials.data_encryption_key is None: raise GenerateKeyError("Unable to generate data encryption key.") # Call on_encrypt on all other keyrings @@ -96,7 +96,7 @@ def on_decrypt(self, decryption_materials, encrypted_data_keys): """ # Call on_decrypt on all keyrings till decryption is successful for keyring in self._decryption_keyrings: - if decryption_materials.data_encryption_key: + if decryption_materials.data_encryption_key is not None: return decryption_materials decryption_materials = keyring.on_decrypt(decryption_materials=decryption_materials, encrypted_data_keys=encrypted_data_keys) diff --git a/test/unit/test_keyring_multi.py b/test/unit/test_keyring_multi.py index 262047c57..97584ee2a 100644 --- a/test/unit/test_keyring_multi.py +++ b/test/unit/test_keyring_multi.py @@ -20,6 +20,7 @@ from aws_encryption_sdk.identifiers import Algorithm, KeyringTraceFlag, WrappingAlgorithm from aws_encryption_sdk.keyring.base import EncryptedDataKey, Keyring from aws_encryption_sdk.keyring.multi_keyring import MultiKeyring +from aws_encryption_sdk.keyring.raw_keyring import RawAESKeyring from aws_encryption_sdk.materials_managers import DecryptionMaterials, EncryptionMaterials from aws_encryption_sdk.structures import KeyringTrace, MasterKeyInfo, RawDataKey @@ -41,45 +42,57 @@ _SIGNING_KEY = b"aws-crypto-public-key" -class TestMultiKeyring(object): - - def test_parent(self): - assert issubclass(MultiKeyring, Keyring) - - def test_keyring_with_no_generator_no_children(self): - with pytest.raises(TypeError) as exc_info: - MultiKeyring() - assert exc_info.match("At least one of generator or children must be provided") - - def test_children_not_keyrings(self): - with pytest.raises(TypeError): - MultiKeyring( - children=[ - WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING - ] - ) - - def test_no_generator_no_data_encryption_key(self): - test_multi_keyring = _MULTI_KEYRING_WITH_NO_GENERATOR - with pytest.raises(EncryptKeyError) as exc_info: - test_multi_keyring.on_encrypt(encryption_materials=_ENCRYPTION_MATERIALS_WITHOUT_DATA_KEY) - assert exc_info.match("Generator keyring not provided and encryption materials do not already " - "contain a plaintext data key.") - - @patch("aws_encryption_sdk.keyring.raw_keyring.generate_data_key") - def test_data_key_not_generated(self, mock_generate): - mock_generate.return_value = None - test_multi_keyring = _MULTI_KEYRING - with pytest.raises(GenerateKeyError) as exc_info: - test_multi_keyring.on_encrypt(encryption_materials=_ENCRYPTION_MATERIALS_WITHOUT_DATA_KEY) - assert exc_info.match("Unable to generate data encryption key") - - def test_number_of_encrypted_data_keys_without_generator(self): - test_multi_keyring = _MULTI_KEYRING_WITH_NO_GENERATOR - test = test_multi_keyring.on_encrypt(encryption_materials=_ENCRYPTION_MATERIALS_WITH_DATA_KEY) - assert len(test.encrypted_data_keys) == len(test_multi_keyring.children) - - def test_number_of_encrypted_data_keys_with_generator(self): - test_multi_keyring = _MULTI_KEYRING - test = test_multi_keyring.on_encrypt(encryption_materials=_ENCRYPTION_MATERIALS_WITH_DATA_KEY) - assert len(test.encrypted_data_keys) == len(test_multi_keyring.children) + 1 +def test_parent(): + assert issubclass(MultiKeyring, Keyring) + + +def test_keyring_with_generator_but_no_children(): + test_multi_keyring = MultiKeyring( + generator=RawAESKeyring( + + ) + ) + + +def test_keyring_with_no_generator_no_children(): + with pytest.raises(TypeError) as exc_info: + MultiKeyring() + assert exc_info.match("At least one of generator or children must be provided") + + +def test_children_not_keyrings(): + with pytest.raises(TypeError) as exc_info: + MultiKeyring( + children=[ + WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING + ] + ) + assert exc_info.errisinstance(TypeError) + + +def test_no_generator_no_data_encryption_key(): + test_multi_keyring = _MULTI_KEYRING_WITH_NO_GENERATOR + with pytest.raises(EncryptKeyError) as exc_info: + test_multi_keyring.on_encrypt(encryption_materials=_ENCRYPTION_MATERIALS_WITHOUT_DATA_KEY) + assert exc_info.match("Generator keyring not provided and encryption materials do not already " + "contain a plaintext data key.") + +@patch("aws_encryption_sdk.keyring.raw_keyring.generate_data_key") +def test_data_key_not_generated(mock_generate): + mock_generate.return_value = None + test_multi_keyring = _MULTI_KEYRING + with pytest.raises(GenerateKeyError) as exc_info: + test_multi_keyring.on_encrypt(encryption_materials=_ENCRYPTION_MATERIALS_WITHOUT_DATA_KEY) + assert exc_info.match("Unable to generate data encryption key") + + +def test_number_of_encrypted_data_keys_without_generator(): + test_multi_keyring = _MULTI_KEYRING_WITH_NO_GENERATOR + test = test_multi_keyring.on_encrypt(encryption_materials=_ENCRYPTION_MATERIALS_WITH_DATA_KEY) + assert len(test.encrypted_data_keys) == len(test_multi_keyring.children) + + +def test_number_of_encrypted_data_keys_with_generator(): + test_multi_keyring = _MULTI_KEYRING + test = test_multi_keyring.on_encrypt(encryption_materials=_ENCRYPTION_MATERIALS_WITH_DATA_KEY) + assert len(test.encrypted_data_keys) == len(test_multi_keyring.children) + 1 From e89c5c791bd4951dae7c7c50dce949078708398f Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Fri, 26 Jul 2019 16:11:50 -0700 Subject: [PATCH 50/61] Almost all unit tests done --- src/aws_encryption_sdk/keyring/raw_keyring.py | 410 ++++++++++-------- test/functional/test_f_multi_keyring.py | 8 +- test/unit/test_keyring_multi.py | 121 +++++- test/unit/test_multi_keyrings.py | 266 ++++++------ test/unit/test_utils.py | 225 +++++----- 5 files changed, 599 insertions(+), 431 deletions(-) diff --git a/src/aws_encryption_sdk/keyring/raw_keyring.py b/src/aws_encryption_sdk/keyring/raw_keyring.py index 3cfdf9c21..da4d93707 100644 --- a/src/aws_encryption_sdk/keyring/raw_keyring.py +++ b/src/aws_encryption_sdk/keyring/raw_keyring.py @@ -17,6 +17,7 @@ import attr import six +from attr.validators import instance_of, optional from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives import serialization from cryptography.hazmat.primitives.asymmetric import padding, rsa @@ -32,27 +33,12 @@ from aws_encryption_sdk.structures import EncryptedDataKey, KeyringTrace, MasterKeyInfo, RawDataKey try: # Python 3.5.0 and 3.5.1 have incompatible typing modules - from typing import Iterable, Union # noqa pylint: disable=unused-import + from typing import Iterable # noqa pylint: disable=unused-import except ImportError: # pragma: no cover # We only actually need these imports when running the mypy checks pass - -def get_key_info_prefix(key_namespace, key_name, wrapping_key): - # type: (str, bytes, WrappingKey) -> six.binary_type - """Helper function to get key info prefix - - :param str key_namespace: String defining the keyring. - :param bytes key_name: Key ID - :param wrapping_key: Encryption key with which to wrap plaintext data key. - :type wrapping_key: WrappingKey - :return: Serialized key_info prefix - :rtype: bytes - """ - key_info_prefix = serialize_raw_master_key_prefix( - RawMasterKey(provider_id=key_namespace, key_id=key_name, wrapping_key=wrapping_key) - ) - return key_info_prefix +_LOGGER = logging.getLogger(__name__) def generate_data_key( @@ -68,11 +54,16 @@ def generate_data_key( :type key_provider: MasterKeyInfo :return bytes: Plaintext data key """ - # Generate data key - plaintext_data_key = os.urandom(encryption_materials.algorithm.kdf_input_len) + # Check if encryption materials contain data encryption key + if encryption_materials.data_encryption_key is not None: + raise TypeError("Data encryption key already exists.") - # Check if data key is generated - if not plaintext_data_key or plaintext_data_key is None: + # Generate data key + try: + plaintext_data_key = os.urandom(encryption_materials.algorithm.kdf_input_len) + except Exception: # pylint: disable=broad-except + error_message = "Unable to generate data encryption key." + _LOGGER.exception(error_message) raise GenerateKeyError("Unable to generate data encryption key.") # Create a keyring trace @@ -98,10 +89,27 @@ class RawAESKeyring(Keyring): :type wrapping_algorithm: WrappingAlgorithm """ - key_namespace = attr.ib(validator=attr.validators.instance_of(six.string_types)) - key_name = attr.ib(validator=attr.validators.instance_of(six.binary_type)) - _wrapping_key = attr.ib(repr=False, validator=attr.validators.instance_of(six.binary_type)) - _wrapping_algorithm = attr.ib(repr=False, validator=attr.validators.instance_of(WrappingAlgorithm)) + key_namespace = attr.ib(validator=instance_of(six.string_types)) + key_name = attr.ib(validator=instance_of(six.binary_type)) + _wrapping_key = attr.ib(repr=False, validator=instance_of(six.binary_type)) + _wrapping_algorithm = attr.ib(repr=False, validator=instance_of(WrappingAlgorithm)) + + @staticmethod + def _get_key_info_prefix(key_namespace, key_name, wrapping_key): + # type: (str, bytes, WrappingKey) -> six.binary_type + """Helper function to get key info prefix + + :param str key_namespace: String defining the keyring. + :param bytes key_name: Key ID + :param wrapping_key: Encryption key with which to wrap plaintext data key. + :type wrapping_key: WrappingKey + :return: Serialized key_info prefix + :rtype: bytes + """ + key_info_prefix = serialize_raw_master_key_prefix( + RawMasterKey(provider_id=key_namespace, key_id=key_name, wrapping_key=wrapping_key) + ) + return key_info_prefix def __attrs_post_init__(self): # type: () -> None @@ -114,7 +122,7 @@ def __attrs_post_init__(self): wrapping_key_type=EncryptionKeyType.SYMMETRIC, ) - self._key_info_prefix = get_key_info_prefix( + self._key_info_prefix = self._get_key_info_prefix( key_namespace=self.key_namespace, key_name=self.key_name, wrapping_key=self._wrapping_key_structure ) @@ -127,40 +135,45 @@ def on_encrypt(self, encryption_materials): :returns: Optionally modified encryption materials :rtype: aws_encryption_sdk.materials_managers.EncryptionMaterials """ - if not encryption_materials.data_encryption_key: - plaintext_data_key = generate_data_key( + if encryption_materials.data_encryption_key is None: + plaintext_generated = generate_data_key( encryption_materials=encryption_materials, key_provider=self._key_provider ) - else: - plaintext_data_key = encryption_materials.data_encryption_key.data_key - # Check if data key exists - if not plaintext_data_key or plaintext_data_key is None: - raise GenerateKeyError("Unable to generate data encryption key.") + # Check if data key exists + if not plaintext_generated or plaintext_generated is None: + raise GenerateKeyError("Unable to generate data encryption key.") # Encrypt data key encrypted_wrapped_key = self._wrapping_key_structure.encrypt( - plaintext_data_key=plaintext_data_key, encryption_context=encryption_materials.encryption_context + plaintext_data_key=encryption_materials.data_encryption_key.data_key, + encryption_context=encryption_materials.encryption_context, ) + # Check if encryption is successful + if encrypted_wrapped_key is None: + return encryption_materials + # EncryptedData to EncryptedDataKey - encrypted_data_key = serialize_wrapped_key( - key_provider=self._key_provider, - wrapping_algorithm=self._wrapping_algorithm, - wrapping_key_id=self.key_name, - encrypted_wrapped_key=encrypted_wrapped_key, - ) + try: + encrypted_data_key = serialize_wrapped_key( + key_provider=self._key_provider, + wrapping_algorithm=self._wrapping_algorithm, + wrapping_key_id=self.key_name, + encrypted_wrapped_key=encrypted_wrapped_key, + ) + except Exception: # pylint: disable=broad-except + error_message = "Raw AES Keyring unable to encrypt data key" + _LOGGER.exception(error_message) + return encryption_materials # Update Keyring Trace - if encrypted_data_key: - keyring_trace = KeyringTrace( - wrapping_key=encrypted_data_key.key_provider, flags={KeyringTraceFlag.WRAPPING_KEY_ENCRYPTED_DATA_KEY} - ) + keyring_trace = KeyringTrace( + wrapping_key=encrypted_data_key.key_provider, flags={KeyringTraceFlag.WRAPPING_KEY_ENCRYPTED_DATA_KEY} + ) - # Add encrypted data key to encryption_materials - encryption_materials.add_encrypted_data_key( - encrypted_data_key=encrypted_data_key, keyring_trace=keyring_trace - ) + # Add encrypted data key to encryption_materials + encryption_materials.add_encrypted_data_key(encrypted_data_key=encrypted_data_key, keyring_trace=keyring_trace) return encryption_materials def on_decrypt(self, decryption_materials, encrypted_data_keys): @@ -174,50 +187,51 @@ def on_decrypt(self, decryption_materials, encrypted_data_keys): :returns: Optionally modified decryption materials :rtype: aws_encryption_sdk.materials_managers.DecryptionMaterials """ - if decryption_materials.data_encryption_key: + if decryption_materials.data_encryption_key is not None: return decryption_materials # Decrypt data key expected_key_info_len = len(self._key_info_prefix) + self._wrapping_algorithm.algorithm.iv_len for key in encrypted_data_keys: + + if decryption_materials.data_encryption_key is not None: + return decryption_materials + if ( - key.key_provider.provider_id == self._key_provider.provider_id - and len(key.key_provider.key_info) == expected_key_info_len - and key.key_provider.key_info.startswith(self._key_info_prefix) + key.key_provider.provider_id != self._key_provider.provider_id + or len(key.key_provider.key_info) != expected_key_info_len + or not key.key_provider.key_info.startswith(self._key_info_prefix) ): - # Wrapped EncryptedDataKey to deserialized EncryptedData - encrypted_wrapped_key = deserialize_wrapped_key( - wrapping_algorithm=self._wrapping_algorithm, - wrapping_key_id=self.key_name, - wrapped_encrypted_key=key, + continue + + # Wrapped EncryptedDataKey to deserialized EncryptedData + encrypted_wrapped_key = deserialize_wrapped_key( + wrapping_algorithm=self._wrapping_algorithm, wrapping_key_id=self.key_name, wrapped_encrypted_key=key + ) + + # EncryptedData to raw key string + try: + plaintext_data_key = self._wrapping_key_structure.decrypt( + encrypted_wrapped_data_key=encrypted_wrapped_key, + encryption_context=decryption_materials.encryption_context, ) - # EncryptedData to raw key string - try: - plaintext_data_key = self._wrapping_key_structure.decrypt( - encrypted_wrapped_data_key=encrypted_wrapped_key, - encryption_context=decryption_materials.encryption_context, - ) - - except Exception as error: # pylint: disable=broad-except - logger = logging.getLogger(__name__) - logger.error(error.__class__.__name__, ":", str(error)) - return decryption_materials - - if plaintext_data_key: - # Create a keyring trace - keyring_trace = KeyringTrace( - wrapping_key=self._key_provider, flags={KeyringTraceFlag.WRAPPING_KEY_DECRYPTED_DATA_KEY} - ) - - # Update decryption materials - data_encryption_key = RawDataKey( - key_provider=MasterKeyInfo(provider_id=self._key_provider.provider_id, key_info=self.key_name), - data_key=plaintext_data_key, - ) - decryption_materials.add_data_encryption_key(data_encryption_key, keyring_trace) - - if decryption_materials.data_encryption_key: - return decryption_materials + + except Exception: # pylint: disable=broad-except + error_message = "Raw AES Keyring unable to decrypt data key" + _LOGGER.exception(error_message) + return decryption_materials + + # Create a keyring trace + keyring_trace = KeyringTrace( + wrapping_key=self._key_provider, flags={KeyringTraceFlag.WRAPPING_KEY_DECRYPTED_DATA_KEY} + ) + + # Update decryption materials + data_encryption_key = RawDataKey( + key_provider=MasterKeyInfo(provider_id=self._key_provider.provider_id, key_info=self.key_name), + data_key=plaintext_data_key, + ) + decryption_materials.add_data_encryption_key(data_encryption_key, keyring_trace) return decryption_materials @@ -228,59 +242,99 @@ class RawRSAKeyring(Keyring): :param str key_namespace: String defining the keyring ID :param bytes key_name: Key ID - :param wrapping_key: Encryption key with which to wrap plaintext data key - :type wrapping_key: object + :param _private_wrapping_key: Private encryption key with which to wrap plaintext data key (optional) + :type _private_wrapping_key: RSAPrivateKey + :param _public_wrapping_key: Public encryption key with which to wrap plaintext data key (optional) + :type _public_wrapping_key: RSAPublicKey :param wrapping_algorithm: Wrapping Algorithm with which to wrap plaintext data key :type wrapping_algorithm: WrappingAlgorithm :param key_provider: Complete information about the key in the keyring :type key_provider: MasterKeyInfo """ - key_namespace = attr.ib(validator=attr.validators.instance_of(six.string_types)) - key_name = attr.ib(validator=attr.validators.instance_of(six.binary_type)) - # _wrapping_key = attr.ib(repr=False, validator=attr.validators.in_([rsa.RSAPrivateKey, rsa.RSAPublicKey])) - # ----- need to figure out how to do this correctly - _wrapping_key = attr.ib(repr=False, validator=attr.validators.instance_of(object)) - _wrapping_algorithm = attr.ib(repr=False, validator=attr.validators.instance_of(WrappingAlgorithm)) + key_namespace = attr.ib(validator=instance_of(six.string_types)) + key_name = attr.ib(validator=instance_of(six.binary_type)) + _wrapping_algorithm = attr.ib(repr=False, validator=instance_of(WrappingAlgorithm)) + _private_wrapping_key = attr.ib(default=None, repr=False, validator=optional(instance_of(rsa.RSAPrivateKey))) + _public_wrapping_key = attr.ib(default=None, repr=False, validator=optional(instance_of(rsa.RSAPublicKey))) @classmethod - def fromPEMEncoding(cls, key_namespace, key_name, encoded_key, password, wrapping_algorithm): - # key_namespace = attr.ib(validator=attr.validators.instance_of(six.string_types)) - # key_name = attr.ib(validator=attr.validators.instance_of(six.binary_type)) - # _encoded_key = attr.ib(validator=attr.validators.instance_of(six.binary_type)) - # _password = attr.ib(validator=attr.validators.optional(attr.validators.instance_of(six.binary_type))) - # _wrapping_algorithm = attr.ib(repr=False, validator=attr.validators.instance_of(WrappingAlgorithm)) - if password: - loaded_wrapping_key = serialization.load_pem_private_key( - data=encoded_key, password=password, backend=default_backend() + def fromPEMEncoding( + cls, + key_namespace, # type: str + key_name, # type: bytes + wrapping_algorithm, # type: WrappingAlgorithm + public_encoded_key=None, # type: bytes + private_encoded_key=None, # type: bytes + password=None, # type: bytes + ): + # type: (...) -> RawRSAKeyring + """Generate a raw RSA keyring using a key with PEM Encoding + + :param str key_namespace: String defining the keyring ID + :param bytes key_name: Key ID + :param wrapping_algorithm: Wrapping Algorithm with which to wrap plaintext data key + :type wrapping_algorithm: WrappingAlgorithm + :param bytes public_encoded_key: PEM encoded public key (optional) + :param bytes private_encoded_key: PEM encoded private key (optional) + :param bytes password: Password to load private key (optional) + :return: Calls RawRSAKeyring class with required parameters + """ + loaded_private_wrapping_key = loaded_public_wrapping_key = None + if private_encoded_key is not None: + loaded_private_wrapping_key = serialization.load_pem_private_key( + data=private_encoded_key, password=password, backend=default_backend() + ) + if public_encoded_key is not None: + loaded_public_wrapping_key = serialization.load_pem_public_key( + data=public_encoded_key, backend=default_backend() ) - else: - loaded_wrapping_key = serialization.load_pem_public_key(data=encoded_key, backend=default_backend()) + return cls( key_namespace=key_namespace, key_name=key_name, - wrapping_key=loaded_wrapping_key, wrapping_algorithm=wrapping_algorithm, + private_wrapping_key=loaded_private_wrapping_key, + public_wrapping_key=loaded_public_wrapping_key, ) @classmethod - def fromDEREncoding(cls, key_namespace, key_name, encoded_key, password, wrapping_algorithm): - # key_namespace = attr.ib(validator=attr.validators.instance_of(six.string_types)) - # key_name = attr.ib(validator=attr.validators.instance_of(six.binary_type)) - # _encoded_key = attr.ib(validator=attr.validators.instance_of(six.binary_type)) - # _password = attr.ib(validator=attr.validators.optional(attr.validators.instance_of(six.binary_type))) - # _wrapping_algorithm = attr.ib(repr=False, validator=attr.validators.instance_of(WrappingAlgorithm)) - if password: - loaded_wrapping_key = serialization.load_der_private_key( - data=encoded_key, password=password, backend=default_backend() + def fromDEREncoding( + cls, + key_namespace, # type: str + key_name, # type: bytes + wrapping_algorithm, # type: WrappingAlgorithm + public_encoded_key=None, # type: bytes + private_encoded_key=None, # type: bytes + password=None, # type: bytes + ): + """Generate a raw RSA keyring using a key with DER Encoding + + :param str key_namespace: String defining the keyring ID + :param bytes key_name: Key ID + :param wrapping_algorithm: Wrapping Algorithm with which to wrap plaintext data key + :type wrapping_algorithm: WrappingAlgorithm + :param bytes public_encoded_key: DER encoded public key (optional) + :param bytes private_encoded_key: DER encoded private key (optional) + :param password: Password to load private key (optional) + :return: Calls RawRSAKeyring class with required parameters + """ + loaded_private_wrapping_key = loaded_public_wrapping_key = None + if private_encoded_key is not None: + loaded_private_wrapping_key = serialization.load_der_private_key( + data=private_encoded_key, password=password, backend=default_backend() ) - else: - loaded_wrapping_key = serialization.load_der_public_key(data=encoded_key, backend=default_backend()) + if public_encoded_key is not None: + loaded_public_wrapping_key = serialization.load_der_public_key( + data=public_encoded_key, backend=default_backend() + ) + return cls( key_namespace=key_namespace, key_name=key_name, - wrapping_key=loaded_wrapping_key, wrapping_algorithm=wrapping_algorithm, + private_wrapping_key=loaded_private_wrapping_key, + public_wrapping_key=loaded_public_wrapping_key, ) def __attrs_post_init__(self): @@ -288,6 +342,12 @@ def __attrs_post_init__(self): """Prepares initial values not handled by attrs.""" self._key_provider = MasterKeyInfo(provider_id=self.key_namespace, key_info=self.key_name) + if self._public_wrapping_key is None and self._private_wrapping_key is None: + raise TypeError("At least one of public key or private key must be provided.") + + if self._private_wrapping_key is not None: + self._public_wrapping_key = self._private_wrapping_key.public_key() + def on_encrypt(self, encryption_materials): # type: (EncryptionMaterials) -> EncryptionMaterials """Generate a data key if not present and encrypt it using any available wrapping key. @@ -297,31 +357,32 @@ def on_encrypt(self, encryption_materials): :returns: Optionally modified encryption materials. :rtype: aws_encryption_sdk.materials_managers.EncryptionMaterials """ - if not encryption_materials.data_encryption_key: - plaintext_data_key = generate_data_key( + if encryption_materials.data_encryption_key is None: + plaintext_generated = generate_data_key( encryption_materials=encryption_materials, key_provider=self._key_provider ) - else: - plaintext_data_key = encryption_materials.data_encryption_key.data_key - if isinstance(self._wrapping_key, rsa.RSAPublicKey): - # Encrypt data key - encrypted_wrapped_key = EncryptedData( - iv=None, - ciphertext=self._wrapping_key.encrypt( - plaintext=plaintext_data_key, padding=self._wrapping_algorithm.padding - ), - tag=None, - ) - else: - # Encrypt data key + # Check if data key exists + if not plaintext_generated or plaintext_generated is None: + raise GenerateKeyError("Unable to generate data encryption key.") + + if self._public_wrapping_key is None: + return encryption_materials + + # Encrypt data key + try: encrypted_wrapped_key = EncryptedData( iv=None, - ciphertext=self._wrapping_key.public_key().encrypt( - plaintext=plaintext_data_key, padding=self._wrapping_algorithm.padding + ciphertext=self._public_wrapping_key.encrypt( + plaintext=encryption_materials.data_encryption_key.data_key, + padding=self._wrapping_algorithm.padding, ), tag=None, ) + except Exception: # pylint: disable=broad-except + error_message = "Raw RSA Keyring unable to encrypt data key" + _LOGGER.exception(error_message) + return encryption_materials # EncryptedData to EncryptedDataKey encrypted_data_key = serialize_wrapped_key( @@ -332,15 +393,12 @@ def on_encrypt(self, encryption_materials): ) # Update Keyring Trace - if encrypted_data_key: - keyring_trace = KeyringTrace( - wrapping_key=encrypted_data_key.key_provider, flags={KeyringTraceFlag.WRAPPING_KEY_ENCRYPTED_DATA_KEY} - ) + keyring_trace = KeyringTrace( + wrapping_key=encrypted_data_key.key_provider, flags={KeyringTraceFlag.WRAPPING_KEY_ENCRYPTED_DATA_KEY} + ) - # Add encrypted data key to encryption_materials - encryption_materials.add_encrypted_data_key( - encrypted_data_key=encrypted_data_key, keyring_trace=keyring_trace - ) + # Add encrypted data key to encryption_materials + encryption_materials.add_encrypted_data_key(encrypted_data_key=encrypted_data_key, keyring_trace=keyring_trace) return encryption_materials @@ -355,40 +413,40 @@ def on_decrypt(self, decryption_materials, encrypted_data_keys): :returns: Optionally modified decryption materials. :rtype: aws_encryption_sdk.materials_managers.DecryptionMaterials """ - if isinstance(self._wrapping_key, rsa.RSAPrivateKey): - # Decrypt data key - for key in encrypted_data_keys: - if key.key_provider == self._key_provider: - # Wrapped EncryptedDataKey to deserialized EncryptedData - encrypted_wrapped_key = deserialize_wrapped_key( - wrapping_algorithm=self._wrapping_algorithm, - wrapping_key_id=self.key_name, - wrapped_encrypted_key=key, - ) - try: - plaintext_data_key = self._wrapping_key.decrypt( - ciphertext=encrypted_wrapped_key.ciphertext, padding=self._wrapping_algorithm.padding - ) - except Exception as error: # pylint: disable=broad-except - logger = logging.getLogger() - logger.error(error.__class__.__name__, ":", str(error)) - return decryption_materials - - if plaintext_data_key: - # Create a keyring trace - keyring_trace = KeyringTrace( - wrapping_key=self._key_provider, flags={KeyringTraceFlag.WRAPPING_KEY_DECRYPTED_DATA_KEY} - ) - - # Update decryption materials - data_encryption_key = RawDataKey( - key_provider=MasterKeyInfo( - provider_id=self._key_provider.provider_id, key_info=self.key_name - ), - data_key=plaintext_data_key, - ) - decryption_materials.add_data_encryption_key(data_encryption_key, keyring_trace) - if decryption_materials.data_encryption_key: - return decryption_materials + if self._private_wrapping_key is None: + return decryption_materials + + # Decrypt data key + for key in encrypted_data_keys: + if decryption_materials.data_encryption_key is not None: + print("DEC MAT") + return decryption_materials + if key.key_provider != self._key_provider: + print("PROVIDER PROB") + continue + # Wrapped EncryptedDataKey to deserialized EncryptedData + encrypted_wrapped_key = deserialize_wrapped_key( + wrapping_algorithm=self._wrapping_algorithm, wrapping_key_id=self.key_name, wrapped_encrypted_key=key + ) + try: + plaintext_data_key = self._private_wrapping_key.decrypt( + ciphertext=encrypted_wrapped_key.ciphertext, padding=self._wrapping_algorithm.padding + ) + except Exception: # pylint: disable=broad-except + error_message = "Raw RSA Keyring unable to decrypt data key" + _LOGGER.exception(error_message) + continue + + # Create a keyring trace + keyring_trace = KeyringTrace( + wrapping_key=self._key_provider, flags={KeyringTraceFlag.WRAPPING_KEY_DECRYPTED_DATA_KEY} + ) + + # Update decryption materials + data_encryption_key = RawDataKey( + key_provider=MasterKeyInfo(provider_id=self._key_provider.provider_id, key_info=self.key_name), + data_key=plaintext_data_key, + ) + decryption_materials.add_data_encryption_key(data_encryption_key, keyring_trace) return decryption_materials diff --git a/test/functional/test_f_multi_keyring.py b/test/functional/test_f_multi_keyring.py index ab1e0c25f..b9e48ac6f 100644 --- a/test/functional/test_f_multi_keyring.py +++ b/test/functional/test_f_multi_keyring.py @@ -92,13 +92,13 @@ key_namespace=_PROVIDER_ID, key_name=_KEY_ID, wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, - wrapping_key=rsa.generate_private_key(public_exponent=65537, key_size=2048, backend=default_backend()), + private_wrapping_key=rsa.generate_private_key(public_exponent=65537, key_size=2048, backend=default_backend()), ), RawRSAKeyring( key_namespace=_PROVIDER_ID, key_name=_KEY_ID, wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, - wrapping_key=rsa.generate_private_key(public_exponent=65537, key_size=2048, backend=default_backend()), + private_wrapping_key=rsa.generate_private_key(public_exponent=65537, key_size=2048, backend=default_backend()), ), ], ), @@ -107,7 +107,7 @@ key_namespace=_PROVIDER_ID, key_name=_KEY_ID, wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, - wrapping_key=rsa.generate_private_key(public_exponent=65537, key_size=2048, backend=default_backend()), + private_wrapping_key=rsa.generate_private_key(public_exponent=65537, key_size=2048, backend=default_backend()), ) ), MultiKeyring( @@ -116,7 +116,7 @@ key_namespace=_PROVIDER_ID, key_name=_KEY_ID, wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, - wrapping_key=rsa.generate_private_key(public_exponent=65537, key_size=2048, backend=default_backend()), + private_wrapping_key=rsa.generate_private_key(public_exponent=65537, key_size=2048, backend=default_backend()), ), RawAESKeyring( key_namespace=_PROVIDER_ID, diff --git a/test/unit/test_keyring_multi.py b/test/unit/test_keyring_multi.py index 97584ee2a..b4c350a63 100644 --- a/test/unit/test_keyring_multi.py +++ b/test/unit/test_keyring_multi.py @@ -15,17 +15,23 @@ import pytest import six from mock import MagicMock, patch, sentinel +from cryptography.hazmat.backends import default_backend +from cryptography.hazmat.primitives.asymmetric import rsa from aws_encryption_sdk.exceptions import GenerateKeyError, EncryptKeyError from aws_encryption_sdk.identifiers import Algorithm, KeyringTraceFlag, WrappingAlgorithm from aws_encryption_sdk.keyring.base import EncryptedDataKey, Keyring from aws_encryption_sdk.keyring.multi_keyring import MultiKeyring -from aws_encryption_sdk.keyring.raw_keyring import RawAESKeyring +from aws_encryption_sdk.keyring.raw_keyring import RawAESKeyring, RawRSAKeyring from aws_encryption_sdk.materials_managers import DecryptionMaterials, EncryptionMaterials from aws_encryption_sdk.structures import KeyringTrace, MasterKeyInfo, RawDataKey -from .test_utils import _MULTI_KEYRING_WITH_NO_GENERATOR, _ENCRYPTION_MATERIALS_WITHOUT_DATA_KEY, \ - _MULTI_KEYRING, _ENCRYPTION_MATERIALS_WITH_DATA_KEY +from pytest_mock import mocker # noqa pylint: disable=unused-import + +from .test_utils import get_encryption_materials_without_data_key, get_encryption_materials_with_data_key, \ + get_multi_keyring_with_generator_and_children, get_multi_keyring_with_no_children, \ + get_multi_keyring_with_no_generator, get_identity_keyring, get_decryption_materials_with_data_key, \ + get_decryption_materials_without_data_key try: # Python 3.5.0 and 3.5.1 have incompatible typing modules from typing import Iterable # noqa pylint: disable=unused-import @@ -35,12 +41,26 @@ pytestmark = [pytest.mark.unit, pytest.mark.local] + +# @pytest.fixture +# def patch_on_encrypt(mocker): +# mocker.patch.object(RawAESKeyring, "on_encrypt") +# return RawAESKeyring.on_encrypt + + _ENCRYPTION_CONTEXT = {"encryption": "context", "values": "here"} _PROVIDER_ID = "Random Raw Keys" _KEY_ID = b"5325b043-5843-4629-869c-64794af77ada" -_WRAPPING_KEY = b"\xeby-\x80A6\x15rA8\x83#,\xe4\xab\xac`\xaf\x99Z\xc1\xce\xdb\xb6\x0f\xb7\x805\xb2\x14J3" +_WRAPPING_KEY_AES = b"\xeby-\x80A6\x15rA8\x83#,\xe4\xab\xac`\xaf\x99Z\xc1\xce\xdb\xb6\x0f\xb7\x805\xb2\x14J3" _SIGNING_KEY = b"aws-crypto-public-key" +mock_generator = MagicMock() +mock_generator.__class__ = RawAESKeyring +mock_child_1 = MagicMock() +mock_child_1.__class__ = RawAESKeyring +mock_child_2 = MagicMock() +mock_child_2.__class__ = RawAESKeyring + def test_parent(): assert issubclass(MultiKeyring, Keyring) @@ -49,9 +69,27 @@ def test_parent(): def test_keyring_with_generator_but_no_children(): test_multi_keyring = MultiKeyring( generator=RawAESKeyring( - + key_namespace=_PROVIDER_ID, + key_name=_KEY_ID, + wrapping_key=_WRAPPING_KEY_AES, + wrapping_algorithm=WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING ) ) + assert isinstance(test_multi_keyring.generator,RawAESKeyring) + + +def test_keyring_with_children_but_no_generator(): + test_multi_keyring = MultiKeyring( + children=[ + RawAESKeyring( + key_namespace=_PROVIDER_ID, + key_name=_KEY_ID, + wrapping_key=_WRAPPING_KEY_AES, + wrapping_algorithm=WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING + ) + ] + ) + assert isinstance(test_multi_keyring.children, list) def test_keyring_with_no_generator_no_children(): @@ -70,29 +108,70 @@ def test_children_not_keyrings(): assert exc_info.errisinstance(TypeError) -def test_no_generator_no_data_encryption_key(): - test_multi_keyring = _MULTI_KEYRING_WITH_NO_GENERATOR +def test_on_encrypt_with_no_generator_no_data_encryption_key(): + test_multi_keyring = get_multi_keyring_with_no_generator() with pytest.raises(EncryptKeyError) as exc_info: - test_multi_keyring.on_encrypt(encryption_materials=_ENCRYPTION_MATERIALS_WITHOUT_DATA_KEY) + test_multi_keyring.on_encrypt(encryption_materials=get_encryption_materials_without_data_key()) assert exc_info.match("Generator keyring not provided and encryption materials do not already " "contain a plaintext data key.") -@patch("aws_encryption_sdk.keyring.raw_keyring.generate_data_key") -def test_data_key_not_generated(mock_generate): - mock_generate.return_value = None - test_multi_keyring = _MULTI_KEYRING + +def test_identity_keyring_as_generator_and_no_data_encryption_key(): + test_multi_keyring = MultiKeyring( + generator=get_identity_keyring() + ) with pytest.raises(GenerateKeyError) as exc_info: - test_multi_keyring.on_encrypt(encryption_materials=_ENCRYPTION_MATERIALS_WITHOUT_DATA_KEY) - assert exc_info.match("Unable to generate data encryption key") + test_multi_keyring.on_encrypt(encryption_materials=get_encryption_materials_without_data_key()) + assert exc_info.match("Unable to generate data encryption key.") -def test_number_of_encrypted_data_keys_without_generator(): - test_multi_keyring = _MULTI_KEYRING_WITH_NO_GENERATOR - test = test_multi_keyring.on_encrypt(encryption_materials=_ENCRYPTION_MATERIALS_WITH_DATA_KEY) +def test_number_of_encrypted_data_keys_without_generator_with_children(): + test_multi_keyring = get_multi_keyring_with_no_generator() + test = test_multi_keyring.on_encrypt(encryption_materials=get_encryption_materials_with_data_key()) assert len(test.encrypted_data_keys) == len(test_multi_keyring.children) -def test_number_of_encrypted_data_keys_with_generator(): - test_multi_keyring = _MULTI_KEYRING - test = test_multi_keyring.on_encrypt(encryption_materials=_ENCRYPTION_MATERIALS_WITH_DATA_KEY) - assert len(test.encrypted_data_keys) == len(test_multi_keyring.children) + 1 +def test_number_of_encrypted_data_keys_without_children_with_generator(): + test_multi_keyring = get_multi_keyring_with_no_children() + test = test_multi_keyring.on_encrypt(encryption_materials=get_encryption_materials_with_data_key()) + assert len(test.encrypted_data_keys) == 1 + + +def test_number_of_encrypted_data_keys_with_generator_and_children(): + test_multi_keyring = get_multi_keyring_with_generator_and_children() + number_of_children = len(test_multi_keyring.children) + test = test_multi_keyring.on_encrypt(encryption_materials=get_encryption_materials_with_data_key()) + assert len(test.encrypted_data_keys) == number_of_children + 1 + + +def test_on_encrypt_when_data_encryption_key_given(): + test_multi_keyring = MultiKeyring( + generator=mock_generator, + children=[ + mock_child_1, + mock_child_2 + ] + ) + test = test_multi_keyring.on_encrypt(encryption_materials=get_encryption_materials_with_data_key()) + mock_generator.on_encrypt.assert_called_once() + for keyring in test_multi_keyring.children: + keyring.on_encrypt.assert_called_once() + + +def test_on_decrypt_when_data_encryption_key_given(): + test_multi_keyring = MultiKeyring( + generator=mock_generator, + children=[ + mock_child_1, + mock_child_2 + ] + ) + test = test_multi_keyring.on_decrypt(decryption_materials=get_decryption_materials_with_data_key(), + encrypted_data_keys=[]) + mock_generator.on_decrypt.assert_not_called() + for keyring in test_multi_keyring.children: + keyring.on_decrypt.assert_not_called() + + +# def test_every_keyring_called_when_edk_not_added(): +# diff --git a/test/unit/test_multi_keyrings.py b/test/unit/test_multi_keyrings.py index 4d04552ec..417ecd051 100644 --- a/test/unit/test_multi_keyrings.py +++ b/test/unit/test_multi_keyrings.py @@ -1,107 +1,82 @@ -# Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"). You -# may not use this file except in compliance with the License. A copy of -# the License is located at -# -# http://aws.amazon.com/apache2.0/ -# -# or in the "license" file accompanying this file. This file is -# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF -# ANY KIND, either express or implied. See the License for the specific -# language governing permissions and limitations under the License. -"""Unit tests for Multi keyring.""" - -import pytest -from cryptography.hazmat.backends import default_backend -from cryptography.hazmat.primitives.asymmetric import rsa - -from aws_encryption_sdk.identifiers import WrappingAlgorithm -from aws_encryption_sdk.keyring.multi_keyring import MultiKeyring -from aws_encryption_sdk.keyring.raw_keyring import RawAESKeyring, RawRSAKeyring - -pytestmark = [pytest.mark.unit, pytest.mark.local] - -_ENCRYPTION_CONTEXT = {"encryption": "context", "values": "here"} -_PROVIDER_ID = "Random Raw Keys" -_KEY_ID = b"5325b043-5843-4629-869c-64794af77ada" -_WRAPPING_KEY_AES = b"\xeby-\x80A6\x15rA8\x83#,\xe4\xab\xac`\xaf\x99Z\xc1\xce\xdb\xb6\x0f\xb7\x805\xb2\x14J3" - -_SIGNING_KEY = b"aws-crypto-public-key" - -_raw_rsa_keyring_1 = RawRSAKeyring( - key_namespace=_PROVIDER_ID, - key_name=_KEY_ID, - wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, - wrapping_key=rsa.generate_private_key(public_exponent=65537, key_size=2048, backend=default_backend()), -) - -_raw_rsa_keyring_2 = RawRSAKeyring( - key_namespace=_PROVIDER_ID, - key_name=_KEY_ID, - wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, - wrapping_key=rsa.generate_private_key(public_exponent=65537, key_size=2048, backend=default_backend()), -) - -_raw_aes_keyring = RawAESKeyring( - key_namespace=_PROVIDER_ID, - key_name=_KEY_ID, - wrapping_algorithm=WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING, - wrapping_key=_WRAPPING_KEY_AES, -) - -_multi_keyring_no_children = MultiKeyring( - generator=RawRSAKeyring( - key_namespace=_PROVIDER_ID, - key_name=_KEY_ID, - wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, - wrapping_key=rsa.generate_private_key(public_exponent=65537, key_size=2048, backend=default_backend()), - ) -) - -_multi_keyring_no_generator = MultiKeyring( - children=[ - RawRSAKeyring( - key_namespace=_PROVIDER_ID, - key_name=_KEY_ID, - wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, - wrapping_key=rsa.generate_private_key(public_exponent=65537, key_size=2048, backend=default_backend()), - ), - RawAESKeyring( - key_namespace=_PROVIDER_ID, - key_name=_KEY_ID, - wrapping_algorithm=WrappingAlgorithm.AES_128_GCM_IV12_TAG16_NO_PADDING, - wrapping_key=_WRAPPING_KEY_AES, - ), - ] -) - -_multi_keyring = MultiKeyring( - generator=RawAESKeyring( - key_namespace=_PROVIDER_ID, - key_name=_KEY_ID, - wrapping_algorithm=WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING, - wrapping_key=_WRAPPING_KEY_AES, - ), - children=[ - RawRSAKeyring( - key_namespace=_PROVIDER_ID, - key_name=_KEY_ID, - wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, - wrapping_key=rsa.generate_private_key(public_exponent=65537, key_size=2048, backend=default_backend()), - ), - RawRSAKeyring( - key_namespace=_PROVIDER_ID, - key_name=_KEY_ID, - wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, - wrapping_key=rsa.generate_private_key(public_exponent=65537, key_size=2048, backend=default_backend()), - ), - ], -) - -# _multi_keyring_null = MultiKeyring() - -# _multi_keyring_children_not_keyrings = MultiKeyring( +# # Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# # +# # Licensed under the Apache License, Version 2.0 (the "License"). You +# # may not use this file except in compliance with the License. A copy of +# # the License is located at +# # +# # http://aws.amazon.com/apache2.0/ +# # +# # or in the "license" file accompanying this file. This file is +# # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF +# # ANY KIND, either express or implied. See the License for the specific +# # language governing permissions and limitations under the License. +# """Unit tests for Multi keyring.""" +# +# import pytest +# from cryptography.hazmat.backends import default_backend +# from cryptography.hazmat.primitives.asymmetric import rsa +# +# from aws_encryption_sdk.identifiers import WrappingAlgorithm +# from aws_encryption_sdk.keyring.multi_keyring import MultiKeyring +# from aws_encryption_sdk.keyring.raw_keyring import RawAESKeyring, RawRSAKeyring +# +# pytestmark = [pytest.mark.unit, pytest.mark.local] +# +# _ENCRYPTION_CONTEXT = {"encryption": "context", "values": "here"} +# _PROVIDER_ID = "Random Raw Keys" +# _KEY_ID = b"5325b043-5843-4629-869c-64794af77ada" +# _WRAPPING_KEY_AES = b"\xeby-\x80A6\x15rA8\x83#,\xe4\xab\xac`\xaf\x99Z\xc1\xce\xdb\xb6\x0f\xb7\x805\xb2\x14J3" +# +# _SIGNING_KEY = b"aws-crypto-public-key" +# +# _raw_rsa_keyring_1 = RawRSAKeyring( +# key_namespace=_PROVIDER_ID, +# key_name=_KEY_ID, +# wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, +# wrapping_key=rsa.generate_private_key(public_exponent=65537, key_size=2048, backend=default_backend()), +# ) +# +# _raw_rsa_keyring_2 = RawRSAKeyring( +# key_namespace=_PROVIDER_ID, +# key_name=_KEY_ID, +# wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, +# wrapping_key=rsa.generate_private_key(public_exponent=65537, key_size=2048, backend=default_backend()), +# ) +# +# _raw_aes_keyring = RawAESKeyring( +# key_namespace=_PROVIDER_ID, +# key_name=_KEY_ID, +# wrapping_algorithm=WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING, +# wrapping_key=_WRAPPING_KEY_AES, +# ) +# +# _multi_keyring_no_children = MultiKeyring( +# generator=RawRSAKeyring( +# key_namespace=_PROVIDER_ID, +# key_name=_KEY_ID, +# wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, +# wrapping_key=rsa.generate_private_key(public_exponent=65537, key_size=2048, backend=default_backend()), +# ) +# ) +# +# _multi_keyring_no_generator = MultiKeyring( +# children=[ +# RawRSAKeyring( +# key_namespace=_PROVIDER_ID, +# key_name=_KEY_ID, +# wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, +# wrapping_key=rsa.generate_private_key(public_exponent=65537, key_size=2048, backend=default_backend()), +# ), +# RawAESKeyring( +# key_namespace=_PROVIDER_ID, +# key_name=_KEY_ID, +# wrapping_algorithm=WrappingAlgorithm.AES_128_GCM_IV12_TAG16_NO_PADDING, +# wrapping_key=_WRAPPING_KEY_AES, +# ), +# ] +# ) +# +# _multi_keyring = MultiKeyring( # generator=RawAESKeyring( # key_namespace=_PROVIDER_ID, # key_name=_KEY_ID, @@ -115,34 +90,59 @@ # wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, # wrapping_key=rsa.generate_private_key(public_exponent=65537, key_size=2048, backend=default_backend()), # ), -# WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, +# RawRSAKeyring( +# key_namespace=_PROVIDER_ID, +# key_name=_KEY_ID, +# wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, +# wrapping_key=rsa.generate_private_key(public_exponent=65537, key_size=2048, backend=default_backend()), +# ), # ], # ) - - -# def test_null_multi_keyring(): -# class NullMultiKeyring(_multi_keyring_null): -# assert pytest.raises(TypeError) - -# with pytest.raises(TypeError) as exc_info: -# NullMultiKeyring() -# assert exc_info.match("At least one of generator or children must be provided") - - -# def test_no_generator_multi_keyring(): -# class NoGeneratorKeyring(_multi_keyring_no_generator): -# assert not pytest.raises(TypeError) -# -# -# def test_no_children_multi_keyring(): -# class NoChildrenKeyring(_multi_keyring_no_children): -# assert not pytest.raises(TypeError) - - -# def test_children_not_keyrings(): -# class ChildrenNotKeyrings(_multi_keyring_children_not_keyrings): -# pass -# -# with pytest.raises(TypeError) as exc_info: -# ChildrenNotKeyrings() -# assert exc_info.match("Children must me a keyring") +# +# # _multi_keyring_null = MultiKeyring() +# +# # _multi_keyring_children_not_keyrings = MultiKeyring( +# # generator=RawAESKeyring( +# # key_namespace=_PROVIDER_ID, +# # key_name=_KEY_ID, +# # wrapping_algorithm=WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING, +# # wrapping_key=_WRAPPING_KEY_AES, +# # ), +# # children=[ +# # RawRSAKeyring( +# # key_namespace=_PROVIDER_ID, +# # key_name=_KEY_ID, +# # wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, +# # wrapping_key=rsa.generate_private_key(public_exponent=65537, key_size=2048, backend=default_backend()), +# # ), +# # WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, +# # ], +# # ) +# +# +# # def test_null_multi_keyring(): +# # class NullMultiKeyring(_multi_keyring_null): +# # assert pytest.raises(TypeError) +# +# # with pytest.raises(TypeError) as exc_info: +# # NullMultiKeyring() +# # assert exc_info.match("At least one of generator or children must be provided") +# +# +# # def test_no_generator_multi_keyring(): +# # class NoGeneratorKeyring(_multi_keyring_no_generator): +# # assert not pytest.raises(TypeError) +# # +# # +# # def test_no_children_multi_keyring(): +# # class NoChildrenKeyring(_multi_keyring_no_children): +# # assert not pytest.raises(TypeError) +# +# +# # def test_children_not_keyrings(): +# # class ChildrenNotKeyrings(_multi_keyring_children_not_keyrings): +# # pass +# # +# # with pytest.raises(TypeError) as exc_info: +# # ChildrenNotKeyrings() +# # assert exc_info.match("Children must me a keyring") diff --git a/test/unit/test_utils.py b/test/unit/test_utils.py index 2d412c4a3..8e8ea510a 100644 --- a/test/unit/test_utils.py +++ b/test/unit/test_utils.py @@ -25,7 +25,7 @@ from aws_encryption_sdk.exceptions import InvalidDataKeyError, SerializationError, UnknownIdentityError from aws_encryption_sdk.internal.defaults import MAX_FRAME_SIZE, MESSAGE_ID_LENGTH from aws_encryption_sdk.structures import DataKey, EncryptedDataKey, MasterKeyInfo, RawDataKey, KeyringTrace -from aws_encryption_sdk.keyring.raw_keyring import RawRSAKeyring, RawAESKeyring +from aws_encryption_sdk.keyring.raw_keyring import RawRSAKeyring, RawAESKeyring, Keyring from aws_encryption_sdk.keyring.multi_keyring import MultiKeyring from aws_encryption_sdk.identifiers import Algorithm, KeyringTraceFlag, WrappingAlgorithm from aws_encryption_sdk.materials_managers import DecryptionMaterials, EncryptionMaterials @@ -36,6 +36,13 @@ pytestmark = [pytest.mark.unit, pytest.mark.local] +try: # Python 3.5.0 and 3.5.1 have incompatible typing modules + from typing import Iterable # noqa pylint: disable=unused-import +except ImportError: # pragma: no cover + # We only actually need these imports when running the mypy checks + pass + + _ENCRYPTION_CONTEXT = {"encryption": "context", "values": "here"} _PROVIDER_ID = "Random Raw Keys" _KEY_ID = b"5325b043-5843-4629-869c-64794af77ada" @@ -47,123 +54,147 @@ _WRAPPING_KEY_AES = b"\xeby-\x80A6\x15rA8\x83#,\xe4\xab\xac`\xaf\x99Z\xc1\xce\xdb\xb6\x0f\xb7\x805\xb2\x14J3" -_ENCRYPTION_MATERIALS_WITH_DATA_KEY = EncryptionMaterials( - algorithm=Algorithm.AES_256_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384, - data_encryption_key=RawDataKey( - key_provider=MasterKeyInfo(provider_id=_PROVIDER_ID, key_info=_KEY_ID), - data_key=b'*!\xa1"^-(\xf3\x105\x05i@B\xc2\xa2\xb7\xdd\xd5\xd5\xa9\xddm\xfae\xa8\\$\xf9d\x1e(', - ), - encryption_context=_ENCRYPTION_CONTEXT, - signing_key=_SIGNING_KEY, - keyring_trace=[ - KeyringTrace( - wrapping_key=MasterKeyInfo(provider_id=_PROVIDER_ID, key_info=_KEY_ID), - flags={KeyringTraceFlag.WRAPPING_KEY_GENERATED_DATA_KEY}, - ) - ], -) +class IdentityKeyring(Keyring): + def on_encrypt(self, encryption_materials): + # type: (EncryptionMaterials) -> EncryptionMaterials + return encryption_materials + def on_decrypt(self, decryption_materials, encrypted_data_keys): + # type: (DecryptionMaterials, Iterable[EncryptedDataKey]) -> DecryptionMaterials + return decryption_materials -_ENCRYPTION_MATERIALS_WITHOUT_DATA_KEY = EncryptionMaterials( - algorithm=Algorithm.AES_256_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384, - encryption_context=_ENCRYPTION_CONTEXT, - signing_key=_SIGNING_KEY, -) +def get_identity_keyring(): + return IdentityKeyring() -_ENCRYPTION_MATERIALS_WITH_ENCRYPTED_DATA_KEY = EncryptionMaterials( - algorithm=Algorithm.AES_256_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384, - data_encryption_key=RawDataKey( - key_provider=MasterKeyInfo(provider_id=_PROVIDER_ID, key_info=_KEY_ID), - data_key=b'*!\xa1"^-(\xf3\x105\x05i@B\xc2\xa2\xb7\xdd\xd5\xd5\xa9\xddm\xfae\xa8\\$\xf9d\x1e(', - ), - encrypted_data_keys=[ - EncryptedDataKey( - key_provider=MasterKeyInfo(provider_id=_PROVIDER_ID, key_info=_KEY_ID), - encrypted_data_key=b"\xde^\x97\x7f\x84\xe9\x9e\x98\xd0\xe2\xf8\xd5\xcb\xe9\x7f.}\x87\x16,\x11n#\xc8p" - b"\xdb\xbf\x94\x86*Q\x06\xd2\xf5\xdah\x08\xa4p\x81\xf7\xf4G\x07FzE\xde", - ) - ], - encryption_context=_ENCRYPTION_CONTEXT, - signing_key=_SIGNING_KEY, - keyring_trace=[ - KeyringTrace( - wrapping_key=MasterKeyInfo(provider_id=_PROVIDER_ID, key_info=_KEY_ID), - flags={KeyringTraceFlag.WRAPPING_KEY_GENERATED_DATA_KEY, KeyringTraceFlag.WRAPPING_KEY_ENCRYPTED_DATA_KEY}, - ) - ], -) +def get_encryption_materials_with_data_key(): + return EncryptionMaterials( + algorithm=Algorithm.AES_256_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384, + data_encryption_key=RawDataKey( + key_provider=MasterKeyInfo(provider_id=_PROVIDER_ID, key_info=_KEY_ID), + data_key=b'*!\xa1"^-(\xf3\x105\x05i@B\xc2\xa2\xb7\xdd\xd5\xd5\xa9\xddm\xfae\xa8\\$\xf9d\x1e(', + ), + encryption_context=_ENCRYPTION_CONTEXT, + signing_key=_SIGNING_KEY, + keyring_trace=[ + KeyringTrace( + wrapping_key=MasterKeyInfo(provider_id=_PROVIDER_ID, key_info=_KEY_ID), + flags={KeyringTraceFlag.WRAPPING_KEY_GENERATED_DATA_KEY}, + ) + ], + ) -_DECRYPTION_MATERIALS_WITH_DATA_KEY = DecryptionMaterials( - algorithm=Algorithm.AES_256_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384, - data_encryption_key=RawDataKey( - key_provider=MasterKeyInfo(provider_id=_PROVIDER_ID, key_info=_KEY_ID), - data_key=b'*!\xa1"^-(\xf3\x105\x05i@B\xc2\xa2\xb7\xdd\xd5\xd5\xa9\xddm\xfae\xa8\\$\xf9d\x1e(', - ), - encryption_context=_ENCRYPTION_CONTEXT, - verification_key=b"ex_verification_key", - keyring_trace=[KeyringTrace( - wrapping_key=MasterKeyInfo(provider_id=_PROVIDER_ID, key_info=_KEY_ID), - flags={KeyringTraceFlag.WRAPPING_KEY_DECRYPTED_DATA_KEY} - )] -) +def get_encryption_materials_without_data_key(): + return EncryptionMaterials( + algorithm=Algorithm.AES_256_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384, + encryption_context=_ENCRYPTION_CONTEXT, + signing_key=_SIGNING_KEY, + ) -_DECRYPTION_MATERIALS_WITHOUT_DATA_KEY = DecryptionMaterials( - verification_key=b"ex_verification_key", -) -_MULTI_KEYRING = MultiKeyring( - generator=RawAESKeyring( - key_namespace=_PROVIDER_ID, - key_name=_KEY_ID, - wrapping_algorithm=WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING, - wrapping_key=_WRAPPING_KEY_AES, +def get_encryption_materials_with_encrypted_data_key(): + return EncryptionMaterials( + algorithm=Algorithm.AES_256_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384, + data_encryption_key=RawDataKey( + key_provider=MasterKeyInfo(provider_id=_PROVIDER_ID, key_info=_KEY_ID), + data_key=b'*!\xa1"^-(\xf3\x105\x05i@B\xc2\xa2\xb7\xdd\xd5\xd5\xa9\xddm\xfae\xa8\\$\xf9d\x1e(', ), - children=[ - RawRSAKeyring( - key_namespace=_PROVIDER_ID, - key_name=_KEY_ID, - wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, - wrapping_key=rsa.generate_private_key(public_exponent=65537, key_size=2048, backend=default_backend()), - ), - RawRSAKeyring( - key_namespace=_PROVIDER_ID, - key_name=_KEY_ID, - wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, - wrapping_key=rsa.generate_private_key(public_exponent=65537, key_size=2048, backend=default_backend()), - ), + encrypted_data_keys=[ + EncryptedDataKey( + key_provider=MasterKeyInfo(provider_id=_PROVIDER_ID, key_info=_KEY_ID), + encrypted_data_key=b"\xde^\x97\x7f\x84\xe9\x9e\x98\xd0\xe2\xf8\xd5\xcb\xe9\x7f.}\x87\x16,\x11n#\xc8p" + b"\xdb\xbf\x94\x86*Q\x06\xd2\xf5\xdah\x08\xa4p\x81\xf7\xf4G\x07FzE\xde", + ) + ], + encryption_context=_ENCRYPTION_CONTEXT, + signing_key=_SIGNING_KEY, + keyring_trace=[ + KeyringTrace( + wrapping_key=MasterKeyInfo(provider_id=_PROVIDER_ID, key_info=_KEY_ID), + flags={KeyringTraceFlag.WRAPPING_KEY_GENERATED_DATA_KEY, KeyringTraceFlag.WRAPPING_KEY_ENCRYPTED_DATA_KEY}, + ) ], ) -_MULTI_KEYRING_WITH_NO_CHILDREN = MultiKeyring( - generator=RawRSAKeyring( - key_namespace=_PROVIDER_ID, - key_name=_KEY_ID, - wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, - wrapping_key=rsa.generate_private_key(public_exponent=65537, key_size=2048, backend=default_backend()), - ) + +def get_decryption_materials_with_data_key(): + return DecryptionMaterials( + algorithm=Algorithm.AES_256_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384, + data_encryption_key=RawDataKey( + key_provider=MasterKeyInfo(provider_id=_PROVIDER_ID, key_info=_KEY_ID), + data_key=b'*!\xa1"^-(\xf3\x105\x05i@B\xc2\xa2\xb7\xdd\xd5\xd5\xa9\xddm\xfae\xa8\\$\xf9d\x1e(', + ), + encryption_context=_ENCRYPTION_CONTEXT, + verification_key=b"ex_verification_key", + keyring_trace=[KeyringTrace( + wrapping_key=MasterKeyInfo(provider_id=_PROVIDER_ID, key_info=_KEY_ID), + flags={KeyringTraceFlag.WRAPPING_KEY_DECRYPTED_DATA_KEY} + )] + ) + + +def get_decryption_materials_without_data_key(): + return DecryptionMaterials( + encryption_context=_ENCRYPTION_CONTEXT, + verification_key=b"ex_verification_key", ) -_MULTI_KEYRING_WITH_NO_GENERATOR = MultiKeyring( - children=[ - RawRSAKeyring( + +def get_multi_keyring_with_generator_and_children(): + return MultiKeyring( + generator=RawAESKeyring( key_namespace=_PROVIDER_ID, key_name=_KEY_ID, - wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, - wrapping_key=rsa.generate_private_key(public_exponent=65537, key_size=2048, backend=default_backend()), + wrapping_algorithm=WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING, + wrapping_key=_WRAPPING_KEY_AES, ), - RawAESKeyring( + children=[ + RawRSAKeyring( + key_namespace=_PROVIDER_ID, + key_name=_KEY_ID, + wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, + private_wrapping_key=rsa.generate_private_key(public_exponent=65537, key_size=2048, backend=default_backend()), + ), + RawRSAKeyring( + key_namespace=_PROVIDER_ID, + key_name=_KEY_ID, + wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, + private_wrapping_key=rsa.generate_private_key(public_exponent=65537, key_size=2048, backend=default_backend()), + ), + ], + ) + + +def get_multi_keyring_with_no_children(): + return MultiKeyring( + generator=RawRSAKeyring( key_namespace=_PROVIDER_ID, key_name=_KEY_ID, - wrapping_algorithm=WrappingAlgorithm.AES_128_GCM_IV12_TAG16_NO_PADDING, - wrapping_key=_WRAPPING_KEY_AES, - ), - ] - ) + wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, + private_wrapping_key=rsa.generate_private_key(public_exponent=65537, key_size=2048, backend=default_backend()), + ) + ) + -# _MULTI_KEYRING_WITH_NO_GENERATOR_NO_CHILDREN = MultiKeyring() +def get_multi_keyring_with_no_generator(): + return MultiKeyring( + children=[ + RawRSAKeyring( + key_namespace=_PROVIDER_ID, + key_name=_KEY_ID, + wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, + private_wrapping_key=rsa.generate_private_key(public_exponent=65537, key_size=2048, backend=default_backend()), + ), + RawAESKeyring( + key_namespace=_PROVIDER_ID, + key_name=_KEY_ID, + wrapping_algorithm=WrappingAlgorithm.AES_128_GCM_IV12_TAG16_NO_PADDING, + wrapping_key=_WRAPPING_KEY_AES, + ), + ] + ) def test_prep_stream_data_passthrough(): From 65c749d660c00d56e74868d99c335422ac8da573 Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Sat, 27 Jul 2019 14:21:01 -0700 Subject: [PATCH 51/61] Unit tests for multi keyrings --- src/aws_encryption_sdk/keyring/raw_keyring.py | 3 + test/unit/test_keyring_multi.py | 26 ++- test/unit/test_multi_keyrings.py | 148 ------------------ test/unit/test_utils.py | 15 +- 4 files changed, 31 insertions(+), 161 deletions(-) delete mode 100644 test/unit/test_multi_keyrings.py diff --git a/src/aws_encryption_sdk/keyring/raw_keyring.py b/src/aws_encryption_sdk/keyring/raw_keyring.py index da4d93707..8d76be235 100644 --- a/src/aws_encryption_sdk/keyring/raw_keyring.py +++ b/src/aws_encryption_sdk/keyring/raw_keyring.py @@ -136,6 +136,7 @@ def on_encrypt(self, encryption_materials): :rtype: aws_encryption_sdk.materials_managers.EncryptionMaterials """ if encryption_materials.data_encryption_key is None: + print("Data key needs to be generated") plaintext_generated = generate_data_key( encryption_materials=encryption_materials, key_provider=self._key_provider ) @@ -144,6 +145,7 @@ def on_encrypt(self, encryption_materials): if not plaintext_generated or plaintext_generated is None: raise GenerateKeyError("Unable to generate data encryption key.") + print("Generated") # Encrypt data key encrypted_wrapped_key = self._wrapping_key_structure.encrypt( plaintext_data_key=encryption_materials.data_encryption_key.data_key, @@ -152,6 +154,7 @@ def on_encrypt(self, encryption_materials): # Check if encryption is successful if encrypted_wrapped_key is None: + print("Encrypted wrapped key None") return encryption_materials # EncryptedData to EncryptedDataKey diff --git a/test/unit/test_keyring_multi.py b/test/unit/test_keyring_multi.py index b4c350a63..2503487f4 100644 --- a/test/unit/test_keyring_multi.py +++ b/test/unit/test_keyring_multi.py @@ -22,7 +22,8 @@ from aws_encryption_sdk.identifiers import Algorithm, KeyringTraceFlag, WrappingAlgorithm from aws_encryption_sdk.keyring.base import EncryptedDataKey, Keyring from aws_encryption_sdk.keyring.multi_keyring import MultiKeyring -from aws_encryption_sdk.keyring.raw_keyring import RawAESKeyring, RawRSAKeyring +from aws_encryption_sdk.keyring.raw_keyring import RawAESKeyring, RawRSAKeyring, WrappingKey +from aws_encryption_sdk.internal.formatting import serialize from aws_encryption_sdk.materials_managers import DecryptionMaterials, EncryptionMaterials from aws_encryption_sdk.structures import KeyringTrace, MasterKeyInfo, RawDataKey @@ -42,12 +43,6 @@ pytestmark = [pytest.mark.unit, pytest.mark.local] -# @pytest.fixture -# def patch_on_encrypt(mocker): -# mocker.patch.object(RawAESKeyring, "on_encrypt") -# return RawAESKeyring.on_encrypt - - _ENCRYPTION_CONTEXT = {"encryption": "context", "values": "here"} _PROVIDER_ID = "Random Raw Keys" _KEY_ID = b"5325b043-5843-4629-869c-64794af77ada" @@ -62,6 +57,12 @@ mock_child_2.__class__ = RawAESKeyring +@pytest.fixture +def patch_encrypt(mocker): + mocker.patch.object(serialize, "serialize_raw_master_key_prefix") + return serialize.serialize_raw_master_key_prefix + + def test_parent(): assert issubclass(MultiKeyring, Keyring) @@ -158,6 +159,15 @@ def test_on_encrypt_when_data_encryption_key_given(): keyring.on_encrypt.assert_called_once() +def test_on_encrypt_edk_length_when_keyring_generates_but_does_not_encrypt(patch_encrypt): + patch_encrypt.side_effect = Exception("Raw AES Keyring unable to encrypt data key") + test_multi_keyring = get_multi_keyring_with_no_children() + test = test_multi_keyring.on_encrypt(encryption_materials=get_encryption_materials_without_data_key()) + assert test.data_encryption_key is not None + # print(test.encrypted_data_keys) + assert len(test.encrypted_data_keys) == len(get_encryption_materials_without_data_key().encrypted_data_keys) + + def test_on_decrypt_when_data_encryption_key_given(): test_multi_keyring = MultiKeyring( generator=mock_generator, @@ -172,6 +182,6 @@ def test_on_decrypt_when_data_encryption_key_given(): for keyring in test_multi_keyring.children: keyring.on_decrypt.assert_not_called() - +# # def test_every_keyring_called_when_edk_not_added(): # diff --git a/test/unit/test_multi_keyrings.py b/test/unit/test_multi_keyrings.py deleted file mode 100644 index 417ecd051..000000000 --- a/test/unit/test_multi_keyrings.py +++ /dev/null @@ -1,148 +0,0 @@ -# # Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. -# # -# # Licensed under the Apache License, Version 2.0 (the "License"). You -# # may not use this file except in compliance with the License. A copy of -# # the License is located at -# # -# # http://aws.amazon.com/apache2.0/ -# # -# # or in the "license" file accompanying this file. This file is -# # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF -# # ANY KIND, either express or implied. See the License for the specific -# # language governing permissions and limitations under the License. -# """Unit tests for Multi keyring.""" -# -# import pytest -# from cryptography.hazmat.backends import default_backend -# from cryptography.hazmat.primitives.asymmetric import rsa -# -# from aws_encryption_sdk.identifiers import WrappingAlgorithm -# from aws_encryption_sdk.keyring.multi_keyring import MultiKeyring -# from aws_encryption_sdk.keyring.raw_keyring import RawAESKeyring, RawRSAKeyring -# -# pytestmark = [pytest.mark.unit, pytest.mark.local] -# -# _ENCRYPTION_CONTEXT = {"encryption": "context", "values": "here"} -# _PROVIDER_ID = "Random Raw Keys" -# _KEY_ID = b"5325b043-5843-4629-869c-64794af77ada" -# _WRAPPING_KEY_AES = b"\xeby-\x80A6\x15rA8\x83#,\xe4\xab\xac`\xaf\x99Z\xc1\xce\xdb\xb6\x0f\xb7\x805\xb2\x14J3" -# -# _SIGNING_KEY = b"aws-crypto-public-key" -# -# _raw_rsa_keyring_1 = RawRSAKeyring( -# key_namespace=_PROVIDER_ID, -# key_name=_KEY_ID, -# wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, -# wrapping_key=rsa.generate_private_key(public_exponent=65537, key_size=2048, backend=default_backend()), -# ) -# -# _raw_rsa_keyring_2 = RawRSAKeyring( -# key_namespace=_PROVIDER_ID, -# key_name=_KEY_ID, -# wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, -# wrapping_key=rsa.generate_private_key(public_exponent=65537, key_size=2048, backend=default_backend()), -# ) -# -# _raw_aes_keyring = RawAESKeyring( -# key_namespace=_PROVIDER_ID, -# key_name=_KEY_ID, -# wrapping_algorithm=WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING, -# wrapping_key=_WRAPPING_KEY_AES, -# ) -# -# _multi_keyring_no_children = MultiKeyring( -# generator=RawRSAKeyring( -# key_namespace=_PROVIDER_ID, -# key_name=_KEY_ID, -# wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, -# wrapping_key=rsa.generate_private_key(public_exponent=65537, key_size=2048, backend=default_backend()), -# ) -# ) -# -# _multi_keyring_no_generator = MultiKeyring( -# children=[ -# RawRSAKeyring( -# key_namespace=_PROVIDER_ID, -# key_name=_KEY_ID, -# wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, -# wrapping_key=rsa.generate_private_key(public_exponent=65537, key_size=2048, backend=default_backend()), -# ), -# RawAESKeyring( -# key_namespace=_PROVIDER_ID, -# key_name=_KEY_ID, -# wrapping_algorithm=WrappingAlgorithm.AES_128_GCM_IV12_TAG16_NO_PADDING, -# wrapping_key=_WRAPPING_KEY_AES, -# ), -# ] -# ) -# -# _multi_keyring = MultiKeyring( -# generator=RawAESKeyring( -# key_namespace=_PROVIDER_ID, -# key_name=_KEY_ID, -# wrapping_algorithm=WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING, -# wrapping_key=_WRAPPING_KEY_AES, -# ), -# children=[ -# RawRSAKeyring( -# key_namespace=_PROVIDER_ID, -# key_name=_KEY_ID, -# wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, -# wrapping_key=rsa.generate_private_key(public_exponent=65537, key_size=2048, backend=default_backend()), -# ), -# RawRSAKeyring( -# key_namespace=_PROVIDER_ID, -# key_name=_KEY_ID, -# wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, -# wrapping_key=rsa.generate_private_key(public_exponent=65537, key_size=2048, backend=default_backend()), -# ), -# ], -# ) -# -# # _multi_keyring_null = MultiKeyring() -# -# # _multi_keyring_children_not_keyrings = MultiKeyring( -# # generator=RawAESKeyring( -# # key_namespace=_PROVIDER_ID, -# # key_name=_KEY_ID, -# # wrapping_algorithm=WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING, -# # wrapping_key=_WRAPPING_KEY_AES, -# # ), -# # children=[ -# # RawRSAKeyring( -# # key_namespace=_PROVIDER_ID, -# # key_name=_KEY_ID, -# # wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, -# # wrapping_key=rsa.generate_private_key(public_exponent=65537, key_size=2048, backend=default_backend()), -# # ), -# # WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, -# # ], -# # ) -# -# -# # def test_null_multi_keyring(): -# # class NullMultiKeyring(_multi_keyring_null): -# # assert pytest.raises(TypeError) -# -# # with pytest.raises(TypeError) as exc_info: -# # NullMultiKeyring() -# # assert exc_info.match("At least one of generator or children must be provided") -# -# -# # def test_no_generator_multi_keyring(): -# # class NoGeneratorKeyring(_multi_keyring_no_generator): -# # assert not pytest.raises(TypeError) -# # -# # -# # def test_no_children_multi_keyring(): -# # class NoChildrenKeyring(_multi_keyring_no_children): -# # assert not pytest.raises(TypeError) -# -# -# # def test_children_not_keyrings(): -# # class ChildrenNotKeyrings(_multi_keyring_children_not_keyrings): -# # pass -# # -# # with pytest.raises(TypeError) as exc_info: -# # ChildrenNotKeyrings() -# # assert exc_info.match("Children must me a keyring") diff --git a/test/unit/test_utils.py b/test/unit/test_utils.py index 8e8ea510a..972519871 100644 --- a/test/unit/test_utils.py +++ b/test/unit/test_utils.py @@ -113,7 +113,8 @@ def get_encryption_materials_with_encrypted_data_key(): keyring_trace=[ KeyringTrace( wrapping_key=MasterKeyInfo(provider_id=_PROVIDER_ID, key_info=_KEY_ID), - flags={KeyringTraceFlag.WRAPPING_KEY_GENERATED_DATA_KEY, KeyringTraceFlag.WRAPPING_KEY_ENCRYPTED_DATA_KEY}, + flags={KeyringTraceFlag.WRAPPING_KEY_GENERATED_DATA_KEY, KeyringTraceFlag + .WRAPPING_KEY_ENCRYPTED_DATA_KEY}, ) ], ) @@ -155,13 +156,15 @@ def get_multi_keyring_with_generator_and_children(): key_namespace=_PROVIDER_ID, key_name=_KEY_ID, wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, - private_wrapping_key=rsa.generate_private_key(public_exponent=65537, key_size=2048, backend=default_backend()), + private_wrapping_key=rsa.generate_private_key(public_exponent=65537, key_size=2048, + backend=default_backend()), ), RawRSAKeyring( key_namespace=_PROVIDER_ID, key_name=_KEY_ID, wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, - private_wrapping_key=rsa.generate_private_key(public_exponent=65537, key_size=2048, backend=default_backend()), + private_wrapping_key=rsa.generate_private_key(public_exponent=65537, key_size=2048, + backend=default_backend()), ), ], ) @@ -173,7 +176,8 @@ def get_multi_keyring_with_no_children(): key_namespace=_PROVIDER_ID, key_name=_KEY_ID, wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, - private_wrapping_key=rsa.generate_private_key(public_exponent=65537, key_size=2048, backend=default_backend()), + private_wrapping_key=rsa.generate_private_key(public_exponent=65537, key_size=2048, + backend=default_backend()), ) ) @@ -185,7 +189,8 @@ def get_multi_keyring_with_no_generator(): key_namespace=_PROVIDER_ID, key_name=_KEY_ID, wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, - private_wrapping_key=rsa.generate_private_key(public_exponent=65537, key_size=2048, backend=default_backend()), + private_wrapping_key=rsa.generate_private_key(public_exponent=65537, key_size=2048, + backend=default_backend()), ), RawAESKeyring( key_namespace=_PROVIDER_ID, From 317e0e5efa8c92bb896aa0a84a750f5b48930ab7 Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Sat, 27 Jul 2019 15:23:29 -0700 Subject: [PATCH 52/61] Unit tests for multi keyrings --- test/unit/test_keyring_multi.py | 11 ++++++----- test/unit/test_utils.py | 28 +++++++++++++++++++++++++++- 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/test/unit/test_keyring_multi.py b/test/unit/test_keyring_multi.py index 2503487f4..3c39eacc4 100644 --- a/test/unit/test_keyring_multi.py +++ b/test/unit/test_keyring_multi.py @@ -32,7 +32,7 @@ from .test_utils import get_encryption_materials_without_data_key, get_encryption_materials_with_data_key, \ get_multi_keyring_with_generator_and_children, get_multi_keyring_with_no_children, \ get_multi_keyring_with_no_generator, get_identity_keyring, get_decryption_materials_with_data_key, \ - get_decryption_materials_without_data_key + get_decryption_materials_without_data_key, get_keyring_which_only_generates try: # Python 3.5.0 and 3.5.1 have incompatible typing modules from typing import Iterable # noqa pylint: disable=unused-import @@ -153,15 +153,16 @@ def test_on_encrypt_when_data_encryption_key_given(): mock_child_2 ] ) - test = test_multi_keyring.on_encrypt(encryption_materials=get_encryption_materials_with_data_key()) + test_multi_keyring.on_encrypt(encryption_materials=get_encryption_materials_with_data_key()) mock_generator.on_encrypt.assert_called_once() for keyring in test_multi_keyring.children: keyring.on_encrypt.assert_called_once() -def test_on_encrypt_edk_length_when_keyring_generates_but_does_not_encrypt(patch_encrypt): - patch_encrypt.side_effect = Exception("Raw AES Keyring unable to encrypt data key") - test_multi_keyring = get_multi_keyring_with_no_children() +def test_on_encrypt_edk_length_when_keyring_generates_but_does_not_encrypt(): + test_multi_keyring = MultiKeyring( + generator=get_keyring_which_only_generates() + ) test = test_multi_keyring.on_encrypt(encryption_materials=get_encryption_materials_without_data_key()) assert test.data_encryption_key is not None # print(test.encrypted_data_keys) diff --git a/test/unit/test_utils.py b/test/unit/test_utils.py index 972519871..7607c269e 100644 --- a/test/unit/test_utils.py +++ b/test/unit/test_utils.py @@ -25,7 +25,7 @@ from aws_encryption_sdk.exceptions import InvalidDataKeyError, SerializationError, UnknownIdentityError from aws_encryption_sdk.internal.defaults import MAX_FRAME_SIZE, MESSAGE_ID_LENGTH from aws_encryption_sdk.structures import DataKey, EncryptedDataKey, MasterKeyInfo, RawDataKey, KeyringTrace -from aws_encryption_sdk.keyring.raw_keyring import RawRSAKeyring, RawAESKeyring, Keyring +from aws_encryption_sdk.keyring.raw_keyring import RawRSAKeyring, RawAESKeyring, Keyring, generate_data_key from aws_encryption_sdk.keyring.multi_keyring import MultiKeyring from aws_encryption_sdk.identifiers import Algorithm, KeyringTraceFlag, WrappingAlgorithm from aws_encryption_sdk.materials_managers import DecryptionMaterials, EncryptionMaterials @@ -64,10 +64,36 @@ def on_decrypt(self, decryption_materials, encrypted_data_keys): return decryption_materials +class OnlyGenerateKeyring(Keyring): + def on_encrypt(self, encryption_materials): + # type: (EncryptionMaterials) -> EncryptionMaterials + encryption_materials.data_encryption_key = RawDataKey( + key_provider=MasterKeyInfo( + provider_id=_PROVIDER_ID, + key_info=_KEY_ID + ), + data_key=generate_data_key(encryption_materials=encryption_materials, + key_provider=MasterKeyInfo( + provider_id=_PROVIDER_ID, + key_info=_KEY_ID + ) + ) + ) + return encryption_materials + + def on_decrypt(self, decryption_materials, encrypted_data_keys): + # type: (DecryptionMaterials, Iterable[EncryptedDataKey]) -> DecryptionMaterials + return decryption_materials + + def get_identity_keyring(): return IdentityKeyring() +def get_keyring_which_only_generates(): + return OnlyGenerateKeyring() + + def get_encryption_materials_with_data_key(): return EncryptionMaterials( algorithm=Algorithm.AES_256_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384, From c8d3b32fb2be3d1b1b31322cc3a6046b040334f3 Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Sun, 28 Jul 2019 00:08:03 -0700 Subject: [PATCH 53/61] Unit tests for multi-keyrings working except the one to check if no further keyrings are called if data encryption key is added --- .../keyring/multi_keyring.py | 6 +- test/functional/test_f_multi_keyring.py | 172 ++++++++---------- test/unit/test_keyring_multi.py | 166 +++++++++++------ test/unit/test_utils.py | 140 +++++++------- 4 files changed, 266 insertions(+), 218 deletions(-) diff --git a/src/aws_encryption_sdk/keyring/multi_keyring.py b/src/aws_encryption_sdk/keyring/multi_keyring.py index 88e98068c..9c51eefc2 100644 --- a/src/aws_encryption_sdk/keyring/multi_keyring.py +++ b/src/aws_encryption_sdk/keyring/multi_keyring.py @@ -71,6 +71,7 @@ def on_encrypt(self, encryption_materials): # Call on_encrypt on the generator keyring if it is provided if self.generator is not None: + encryption_materials = self.generator.on_encrypt(encryption_materials=encryption_materials) # Check if data key is generated @@ -98,6 +99,7 @@ def on_decrypt(self, decryption_materials, encrypted_data_keys): for keyring in self._decryption_keyrings: if decryption_materials.data_encryption_key is not None: return decryption_materials - decryption_materials = keyring.on_decrypt(decryption_materials=decryption_materials, - encrypted_data_keys=encrypted_data_keys) + decryption_materials = keyring.on_decrypt( + decryption_materials=decryption_materials, encrypted_data_keys=encrypted_data_keys + ) return decryption_materials diff --git a/test/functional/test_f_multi_keyring.py b/test/functional/test_f_multi_keyring.py index b9e48ac6f..1d7942c01 100644 --- a/test/functional/test_f_multi_keyring.py +++ b/test/functional/test_f_multi_keyring.py @@ -31,113 +31,102 @@ _SIGNING_KEY = b"aws-crypto-public-key" -_ENCRYPTION_MATERIALS = [ - EncryptionMaterials( - algorithm=Algorithm.AES_256_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384, - encryption_context=_ENCRYPTION_CONTEXT, - signing_key=_SIGNING_KEY, - ), - EncryptionMaterials( - algorithm=Algorithm.AES_256_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384, - data_encryption_key=RawDataKey( - key_provider=MasterKeyInfo(provider_id=_PROVIDER_ID, key_info=_KEY_ID), - data_key=b'*!\xa1"^-(\xf3\x105\x05i@B\xc2\xa2\xb7\xdd\xd5\xd5\xa9\xddm\xfae\xa8\\$\xf9d\x1e(', - ), - encryption_context=_ENCRYPTION_CONTEXT, - signing_key=_SIGNING_KEY, - keyring_trace=[ - KeyringTrace( - wrapping_key=MasterKeyInfo(provider_id=_PROVIDER_ID, key_info=_KEY_ID), - flags={KeyringTraceFlag.WRAPPING_KEY_GENERATED_DATA_KEY}, - ) - ], - ), - EncryptionMaterials( - algorithm=Algorithm.AES_256_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384, - data_encryption_key=RawDataKey( - key_provider=MasterKeyInfo(provider_id=_PROVIDER_ID, key_info=_KEY_ID), - data_key=b'*!\xa1"^-(\xf3\x105\x05i@B\xc2\xa2\xb7\xdd\xd5\xd5\xa9\xddm\xfae\xa8\\$\xf9d\x1e(', - ), - encrypted_data_keys=[ - EncryptedDataKey( - key_provider=MasterKeyInfo(provider_id=_PROVIDER_ID, key_info=_KEY_ID), - encrypted_data_key=b"\xde^\x97\x7f\x84\xe9\x9e\x98\xd0\xe2\xf8\xd5\xcb\xe9\x7f.}\x87\x16,\x11n#\xc8p" - b"\xdb\xbf\x94\x86*Q\x06\xd2\xf5\xdah\x08\xa4p\x81\xf7\xf4G\x07FzE\xde", - ) - ], - encryption_context=_ENCRYPTION_CONTEXT, - signing_key=_SIGNING_KEY, - keyring_trace=[ - KeyringTrace( - wrapping_key=MasterKeyInfo(provider_id=_PROVIDER_ID, key_info=_KEY_ID), - flags={ - KeyringTraceFlag.WRAPPING_KEY_GENERATED_DATA_KEY, - KeyringTraceFlag.WRAPPING_KEY_ENCRYPTED_DATA_KEY, - }, - ) - ], +_ENCRYPTION_MATERIALS_WITHOUT_DATA_KEY = EncryptionMaterials( + algorithm=Algorithm.AES_256_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384, + encryption_context=_ENCRYPTION_CONTEXT, + signing_key=_SIGNING_KEY, +) + +_ENCRYPTION_MATERIALS_WITH_DATA_KEY = EncryptionMaterials( + algorithm=Algorithm.AES_256_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384, + data_encryption_key=RawDataKey( + key_provider=MasterKeyInfo(provider_id=_PROVIDER_ID, key_info=_KEY_ID), + data_key=b'*!\xa1"^-(\xf3\x105\x05i@B\xc2\xa2\xb7\xdd\xd5\xd5\xa9\xddm\xfae\xa8\\$\xf9d\x1e(', ), -] + encryption_context=_ENCRYPTION_CONTEXT, + signing_key=_SIGNING_KEY, + keyring_trace=[ + KeyringTrace( + wrapping_key=MasterKeyInfo(provider_id=_PROVIDER_ID, key_info=_KEY_ID), + flags={KeyringTraceFlag.WRAPPING_KEY_GENERATED_DATA_KEY}, + ) + ], +) -_MULTI_KEYRINGS = [ - MultiKeyring( - generator=RawAESKeyring( +_MULTI_KEYRING_WITH_GENERATOR_AND_CHILDREN = MultiKeyring( + generator=RawAESKeyring( + key_namespace=_PROVIDER_ID, + key_name=_KEY_ID, + wrapping_algorithm=WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING, + wrapping_key=_WRAPPING_KEY_AES, + ), + children=[ + RawRSAKeyring( key_namespace=_PROVIDER_ID, key_name=_KEY_ID, - wrapping_algorithm=WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING, - wrapping_key=_WRAPPING_KEY_AES, - ), - children=[ - RawRSAKeyring( - key_namespace=_PROVIDER_ID, - key_name=_KEY_ID, - wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, - private_wrapping_key=rsa.generate_private_key(public_exponent=65537, key_size=2048, backend=default_backend()), - ), - RawRSAKeyring( - key_namespace=_PROVIDER_ID, - key_name=_KEY_ID, - wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, - private_wrapping_key=rsa.generate_private_key(public_exponent=65537, key_size=2048, backend=default_backend()), + wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, + private_wrapping_key=rsa.generate_private_key( + public_exponent=65537, key_size=2048, backend=default_backend() ), - ], - ), - MultiKeyring( - generator=RawRSAKeyring( + ), + RawRSAKeyring( key_namespace=_PROVIDER_ID, key_name=_KEY_ID, wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, - private_wrapping_key=rsa.generate_private_key(public_exponent=65537, key_size=2048, backend=default_backend()), - ) - ), - MultiKeyring( - children=[ - RawRSAKeyring( - key_namespace=_PROVIDER_ID, - key_name=_KEY_ID, - wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, - private_wrapping_key=rsa.generate_private_key(public_exponent=65537, key_size=2048, backend=default_backend()), + private_wrapping_key=rsa.generate_private_key( + public_exponent=65537, key_size=2048, backend=default_backend() ), - RawAESKeyring( - key_namespace=_PROVIDER_ID, - key_name=_KEY_ID, - wrapping_algorithm=WrappingAlgorithm.AES_128_GCM_IV12_TAG16_NO_PADDING, - wrapping_key=_WRAPPING_KEY_AES, + ), + ], +) + +_MULTI_KEYRING_WITHOUT_CHILDREN = MultiKeyring( + generator=RawRSAKeyring( + key_namespace=_PROVIDER_ID, + key_name=_KEY_ID, + wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, + private_wrapping_key=rsa.generate_private_key(public_exponent=65537, key_size=2048, backend=default_backend()), + ) +) + +_MULTI_KEYRING_WITHOUT_GENERATOR = MultiKeyring( + children=[ + RawRSAKeyring( + key_namespace=_PROVIDER_ID, + key_name=_KEY_ID, + wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, + private_wrapping_key=rsa.generate_private_key( + public_exponent=65537, key_size=2048, backend=default_backend() ), - ] - ), -] + ), + RawAESKeyring( + key_namespace=_PROVIDER_ID, + key_name=_KEY_ID, + wrapping_algorithm=WrappingAlgorithm.AES_128_GCM_IV12_TAG16_NO_PADDING, + wrapping_key=_WRAPPING_KEY_AES, + ), + ] +) -@pytest.mark.parametrize("multi_keyring", _MULTI_KEYRINGS) -@pytest.mark.parametrize("encryption_materials", _ENCRYPTION_MATERIALS) +@pytest.mark.parametrize( + "multi_keyring, encryption_materials", + [ + (_MULTI_KEYRING_WITH_GENERATOR_AND_CHILDREN, _ENCRYPTION_MATERIALS_WITHOUT_DATA_KEY), + (_MULTI_KEYRING_WITH_GENERATOR_AND_CHILDREN, _ENCRYPTION_MATERIALS_WITH_DATA_KEY), + (_MULTI_KEYRING_WITHOUT_CHILDREN, _ENCRYPTION_MATERIALS_WITH_DATA_KEY), + (_MULTI_KEYRING_WITHOUT_GENERATOR, _ENCRYPTION_MATERIALS_WITH_DATA_KEY), + ], +) def test_multi_keyring_encryption_decryption(multi_keyring, encryption_materials): # Call on_encrypt function for the keyring encryption_materials = multi_keyring.on_encrypt(encryption_materials) # Generate decryption materials decryption_materials = DecryptionMaterials( - algorithm=Algorithm.AES_256_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384, verification_key=b"ex_verification_key" + algorithm=Algorithm.AES_256_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384, + verification_key=b"ex_verification_key", + encryption_context=_ENCRYPTION_CONTEXT, ) # Call on_decrypt function for the keyring @@ -145,6 +134,5 @@ def test_multi_keyring_encryption_decryption(multi_keyring, encryption_materials decryption_materials=decryption_materials, encrypted_data_keys=encryption_materials.encrypted_data_keys ) - if decryption_materials.data_encryption_key: - # Check if the data keys match - assert encryption_materials.data_encryption_key == decryption_materials.data_encryption_key + # Check if the data keys match + assert encryption_materials.data_encryption_key == decryption_materials.data_encryption_key diff --git a/test/unit/test_keyring_multi.py b/test/unit/test_keyring_multi.py index 3c39eacc4..e6bbaee85 100644 --- a/test/unit/test_keyring_multi.py +++ b/test/unit/test_keyring_multi.py @@ -13,26 +13,28 @@ """Unit tests for Multi keyring.""" import pytest -import six -from mock import MagicMock, patch, sentinel -from cryptography.hazmat.backends import default_backend -from cryptography.hazmat.primitives.asymmetric import rsa - -from aws_encryption_sdk.exceptions import GenerateKeyError, EncryptKeyError -from aws_encryption_sdk.identifiers import Algorithm, KeyringTraceFlag, WrappingAlgorithm -from aws_encryption_sdk.keyring.base import EncryptedDataKey, Keyring -from aws_encryption_sdk.keyring.multi_keyring import MultiKeyring -from aws_encryption_sdk.keyring.raw_keyring import RawAESKeyring, RawRSAKeyring, WrappingKey -from aws_encryption_sdk.internal.formatting import serialize -from aws_encryption_sdk.materials_managers import DecryptionMaterials, EncryptionMaterials -from aws_encryption_sdk.structures import KeyringTrace, MasterKeyInfo, RawDataKey - +from mock import MagicMock from pytest_mock import mocker # noqa pylint: disable=unused-import -from .test_utils import get_encryption_materials_without_data_key, get_encryption_materials_with_data_key, \ - get_multi_keyring_with_generator_and_children, get_multi_keyring_with_no_children, \ - get_multi_keyring_with_no_generator, get_identity_keyring, get_decryption_materials_with_data_key, \ - get_decryption_materials_without_data_key, get_keyring_which_only_generates +from aws_encryption_sdk.exceptions import EncryptKeyError, GenerateKeyError +from aws_encryption_sdk.identifiers import WrappingAlgorithm +from aws_encryption_sdk.internal.formatting import serialize +from aws_encryption_sdk.keyring.base import Keyring +from aws_encryption_sdk.keyring.multi_keyring import MultiKeyring +from aws_encryption_sdk.keyring.raw_keyring import RawAESKeyring + +from .test_utils import ( + IdentityKeyring, + OnlyGenerateKeyring, + get_decryption_materials_with_data_key, + get_decryption_materials_without_data_key, + get_encryption_materials_with_data_key, + get_encryption_materials_with_encrypted_data_key, + get_encryption_materials_without_data_key, + get_multi_keyring_with_generator_and_children, + get_multi_keyring_with_no_children, + get_multi_keyring_with_no_generator, +) try: # Python 3.5.0 and 3.5.1 have incompatible typing modules from typing import Iterable # noqa pylint: disable=unused-import @@ -51,11 +53,27 @@ mock_generator = MagicMock() mock_generator.__class__ = RawAESKeyring + mock_child_1 = MagicMock() mock_child_1.__class__ = RawAESKeyring + mock_child_2 = MagicMock() mock_child_2.__class__ = RawAESKeyring +mock_child_3 = MagicMock() +mock_child_3.__class__ = RawAESKeyring +mock_child_3.on_decrypt.return_value = get_decryption_materials_with_data_key() + + +mock_generator_does_not_add_edk = MagicMock() +mock_generator_does_not_add_edk.__class__ = OnlyGenerateKeyring + +mock_child_1_does_not_add_edk = MagicMock() +mock_child_1_does_not_add_edk.__class__ = OnlyGenerateKeyring + +mock_child_2_does_not_add_edk = MagicMock() +mock_child_2_does_not_add_edk.__class__ = OnlyGenerateKeyring + @pytest.fixture def patch_encrypt(mocker): @@ -73,10 +91,10 @@ def test_keyring_with_generator_but_no_children(): key_namespace=_PROVIDER_ID, key_name=_KEY_ID, wrapping_key=_WRAPPING_KEY_AES, - wrapping_algorithm=WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING + wrapping_algorithm=WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING, ) ) - assert isinstance(test_multi_keyring.generator,RawAESKeyring) + assert isinstance(test_multi_keyring.generator, RawAESKeyring) def test_keyring_with_children_but_no_generator(): @@ -86,7 +104,7 @@ def test_keyring_with_children_but_no_generator(): key_namespace=_PROVIDER_ID, key_name=_KEY_ID, wrapping_key=_WRAPPING_KEY_AES, - wrapping_algorithm=WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING + wrapping_algorithm=WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING, ) ] ) @@ -101,11 +119,7 @@ def test_keyring_with_no_generator_no_children(): def test_children_not_keyrings(): with pytest.raises(TypeError) as exc_info: - MultiKeyring( - children=[ - WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING - ] - ) + MultiKeyring(children=[WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING]) assert exc_info.errisinstance(TypeError) @@ -113,14 +127,13 @@ def test_on_encrypt_with_no_generator_no_data_encryption_key(): test_multi_keyring = get_multi_keyring_with_no_generator() with pytest.raises(EncryptKeyError) as exc_info: test_multi_keyring.on_encrypt(encryption_materials=get_encryption_materials_without_data_key()) - assert exc_info.match("Generator keyring not provided and encryption materials do not already " - "contain a plaintext data key.") + assert exc_info.match( + "Generator keyring not provided and encryption materials do not already " "contain a plaintext data key." + ) def test_identity_keyring_as_generator_and_no_data_encryption_key(): - test_multi_keyring = MultiKeyring( - generator=get_identity_keyring() - ) + test_multi_keyring = MultiKeyring(generator=IdentityKeyring()) with pytest.raises(GenerateKeyError) as exc_info: test_multi_keyring.on_encrypt(encryption_materials=get_encryption_materials_without_data_key()) assert exc_info.match("Unable to generate data encryption key.") @@ -146,43 +159,84 @@ def test_number_of_encrypted_data_keys_with_generator_and_children(): def test_on_encrypt_when_data_encryption_key_given(): - test_multi_keyring = MultiKeyring( - generator=mock_generator, - children=[ - mock_child_1, - mock_child_2 - ] - ) + test_multi_keyring = MultiKeyring(generator=mock_generator, children=[mock_child_1, mock_child_2]) test_multi_keyring.on_encrypt(encryption_materials=get_encryption_materials_with_data_key()) - mock_generator.on_encrypt.assert_called_once() - for keyring in test_multi_keyring.children: + for keyring in test_multi_keyring._decryption_keyrings: keyring.on_encrypt.assert_called_once() def test_on_encrypt_edk_length_when_keyring_generates_but_does_not_encrypt(): - test_multi_keyring = MultiKeyring( - generator=get_keyring_which_only_generates() - ) + test_multi_keyring = MultiKeyring(generator=OnlyGenerateKeyring()) test = test_multi_keyring.on_encrypt(encryption_materials=get_encryption_materials_without_data_key()) assert test.data_encryption_key is not None - # print(test.encrypted_data_keys) assert len(test.encrypted_data_keys) == len(get_encryption_materials_without_data_key().encrypted_data_keys) + test = test_multi_keyring.on_encrypt(encryption_materials=get_encryption_materials_with_encrypted_data_key()) + assert len(test.encrypted_data_keys) == len(get_encryption_materials_with_encrypted_data_key().encrypted_data_keys) + def test_on_decrypt_when_data_encryption_key_given(): - test_multi_keyring = MultiKeyring( - generator=mock_generator, - children=[ - mock_child_1, - mock_child_2 - ] - ) - test = test_multi_keyring.on_decrypt(decryption_materials=get_decryption_materials_with_data_key(), - encrypted_data_keys=[]) - mock_generator.on_decrypt.assert_not_called() - for keyring in test_multi_keyring.children: + test_multi_keyring = MultiKeyring(generator=mock_generator, children=[mock_child_1, mock_child_2]) + test_multi_keyring.on_decrypt(decryption_materials=get_decryption_materials_with_data_key(), encrypted_data_keys=[]) + for keyring in test_multi_keyring._decryption_keyrings: keyring.on_decrypt.assert_not_called() + +def test_on_decrypt_every_keyring_called_when_data_encryption_key_not_added(): + mock_generator.on_decrypt.return_value = get_decryption_materials_without_data_key() + mock_child_1.on_decrypt.return_value = get_decryption_materials_without_data_key() + mock_child_2.on_decrypt.return_value = get_decryption_materials_without_data_key() + + test_multi_keyring = MultiKeyring(generator=mock_generator, children=[mock_child_1, mock_child_2]) + test_multi_keyring.on_decrypt( + decryption_materials=get_decryption_materials_without_data_key(), encrypted_data_keys=[] + ) + + for keyring in test_multi_keyring._decryption_keyrings: + keyring.on_decrypt.assert_called() + + +# def test_no_keyring_called_after_data_encryption_key_added_when_data_encryption_key_not_given(): +# mock_generator.on_decrypt(decryption_materials=get_decryption_materials_without_data_key(), +# encrypted_data_keys=[]) +# mock_generator.on_decrypt.return_value = get_decryption_materials_without_data_key() +# +# mock_child_3.on_decrypt(decryption_materials=mock_generator.on_decrypt.return_value, +# encrypted_data_keys=[]) +# mock_child_3.on_decrypt.return_value = get_decryption_materials_with_data_key() +# +# mock_child_1.on_decrypt(decryption_materials=mock_child_3.on_decrypt.return_value, +# encrypted_data_keys=[]) +# mock_child_1.on_decrypt.return_value = get_decryption_materials_with_data_key() # -# def test_every_keyring_called_when_edk_not_added(): +# mock_child_2.on_decrypt(decryption_materials=mock_child_1.on_decrypt.return_value, +# encrypted_data_keys=[]) +# mock_child_2.on_decrypt.return_value = get_decryption_materials_with_data_key() # +# test_multi_keyring = MultiKeyring( +# generator=mock_generator, +# children=[ +# mock_child_3, +# mock_child_1, +# mock_child_2, +# ] +# ) +# test_multi_keyring.on_decrypt(decryption_materials=get_decryption_materials_without_data_key(), +# encrypted_data_keys=[]) +# mock_generator.on_decrypt.assert_called() +# mock_child_3.on_decrypt.assert_called() +# mock_child_1.on_decrypt.assert_not_called() +# mock_child_2.on_decrypt.assert_not_called() + +# def test_no_keyring_called_after_data_encryption_key_added_when_data_encryption_key_not_given(): +# test_multi_keyring = get_multi_keyring_with_generator_and_children() +# test_multi_keyring.on_decrypt(decryption_materials=get_decryption_materials_without_data_key(), +# encrypted_data_keys=[ +# EncryptedDataKey( +# key_provider=MasterKeyInfo(provider_id=_PROVIDER_ID, key_info=_KEY_ID), +# encrypted_data_key=b"\xde^\x97\x7f\x84\xe9\x9e\x98\xd0\xe2\xf8\xd5\xcb\xe9" +# b"\x7f.}\x87\x16,\x11n#\xc8p\xdb\xbf\x94\x86*Q\x06\xd2" +# b"\xf5\xdah\x08\xa4p\x81\xf7\xf4G\x07FzE\xde", +# ) +# ]) +# for diff --git a/test/unit/test_utils.py b/test/unit/test_utils.py index 7607c269e..cc3399ffe 100644 --- a/test/unit/test_utils.py +++ b/test/unit/test_utils.py @@ -13,22 +13,22 @@ # language governing permissions and limitations under the License. """Test suite for aws_encryption_sdk.internal.utils""" import io +import os import pytest -from mock import MagicMock, patch, sentinel - from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives.asymmetric import rsa +from mock import MagicMock, patch, sentinel import aws_encryption_sdk.identifiers import aws_encryption_sdk.internal.utils from aws_encryption_sdk.exceptions import InvalidDataKeyError, SerializationError, UnknownIdentityError +from aws_encryption_sdk.identifiers import Algorithm, KeyringTraceFlag, WrappingAlgorithm from aws_encryption_sdk.internal.defaults import MAX_FRAME_SIZE, MESSAGE_ID_LENGTH -from aws_encryption_sdk.structures import DataKey, EncryptedDataKey, MasterKeyInfo, RawDataKey, KeyringTrace -from aws_encryption_sdk.keyring.raw_keyring import RawRSAKeyring, RawAESKeyring, Keyring, generate_data_key from aws_encryption_sdk.keyring.multi_keyring import MultiKeyring -from aws_encryption_sdk.identifiers import Algorithm, KeyringTraceFlag, WrappingAlgorithm +from aws_encryption_sdk.keyring.raw_keyring import Keyring, RawAESKeyring, RawRSAKeyring, generate_data_key from aws_encryption_sdk.materials_managers import DecryptionMaterials, EncryptionMaterials +from aws_encryption_sdk.structures import DataKey, EncryptedDataKey, KeyringTrace, MasterKeyInfo, RawDataKey from .test_values import VALUES from .unit_test_utils import assert_prepped_stream_identity @@ -67,18 +67,17 @@ def on_decrypt(self, decryption_materials, encrypted_data_keys): class OnlyGenerateKeyring(Keyring): def on_encrypt(self, encryption_materials): # type: (EncryptionMaterials) -> EncryptionMaterials - encryption_materials.data_encryption_key = RawDataKey( - key_provider=MasterKeyInfo( - provider_id=_PROVIDER_ID, - key_info=_KEY_ID - ), - data_key=generate_data_key(encryption_materials=encryption_materials, - key_provider=MasterKeyInfo( - provider_id=_PROVIDER_ID, - key_info=_KEY_ID - ) - ) - ) + if encryption_materials.data_encryption_key is None: + key_provider = MasterKeyInfo(provider_id=_PROVIDER_ID, key_info=_KEY_ID) + data_encryption_key = RawDataKey( + key_provider=key_provider, data_key=os.urandom(encryption_materials.algorithm.kdf_input_len) + ) + encryption_materials.add_data_encryption_key( + data_encryption_key=data_encryption_key, + keyring_trace=KeyringTrace( + wrapping_key=key_provider, flags={KeyringTraceFlag.WRAPPING_KEY_GENERATED_DATA_KEY} + ), + ) return encryption_materials def on_decrypt(self, decryption_materials, encrypted_data_keys): @@ -139,8 +138,10 @@ def get_encryption_materials_with_encrypted_data_key(): keyring_trace=[ KeyringTrace( wrapping_key=MasterKeyInfo(provider_id=_PROVIDER_ID, key_info=_KEY_ID), - flags={KeyringTraceFlag.WRAPPING_KEY_GENERATED_DATA_KEY, KeyringTraceFlag - .WRAPPING_KEY_ENCRYPTED_DATA_KEY}, + flags={ + KeyringTraceFlag.WRAPPING_KEY_GENERATED_DATA_KEY, + KeyringTraceFlag.WRAPPING_KEY_ENCRYPTED_DATA_KEY, + }, ) ], ) @@ -155,77 +156,80 @@ def get_decryption_materials_with_data_key(): ), encryption_context=_ENCRYPTION_CONTEXT, verification_key=b"ex_verification_key", - keyring_trace=[KeyringTrace( - wrapping_key=MasterKeyInfo(provider_id=_PROVIDER_ID, key_info=_KEY_ID), - flags={KeyringTraceFlag.WRAPPING_KEY_DECRYPTED_DATA_KEY} - )] + keyring_trace=[ + KeyringTrace( + wrapping_key=MasterKeyInfo(provider_id=_PROVIDER_ID, key_info=_KEY_ID), + flags={KeyringTraceFlag.WRAPPING_KEY_DECRYPTED_DATA_KEY}, + ) + ], ) def get_decryption_materials_without_data_key(): - return DecryptionMaterials( - encryption_context=_ENCRYPTION_CONTEXT, - verification_key=b"ex_verification_key", - ) + return DecryptionMaterials(encryption_context=_ENCRYPTION_CONTEXT, verification_key=b"ex_verification_key") def get_multi_keyring_with_generator_and_children(): return MultiKeyring( - generator=RawAESKeyring( + generator=RawAESKeyring( + key_namespace=_PROVIDER_ID, + key_name=_KEY_ID, + wrapping_algorithm=WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING, + wrapping_key=_WRAPPING_KEY_AES, + ), + children=[ + RawRSAKeyring( key_namespace=_PROVIDER_ID, key_name=_KEY_ID, - wrapping_algorithm=WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING, - wrapping_key=_WRAPPING_KEY_AES, - ), - children=[ - RawRSAKeyring( - key_namespace=_PROVIDER_ID, - key_name=_KEY_ID, - wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, - private_wrapping_key=rsa.generate_private_key(public_exponent=65537, key_size=2048, - backend=default_backend()), + wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, + private_wrapping_key=rsa.generate_private_key( + public_exponent=65537, key_size=2048, backend=default_backend() ), - RawRSAKeyring( - key_namespace=_PROVIDER_ID, - key_name=_KEY_ID, - wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, - private_wrapping_key=rsa.generate_private_key(public_exponent=65537, key_size=2048, - backend=default_backend()), + ), + RawRSAKeyring( + key_namespace=_PROVIDER_ID, + key_name=_KEY_ID, + wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, + private_wrapping_key=rsa.generate_private_key( + public_exponent=65537, key_size=2048, backend=default_backend() ), - ], - ) + ), + ], + ) def get_multi_keyring_with_no_children(): return MultiKeyring( - generator=RawRSAKeyring( - key_namespace=_PROVIDER_ID, - key_name=_KEY_ID, - wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, - private_wrapping_key=rsa.generate_private_key(public_exponent=65537, key_size=2048, - backend=default_backend()), - ) + generator=RawRSAKeyring( + key_namespace=_PROVIDER_ID, + key_name=_KEY_ID, + wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, + private_wrapping_key=rsa.generate_private_key( + public_exponent=65537, key_size=2048, backend=default_backend() + ), ) + ) def get_multi_keyring_with_no_generator(): return MultiKeyring( - children=[ - RawRSAKeyring( - key_namespace=_PROVIDER_ID, - key_name=_KEY_ID, - wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, - private_wrapping_key=rsa.generate_private_key(public_exponent=65537, key_size=2048, - backend=default_backend()), - ), - RawAESKeyring( - key_namespace=_PROVIDER_ID, - key_name=_KEY_ID, - wrapping_algorithm=WrappingAlgorithm.AES_128_GCM_IV12_TAG16_NO_PADDING, - wrapping_key=_WRAPPING_KEY_AES, + children=[ + RawRSAKeyring( + key_namespace=_PROVIDER_ID, + key_name=_KEY_ID, + wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, + private_wrapping_key=rsa.generate_private_key( + public_exponent=65537, key_size=2048, backend=default_backend() ), - ] - ) + ), + RawAESKeyring( + key_namespace=_PROVIDER_ID, + key_name=_KEY_ID, + wrapping_algorithm=WrappingAlgorithm.AES_128_GCM_IV12_TAG16_NO_PADDING, + wrapping_key=_WRAPPING_KEY_AES, + ), + ] + ) def test_prep_stream_data_passthrough(): From b9dbcad61252096dddfa8b4cf12925dc1408c2ea Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Sun, 28 Jul 2019 18:06:26 -0700 Subject: [PATCH 54/61] Made changes in raw keyrings to match the latest version --- src/aws_encryption_sdk/keyring/raw_keyring.py | 11 +++-------- test/unit/test_utils.py | 2 +- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/src/aws_encryption_sdk/keyring/raw_keyring.py b/src/aws_encryption_sdk/keyring/raw_keyring.py index 8d76be235..d10fa15c2 100644 --- a/src/aws_encryption_sdk/keyring/raw_keyring.py +++ b/src/aws_encryption_sdk/keyring/raw_keyring.py @@ -20,7 +20,7 @@ from attr.validators import instance_of, optional from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives import serialization -from cryptography.hazmat.primitives.asymmetric import padding, rsa +from cryptography.hazmat.primitives.asymmetric import rsa from aws_encryption_sdk.exceptions import GenerateKeyError from aws_encryption_sdk.identifiers import EncryptionKeyType, KeyringTraceFlag, WrappingAlgorithm @@ -136,7 +136,6 @@ def on_encrypt(self, encryption_materials): :rtype: aws_encryption_sdk.materials_managers.EncryptionMaterials """ if encryption_materials.data_encryption_key is None: - print("Data key needs to be generated") plaintext_generated = generate_data_key( encryption_materials=encryption_materials, key_provider=self._key_provider ) @@ -145,7 +144,6 @@ def on_encrypt(self, encryption_materials): if not plaintext_generated or plaintext_generated is None: raise GenerateKeyError("Unable to generate data encryption key.") - print("Generated") # Encrypt data key encrypted_wrapped_key = self._wrapping_key_structure.encrypt( plaintext_data_key=encryption_materials.data_encryption_key.data_key, @@ -154,7 +152,6 @@ def on_encrypt(self, encryption_materials): # Check if encryption is successful if encrypted_wrapped_key is None: - print("Encrypted wrapped key None") return encryption_materials # EncryptedData to EncryptedDataKey @@ -262,7 +259,7 @@ class RawRSAKeyring(Keyring): _public_wrapping_key = attr.ib(default=None, repr=False, validator=optional(instance_of(rsa.RSAPublicKey))) @classmethod - def fromPEMEncoding( + def from_pem_encoding( cls, key_namespace, # type: str key_name, # type: bytes @@ -302,7 +299,7 @@ def fromPEMEncoding( ) @classmethod - def fromDEREncoding( + def from_der_encoding( cls, key_namespace, # type: str key_name, # type: bytes @@ -422,10 +419,8 @@ def on_decrypt(self, decryption_materials, encrypted_data_keys): # Decrypt data key for key in encrypted_data_keys: if decryption_materials.data_encryption_key is not None: - print("DEC MAT") return decryption_materials if key.key_provider != self._key_provider: - print("PROVIDER PROB") continue # Wrapped EncryptedDataKey to deserialized EncryptedData encrypted_wrapped_key = deserialize_wrapped_key( diff --git a/test/unit/test_utils.py b/test/unit/test_utils.py index cc3399ffe..192c1c830 100644 --- a/test/unit/test_utils.py +++ b/test/unit/test_utils.py @@ -26,7 +26,7 @@ from aws_encryption_sdk.identifiers import Algorithm, KeyringTraceFlag, WrappingAlgorithm from aws_encryption_sdk.internal.defaults import MAX_FRAME_SIZE, MESSAGE_ID_LENGTH from aws_encryption_sdk.keyring.multi_keyring import MultiKeyring -from aws_encryption_sdk.keyring.raw_keyring import Keyring, RawAESKeyring, RawRSAKeyring, generate_data_key +from aws_encryption_sdk.keyring.raw_keyring import Keyring, RawAESKeyring, RawRSAKeyring from aws_encryption_sdk.materials_managers import DecryptionMaterials, EncryptionMaterials from aws_encryption_sdk.structures import DataKey, EncryptedDataKey, KeyringTrace, MasterKeyInfo, RawDataKey From 27c8df083066b3f2f84d5d4c52f74bdc53d16e29 Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Sun, 28 Jul 2019 18:30:42 -0700 Subject: [PATCH 55/61] Removed unused imports --- test/functional/test_f_multi_keyring.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/functional/test_f_multi_keyring.py b/test/functional/test_f_multi_keyring.py index 1d7942c01..4d3fbbce9 100644 --- a/test/functional/test_f_multi_keyring.py +++ b/test/functional/test_f_multi_keyring.py @@ -20,7 +20,7 @@ from aws_encryption_sdk.keyring.multi_keyring import MultiKeyring from aws_encryption_sdk.keyring.raw_keyring import RawAESKeyring, RawRSAKeyring from aws_encryption_sdk.materials_managers import DecryptionMaterials, EncryptionMaterials -from aws_encryption_sdk.structures import EncryptedDataKey, KeyringTrace, MasterKeyInfo, RawDataKey +from aws_encryption_sdk.structures import KeyringTrace, MasterKeyInfo, RawDataKey pytestmark = [pytest.mark.functional, pytest.mark.local] From 3c00e12cc7b17fa230f2b4aa1b9f138ce2104bdd Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Wed, 31 Jul 2019 17:12:20 -0700 Subject: [PATCH 56/61] Made suggested changes --- .../keyring/multi_keyring.py | 6 - test/functional/test_f_multi_keyring.py | 14 +- test/unit/test_keyring_multi.py | 179 ++++++++------- test/unit/test_utils.py | 205 +----------------- test/unit/unit_test_utils.py | 189 ++++++++++++++++ 5 files changed, 291 insertions(+), 302 deletions(-) diff --git a/src/aws_encryption_sdk/keyring/multi_keyring.py b/src/aws_encryption_sdk/keyring/multi_keyring.py index 9c51eefc2..b494a8618 100644 --- a/src/aws_encryption_sdk/keyring/multi_keyring.py +++ b/src/aws_encryption_sdk/keyring/multi_keyring.py @@ -19,12 +19,6 @@ from aws_encryption_sdk.exceptions import EncryptKeyError, GenerateKeyError from aws_encryption_sdk.keyring.base import DecryptionMaterials, EncryptedDataKey, EncryptionMaterials, Keyring -try: # Python 3.5.0 and 3.5.1 have incompatible typing modules - from typing import Iterable # noqa pylint: disable=unused-import -except ImportError: # pragma: no cover - # We only actually need these imports when running the mypy checks - pass - @attr.s class MultiKeyring(Keyring): diff --git a/test/functional/test_f_multi_keyring.py b/test/functional/test_f_multi_keyring.py index 4d3fbbce9..7984c3a70 100644 --- a/test/functional/test_f_multi_keyring.py +++ b/test/functional/test_f_multi_keyring.py @@ -17,6 +17,7 @@ from cryptography.hazmat.primitives.asymmetric import rsa from aws_encryption_sdk.identifiers import Algorithm, KeyringTraceFlag, WrappingAlgorithm +from aws_encryption_sdk.internal.defaults import ALGORITHM from aws_encryption_sdk.keyring.multi_keyring import MultiKeyring from aws_encryption_sdk.keyring.raw_keyring import RawAESKeyring, RawRSAKeyring from aws_encryption_sdk.materials_managers import DecryptionMaterials, EncryptionMaterials @@ -29,22 +30,17 @@ _KEY_ID = b"5325b043-5843-4629-869c-64794af77ada" _WRAPPING_KEY_AES = b"\xeby-\x80A6\x15rA8\x83#,\xe4\xab\xac`\xaf\x99Z\xc1\xce\xdb\xb6\x0f\xb7\x805\xb2\x14J3" -_SIGNING_KEY = b"aws-crypto-public-key" - _ENCRYPTION_MATERIALS_WITHOUT_DATA_KEY = EncryptionMaterials( - algorithm=Algorithm.AES_256_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384, - encryption_context=_ENCRYPTION_CONTEXT, - signing_key=_SIGNING_KEY, + algorithm=ALGORITHM, encryption_context=_ENCRYPTION_CONTEXT ) _ENCRYPTION_MATERIALS_WITH_DATA_KEY = EncryptionMaterials( - algorithm=Algorithm.AES_256_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384, + algorithm=ALGORITHM, data_encryption_key=RawDataKey( key_provider=MasterKeyInfo(provider_id=_PROVIDER_ID, key_info=_KEY_ID), data_key=b'*!\xa1"^-(\xf3\x105\x05i@B\xc2\xa2\xb7\xdd\xd5\xd5\xa9\xddm\xfae\xa8\\$\xf9d\x1e(', ), encryption_context=_ENCRYPTION_CONTEXT, - signing_key=_SIGNING_KEY, keyring_trace=[ KeyringTrace( wrapping_key=MasterKeyInfo(provider_id=_PROVIDER_ID, key_info=_KEY_ID), @@ -124,9 +120,7 @@ def test_multi_keyring_encryption_decryption(multi_keyring, encryption_materials # Generate decryption materials decryption_materials = DecryptionMaterials( - algorithm=Algorithm.AES_256_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384, - verification_key=b"ex_verification_key", - encryption_context=_ENCRYPTION_CONTEXT, + algorithm=ALGORITHM, verification_key=b"ex_verification_key", encryption_context=_ENCRYPTION_CONTEXT ) # Call on_decrypt function for the keyring diff --git a/test/unit/test_keyring_multi.py b/test/unit/test_keyring_multi.py index e6bbaee85..e2eb3d4d2 100644 --- a/test/unit/test_keyring_multi.py +++ b/test/unit/test_keyring_multi.py @@ -11,6 +11,7 @@ # ANY KIND, either express or implied. See the License for the specific # language governing permissions and limitations under the License. """Unit tests for Multi keyring.""" +import itertools import pytest from mock import MagicMock @@ -23,7 +24,7 @@ from aws_encryption_sdk.keyring.multi_keyring import MultiKeyring from aws_encryption_sdk.keyring.raw_keyring import RawAESKeyring -from .test_utils import ( +from .unit_test_utils import ( IdentityKeyring, OnlyGenerateKeyring, get_decryption_materials_with_data_key, @@ -36,12 +37,6 @@ get_multi_keyring_with_no_generator, ) -try: # Python 3.5.0 and 3.5.1 have incompatible typing modules - from typing import Iterable # noqa pylint: disable=unused-import -except ImportError: # pragma: no cover - # We only actually need these imports when running the mypy checks - pass - pytestmark = [pytest.mark.unit, pytest.mark.local] @@ -51,28 +46,44 @@ _WRAPPING_KEY_AES = b"\xeby-\x80A6\x15rA8\x83#,\xe4\xab\xac`\xaf\x99Z\xc1\xce\xdb\xb6\x0f\xb7\x805\xb2\x14J3" _SIGNING_KEY = b"aws-crypto-public-key" -mock_generator = MagicMock() -mock_generator.__class__ = RawAESKeyring -mock_child_1 = MagicMock() -mock_child_1.__class__ = RawAESKeyring +@pytest.fixture +def identity_keyring(): + return IdentityKeyring() + + +@pytest.fixture +def keyring_which_only_generates(): + return OnlyGenerateKeyring() + + +@pytest.fixture +def mock_generator(): + mock_generator = MagicMock() + mock_generator.__class__ = RawAESKeyring + return mock_generator -mock_child_2 = MagicMock() -mock_child_2.__class__ = RawAESKeyring -mock_child_3 = MagicMock() -mock_child_3.__class__ = RawAESKeyring -mock_child_3.on_decrypt.return_value = get_decryption_materials_with_data_key() +@pytest.fixture +def mock_child_1(): + mock_child_1 = MagicMock() + mock_child_1.__class__ = RawAESKeyring + return mock_child_1 -mock_generator_does_not_add_edk = MagicMock() -mock_generator_does_not_add_edk.__class__ = OnlyGenerateKeyring +@pytest.fixture +def mock_child_2(): + mock_child_2 = MagicMock() + mock_child_2.__class__ = RawAESKeyring + return mock_child_2 -mock_child_1_does_not_add_edk = MagicMock() -mock_child_1_does_not_add_edk.__class__ = OnlyGenerateKeyring -mock_child_2_does_not_add_edk = MagicMock() -mock_child_2_does_not_add_edk.__class__ = OnlyGenerateKeyring +@pytest.fixture +def mock_child_3(): + mock_child_3 = MagicMock() + mock_child_3.__class__ = RawAESKeyring + mock_child_3.on_decrypt.return_value = get_decryption_materials_with_data_key() + return mock_child_3 @pytest.fixture @@ -94,7 +105,12 @@ def test_keyring_with_generator_but_no_children(): wrapping_algorithm=WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING, ) ) - assert isinstance(test_multi_keyring.generator, RawAESKeyring) + assert isinstance(test_multi_keyring.generator, Keyring) + assert test_multi_keyring.generator.key_namespace == _PROVIDER_ID + assert test_multi_keyring.generator.key_name == _KEY_ID + assert test_multi_keyring.generator._wrapping_key == _WRAPPING_KEY_AES + assert test_multi_keyring.generator._wrapping_algorithm == WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING + assert test_multi_keyring.children == () def test_keyring_with_children_but_no_generator(): @@ -108,7 +124,12 @@ def test_keyring_with_children_but_no_generator(): ) ] ) - assert isinstance(test_multi_keyring.children, list) + assert len(test_multi_keyring.children) == 1 + assert test_multi_keyring.children[0].key_namespace == _PROVIDER_ID + assert test_multi_keyring.children[0].key_name == _KEY_ID + assert test_multi_keyring.children[0]._wrapping_key == _WRAPPING_KEY_AES + assert test_multi_keyring.children[0]._wrapping_algorithm == WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING + assert test_multi_keyring.generator is None def test_keyring_with_no_generator_no_children(): @@ -117,10 +138,26 @@ def test_keyring_with_no_generator_no_children(): assert exc_info.match("At least one of generator or children must be provided") -def test_children_not_keyrings(): +@pytest.mark.parametrize( + "generator, children", + ( + (WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING, None), + (WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING, get_multi_keyring_with_no_generator().children), + (None, [WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING]), + (get_multi_keyring_with_no_children().generator, [WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING]), + ), +) +def test_keyring_with_invalid_parameters(generator, children): with pytest.raises(TypeError) as exc_info: - MultiKeyring(children=[WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING]) - assert exc_info.errisinstance(TypeError) + MultiKeyring(generator=generator, children=children) + assert exc_info.match("('children'|'generator') must be .*") + + +def test_decryption_keyrings(): + test_multi_keyring = get_multi_keyring_with_generator_and_children() + assert test_multi_keyring.generator in test_multi_keyring._decryption_keyrings + for child_keyring in test_multi_keyring.children: + assert child_keyring in test_multi_keyring._decryption_keyrings def test_on_encrypt_with_no_generator_no_data_encryption_key(): @@ -128,12 +165,12 @@ def test_on_encrypt_with_no_generator_no_data_encryption_key(): with pytest.raises(EncryptKeyError) as exc_info: test_multi_keyring.on_encrypt(encryption_materials=get_encryption_materials_without_data_key()) assert exc_info.match( - "Generator keyring not provided and encryption materials do not already " "contain a plaintext data key." + "Generator keyring not provided and encryption materials do not already contain a plaintext data key." ) -def test_identity_keyring_as_generator_and_no_data_encryption_key(): - test_multi_keyring = MultiKeyring(generator=IdentityKeyring()) +def test_identity_keyring_as_generator_and_no_data_encryption_key(identity_keyring): + test_multi_keyring = MultiKeyring(generator=identity_keyring) with pytest.raises(GenerateKeyError) as exc_info: test_multi_keyring.on_encrypt(encryption_materials=get_encryption_materials_without_data_key()) assert exc_info.match("Unable to generate data encryption key.") @@ -158,32 +195,38 @@ def test_number_of_encrypted_data_keys_with_generator_and_children(): assert len(test.encrypted_data_keys) == number_of_children + 1 -def test_on_encrypt_when_data_encryption_key_given(): +def test_on_encrypt_when_data_encryption_key_given(mock_generator, mock_child_1, mock_child_2): test_multi_keyring = MultiKeyring(generator=mock_generator, children=[mock_child_1, mock_child_2]) test_multi_keyring.on_encrypt(encryption_materials=get_encryption_materials_with_data_key()) for keyring in test_multi_keyring._decryption_keyrings: keyring.on_encrypt.assert_called_once() -def test_on_encrypt_edk_length_when_keyring_generates_but_does_not_encrypt(): +def test_on_encrypt_edk_length_when_keyring_generates_but_does_not_encrypt_encryption_materials_without_data_key(): test_multi_keyring = MultiKeyring(generator=OnlyGenerateKeyring()) + len_edk_before_encrypt = len(get_encryption_materials_without_data_key().encrypted_data_keys) test = test_multi_keyring.on_encrypt(encryption_materials=get_encryption_materials_without_data_key()) assert test.data_encryption_key is not None - assert len(test.encrypted_data_keys) == len(get_encryption_materials_without_data_key().encrypted_data_keys) + assert len(test.encrypted_data_keys) == len_edk_before_encrypt + +def test_on_encrypt_edk_length_when_keyring_generates_but_does_not_encrypt_encryption_materials_with_data_key(): + test_multi_keyring = MultiKeyring(generator=OnlyGenerateKeyring()) test = test_multi_keyring.on_encrypt(encryption_materials=get_encryption_materials_with_encrypted_data_key()) assert len(test.encrypted_data_keys) == len(get_encryption_materials_with_encrypted_data_key().encrypted_data_keys) -def test_on_decrypt_when_data_encryption_key_given(): +def test_on_decrypt_when_data_encryption_key_given(mock_generator, mock_child_1, mock_child_2): test_multi_keyring = MultiKeyring(generator=mock_generator, children=[mock_child_1, mock_child_2]) test_multi_keyring.on_decrypt(decryption_materials=get_decryption_materials_with_data_key(), encrypted_data_keys=[]) for keyring in test_multi_keyring._decryption_keyrings: - keyring.on_decrypt.assert_not_called() + assert not keyring.on_decrypt.called -def test_on_decrypt_every_keyring_called_when_data_encryption_key_not_added(): - mock_generator.on_decrypt.return_value = get_decryption_materials_without_data_key() +def test_on_decrypt_every_keyring_called_when_data_encryption_key_not_added(mock_generator, mock_child_1, mock_child_2): + mock_generator.on_decrypt.side_effect = ( + lambda decryption_materials, encrypted_data_keys: get_decryption_materials_without_data_key() + ) mock_child_1.on_decrypt.return_value = get_decryption_materials_without_data_key() mock_child_2.on_decrypt.return_value = get_decryption_materials_without_data_key() @@ -193,50 +236,22 @@ def test_on_decrypt_every_keyring_called_when_data_encryption_key_not_added(): ) for keyring in test_multi_keyring._decryption_keyrings: - keyring.on_decrypt.assert_called() + assert keyring.on_decrypt.called -# def test_no_keyring_called_after_data_encryption_key_added_when_data_encryption_key_not_given(): -# mock_generator.on_decrypt(decryption_materials=get_decryption_materials_without_data_key(), -# encrypted_data_keys=[]) -# mock_generator.on_decrypt.return_value = get_decryption_materials_without_data_key() -# -# mock_child_3.on_decrypt(decryption_materials=mock_generator.on_decrypt.return_value, -# encrypted_data_keys=[]) -# mock_child_3.on_decrypt.return_value = get_decryption_materials_with_data_key() -# -# mock_child_1.on_decrypt(decryption_materials=mock_child_3.on_decrypt.return_value, -# encrypted_data_keys=[]) -# mock_child_1.on_decrypt.return_value = get_decryption_materials_with_data_key() -# -# mock_child_2.on_decrypt(decryption_materials=mock_child_1.on_decrypt.return_value, -# encrypted_data_keys=[]) -# mock_child_2.on_decrypt.return_value = get_decryption_materials_with_data_key() -# -# test_multi_keyring = MultiKeyring( -# generator=mock_generator, -# children=[ -# mock_child_3, -# mock_child_1, -# mock_child_2, -# ] -# ) -# test_multi_keyring.on_decrypt(decryption_materials=get_decryption_materials_without_data_key(), -# encrypted_data_keys=[]) -# mock_generator.on_decrypt.assert_called() -# mock_child_3.on_decrypt.assert_called() -# mock_child_1.on_decrypt.assert_not_called() -# mock_child_2.on_decrypt.assert_not_called() - -# def test_no_keyring_called_after_data_encryption_key_added_when_data_encryption_key_not_given(): -# test_multi_keyring = get_multi_keyring_with_generator_and_children() -# test_multi_keyring.on_decrypt(decryption_materials=get_decryption_materials_without_data_key(), -# encrypted_data_keys=[ -# EncryptedDataKey( -# key_provider=MasterKeyInfo(provider_id=_PROVIDER_ID, key_info=_KEY_ID), -# encrypted_data_key=b"\xde^\x97\x7f\x84\xe9\x9e\x98\xd0\xe2\xf8\xd5\xcb\xe9" -# b"\x7f.}\x87\x16,\x11n#\xc8p\xdb\xbf\x94\x86*Q\x06\xd2" -# b"\xf5\xdah\x08\xa4p\x81\xf7\xf4G\x07FzE\xde", -# ) -# ]) -# for +def test_no_keyring_called_after_data_encryption_key_added_when_data_encryption_key_not_given( + mock_generator, mock_child_1, mock_child_2, mock_child_3 +): + + mock_generator.on_decrypt.side_effect = ( + lambda decryption_materials, encrypted_data_keys: get_decryption_materials_without_data_key() + ) + + test_multi_keyring = MultiKeyring(generator=mock_generator, children=[mock_child_3, mock_child_1, mock_child_2]) + test_multi_keyring.on_decrypt( + decryption_materials=get_decryption_materials_without_data_key(), encrypted_data_keys=[] + ) + assert mock_generator.on_decrypt.called + assert mock_child_3.on_decrypt.called + assert not mock_child_1.called + assert not mock_child_2.called diff --git a/test/unit/test_utils.py b/test/unit/test_utils.py index 192c1c830..b1374a09d 100644 --- a/test/unit/test_utils.py +++ b/test/unit/test_utils.py @@ -13,22 +13,15 @@ # language governing permissions and limitations under the License. """Test suite for aws_encryption_sdk.internal.utils""" import io -import os import pytest -from cryptography.hazmat.backends import default_backend -from cryptography.hazmat.primitives.asymmetric import rsa from mock import MagicMock, patch, sentinel import aws_encryption_sdk.identifiers import aws_encryption_sdk.internal.utils from aws_encryption_sdk.exceptions import InvalidDataKeyError, SerializationError, UnknownIdentityError -from aws_encryption_sdk.identifiers import Algorithm, KeyringTraceFlag, WrappingAlgorithm from aws_encryption_sdk.internal.defaults import MAX_FRAME_SIZE, MESSAGE_ID_LENGTH -from aws_encryption_sdk.keyring.multi_keyring import MultiKeyring -from aws_encryption_sdk.keyring.raw_keyring import Keyring, RawAESKeyring, RawRSAKeyring -from aws_encryption_sdk.materials_managers import DecryptionMaterials, EncryptionMaterials -from aws_encryption_sdk.structures import DataKey, EncryptedDataKey, KeyringTrace, MasterKeyInfo, RawDataKey +from aws_encryption_sdk.structures import DataKey, EncryptedDataKey, MasterKeyInfo, RawDataKey from .test_values import VALUES from .unit_test_utils import assert_prepped_stream_identity @@ -36,202 +29,6 @@ pytestmark = [pytest.mark.unit, pytest.mark.local] -try: # Python 3.5.0 and 3.5.1 have incompatible typing modules - from typing import Iterable # noqa pylint: disable=unused-import -except ImportError: # pragma: no cover - # We only actually need these imports when running the mypy checks - pass - - -_ENCRYPTION_CONTEXT = {"encryption": "context", "values": "here"} -_PROVIDER_ID = "Random Raw Keys" -_KEY_ID = b"5325b043-5843-4629-869c-64794af77ada" -_WRAPPING_KEY = b"\xeby-\x80A6\x15rA8\x83#,\xe4\xab\xac`\xaf\x99Z\xc1\xce\xdb\xb6\x0f\xb7\x805\xb2\x14J3" -_SIGNING_KEY = b"aws-crypto-public-key" -_DATA_KEY = ( - b"\x00\xfa\x8c\xdd\x08Au\xc6\x92_4\xc5\xfb\x90\xaf\x8f\xa1D\xaf\xcc\xd25" b"\xa8\x0b\x0b\x16\x92\x91W\x01\xb7\x84" -) -_WRAPPING_KEY_AES = b"\xeby-\x80A6\x15rA8\x83#,\xe4\xab\xac`\xaf\x99Z\xc1\xce\xdb\xb6\x0f\xb7\x805\xb2\x14J3" - - -class IdentityKeyring(Keyring): - def on_encrypt(self, encryption_materials): - # type: (EncryptionMaterials) -> EncryptionMaterials - return encryption_materials - - def on_decrypt(self, decryption_materials, encrypted_data_keys): - # type: (DecryptionMaterials, Iterable[EncryptedDataKey]) -> DecryptionMaterials - return decryption_materials - - -class OnlyGenerateKeyring(Keyring): - def on_encrypt(self, encryption_materials): - # type: (EncryptionMaterials) -> EncryptionMaterials - if encryption_materials.data_encryption_key is None: - key_provider = MasterKeyInfo(provider_id=_PROVIDER_ID, key_info=_KEY_ID) - data_encryption_key = RawDataKey( - key_provider=key_provider, data_key=os.urandom(encryption_materials.algorithm.kdf_input_len) - ) - encryption_materials.add_data_encryption_key( - data_encryption_key=data_encryption_key, - keyring_trace=KeyringTrace( - wrapping_key=key_provider, flags={KeyringTraceFlag.WRAPPING_KEY_GENERATED_DATA_KEY} - ), - ) - return encryption_materials - - def on_decrypt(self, decryption_materials, encrypted_data_keys): - # type: (DecryptionMaterials, Iterable[EncryptedDataKey]) -> DecryptionMaterials - return decryption_materials - - -def get_identity_keyring(): - return IdentityKeyring() - - -def get_keyring_which_only_generates(): - return OnlyGenerateKeyring() - - -def get_encryption_materials_with_data_key(): - return EncryptionMaterials( - algorithm=Algorithm.AES_256_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384, - data_encryption_key=RawDataKey( - key_provider=MasterKeyInfo(provider_id=_PROVIDER_ID, key_info=_KEY_ID), - data_key=b'*!\xa1"^-(\xf3\x105\x05i@B\xc2\xa2\xb7\xdd\xd5\xd5\xa9\xddm\xfae\xa8\\$\xf9d\x1e(', - ), - encryption_context=_ENCRYPTION_CONTEXT, - signing_key=_SIGNING_KEY, - keyring_trace=[ - KeyringTrace( - wrapping_key=MasterKeyInfo(provider_id=_PROVIDER_ID, key_info=_KEY_ID), - flags={KeyringTraceFlag.WRAPPING_KEY_GENERATED_DATA_KEY}, - ) - ], - ) - - -def get_encryption_materials_without_data_key(): - return EncryptionMaterials( - algorithm=Algorithm.AES_256_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384, - encryption_context=_ENCRYPTION_CONTEXT, - signing_key=_SIGNING_KEY, - ) - - -def get_encryption_materials_with_encrypted_data_key(): - return EncryptionMaterials( - algorithm=Algorithm.AES_256_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384, - data_encryption_key=RawDataKey( - key_provider=MasterKeyInfo(provider_id=_PROVIDER_ID, key_info=_KEY_ID), - data_key=b'*!\xa1"^-(\xf3\x105\x05i@B\xc2\xa2\xb7\xdd\xd5\xd5\xa9\xddm\xfae\xa8\\$\xf9d\x1e(', - ), - encrypted_data_keys=[ - EncryptedDataKey( - key_provider=MasterKeyInfo(provider_id=_PROVIDER_ID, key_info=_KEY_ID), - encrypted_data_key=b"\xde^\x97\x7f\x84\xe9\x9e\x98\xd0\xe2\xf8\xd5\xcb\xe9\x7f.}\x87\x16,\x11n#\xc8p" - b"\xdb\xbf\x94\x86*Q\x06\xd2\xf5\xdah\x08\xa4p\x81\xf7\xf4G\x07FzE\xde", - ) - ], - encryption_context=_ENCRYPTION_CONTEXT, - signing_key=_SIGNING_KEY, - keyring_trace=[ - KeyringTrace( - wrapping_key=MasterKeyInfo(provider_id=_PROVIDER_ID, key_info=_KEY_ID), - flags={ - KeyringTraceFlag.WRAPPING_KEY_GENERATED_DATA_KEY, - KeyringTraceFlag.WRAPPING_KEY_ENCRYPTED_DATA_KEY, - }, - ) - ], - ) - - -def get_decryption_materials_with_data_key(): - return DecryptionMaterials( - algorithm=Algorithm.AES_256_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384, - data_encryption_key=RawDataKey( - key_provider=MasterKeyInfo(provider_id=_PROVIDER_ID, key_info=_KEY_ID), - data_key=b'*!\xa1"^-(\xf3\x105\x05i@B\xc2\xa2\xb7\xdd\xd5\xd5\xa9\xddm\xfae\xa8\\$\xf9d\x1e(', - ), - encryption_context=_ENCRYPTION_CONTEXT, - verification_key=b"ex_verification_key", - keyring_trace=[ - KeyringTrace( - wrapping_key=MasterKeyInfo(provider_id=_PROVIDER_ID, key_info=_KEY_ID), - flags={KeyringTraceFlag.WRAPPING_KEY_DECRYPTED_DATA_KEY}, - ) - ], - ) - - -def get_decryption_materials_without_data_key(): - return DecryptionMaterials(encryption_context=_ENCRYPTION_CONTEXT, verification_key=b"ex_verification_key") - - -def get_multi_keyring_with_generator_and_children(): - return MultiKeyring( - generator=RawAESKeyring( - key_namespace=_PROVIDER_ID, - key_name=_KEY_ID, - wrapping_algorithm=WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING, - wrapping_key=_WRAPPING_KEY_AES, - ), - children=[ - RawRSAKeyring( - key_namespace=_PROVIDER_ID, - key_name=_KEY_ID, - wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, - private_wrapping_key=rsa.generate_private_key( - public_exponent=65537, key_size=2048, backend=default_backend() - ), - ), - RawRSAKeyring( - key_namespace=_PROVIDER_ID, - key_name=_KEY_ID, - wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, - private_wrapping_key=rsa.generate_private_key( - public_exponent=65537, key_size=2048, backend=default_backend() - ), - ), - ], - ) - - -def get_multi_keyring_with_no_children(): - return MultiKeyring( - generator=RawRSAKeyring( - key_namespace=_PROVIDER_ID, - key_name=_KEY_ID, - wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, - private_wrapping_key=rsa.generate_private_key( - public_exponent=65537, key_size=2048, backend=default_backend() - ), - ) - ) - - -def get_multi_keyring_with_no_generator(): - return MultiKeyring( - children=[ - RawRSAKeyring( - key_namespace=_PROVIDER_ID, - key_name=_KEY_ID, - wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, - private_wrapping_key=rsa.generate_private_key( - public_exponent=65537, key_size=2048, backend=default_backend() - ), - ), - RawAESKeyring( - key_namespace=_PROVIDER_ID, - key_name=_KEY_ID, - wrapping_algorithm=WrappingAlgorithm.AES_128_GCM_IV12_TAG16_NO_PADDING, - wrapping_key=_WRAPPING_KEY_AES, - ), - ] - ) - - def test_prep_stream_data_passthrough(): test = aws_encryption_sdk.internal.utils.prep_stream_data(io.BytesIO(b"some data")) diff --git a/test/unit/unit_test_utils.py b/test/unit/unit_test_utils.py index 6b0a84bdc..8c453a85b 100644 --- a/test/unit/unit_test_utils.py +++ b/test/unit/unit_test_utils.py @@ -14,8 +14,197 @@ import copy import io import itertools +import os +from cryptography.hazmat.backends import default_backend +from cryptography.hazmat.primitives.asymmetric import rsa + +from aws_encryption_sdk.identifiers import Algorithm, KeyringTraceFlag, WrappingAlgorithm from aws_encryption_sdk.internal.utils.streams import InsistentReaderBytesIO +from aws_encryption_sdk.keyring.multi_keyring import MultiKeyring +from aws_encryption_sdk.keyring.raw_keyring import Keyring, RawAESKeyring, RawRSAKeyring +from aws_encryption_sdk.materials_managers import DecryptionMaterials, EncryptionMaterials +from aws_encryption_sdk.structures import EncryptedDataKey, KeyringTrace, MasterKeyInfo, RawDataKey + +_ENCRYPTION_CONTEXT = {"encryption": "context", "values": "here"} +_PROVIDER_ID = "Random Raw Keys" +_KEY_ID = b"5325b043-5843-4629-869c-64794af77ada" +_WRAPPING_KEY = b"\xeby-\x80A6\x15rA8\x83#,\xe4\xab\xac`\xaf\x99Z\xc1\xce\xdb\xb6\x0f\xb7\x805\xb2\x14J3" +_SIGNING_KEY = b"aws-crypto-public-key" +_DATA_KEY = ( + b"\x00\xfa\x8c\xdd\x08Au\xc6\x92_4\xc5\xfb\x90\xaf\x8f\xa1D\xaf\xcc\xd25" b"\xa8\x0b\x0b\x16\x92\x91W\x01\xb7\x84" +) +_WRAPPING_KEY_AES = b"\xeby-\x80A6\x15rA8\x83#,\xe4\xab\xac`\xaf\x99Z\xc1\xce\xdb\xb6\x0f\xb7\x805\xb2\x14J3" + + +class IdentityKeyring(Keyring): + def on_encrypt(self, encryption_materials): + # type: (EncryptionMaterials) -> EncryptionMaterials + return encryption_materials + + def on_decrypt(self, decryption_materials, encrypted_data_keys): + # type: (DecryptionMaterials, Iterable[EncryptedDataKey]) -> DecryptionMaterials + return decryption_materials + + +class OnlyGenerateKeyring(Keyring): + def on_encrypt(self, encryption_materials): + # type: (EncryptionMaterials) -> EncryptionMaterials + if encryption_materials.data_encryption_key is None: + key_provider = MasterKeyInfo(provider_id=_PROVIDER_ID, key_info=_KEY_ID) + data_encryption_key = RawDataKey( + key_provider=key_provider, data_key=os.urandom(encryption_materials.algorithm.kdf_input_len) + ) + encryption_materials.add_data_encryption_key( + data_encryption_key=data_encryption_key, + keyring_trace=KeyringTrace( + wrapping_key=key_provider, flags={KeyringTraceFlag.WRAPPING_KEY_GENERATED_DATA_KEY} + ), + ) + return encryption_materials + + def on_decrypt(self, decryption_materials, encrypted_data_keys): + # type: (DecryptionMaterials, Iterable[EncryptedDataKey]) -> DecryptionMaterials + return decryption_materials + + +def get_encryption_materials_with_data_key(): + return EncryptionMaterials( + algorithm=Algorithm.AES_256_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384, + data_encryption_key=RawDataKey( + key_provider=MasterKeyInfo(provider_id=_PROVIDER_ID, key_info=_KEY_ID), + data_key=b'*!\xa1"^-(\xf3\x105\x05i@B\xc2\xa2\xb7\xdd\xd5\xd5\xa9\xddm\xfae\xa8\\$\xf9d\x1e(', + ), + encryption_context=_ENCRYPTION_CONTEXT, + signing_key=_SIGNING_KEY, + keyring_trace=[ + KeyringTrace( + wrapping_key=MasterKeyInfo(provider_id=_PROVIDER_ID, key_info=_KEY_ID), + flags={KeyringTraceFlag.WRAPPING_KEY_GENERATED_DATA_KEY}, + ) + ], + ) + + +def get_encryption_materials_without_data_key(): + return EncryptionMaterials( + algorithm=Algorithm.AES_256_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384, + encryption_context=_ENCRYPTION_CONTEXT, + signing_key=_SIGNING_KEY, + ) + + +def get_encryption_materials_with_encrypted_data_key(): + return EncryptionMaterials( + algorithm=Algorithm.AES_256_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384, + data_encryption_key=RawDataKey( + key_provider=MasterKeyInfo(provider_id=_PROVIDER_ID, key_info=_KEY_ID), + data_key=b'*!\xa1"^-(\xf3\x105\x05i@B\xc2\xa2\xb7\xdd\xd5\xd5\xa9\xddm\xfae\xa8\\$\xf9d\x1e(', + ), + encrypted_data_keys=[ + EncryptedDataKey( + key_provider=MasterKeyInfo(provider_id=_PROVIDER_ID, key_info=_KEY_ID), + encrypted_data_key=b"\xde^\x97\x7f\x84\xe9\x9e\x98\xd0\xe2\xf8\xd5\xcb\xe9\x7f.}\x87\x16,\x11n#\xc8p" + b"\xdb\xbf\x94\x86*Q\x06\xd2\xf5\xdah\x08\xa4p\x81\xf7\xf4G\x07FzE\xde", + ) + ], + encryption_context=_ENCRYPTION_CONTEXT, + signing_key=_SIGNING_KEY, + keyring_trace=[ + KeyringTrace( + wrapping_key=MasterKeyInfo(provider_id=_PROVIDER_ID, key_info=_KEY_ID), + flags={ + KeyringTraceFlag.WRAPPING_KEY_GENERATED_DATA_KEY, + KeyringTraceFlag.WRAPPING_KEY_ENCRYPTED_DATA_KEY, + }, + ) + ], + ) + + +def get_decryption_materials_with_data_key(): + return DecryptionMaterials( + algorithm=Algorithm.AES_256_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384, + data_encryption_key=RawDataKey( + key_provider=MasterKeyInfo(provider_id=_PROVIDER_ID, key_info=_KEY_ID), + data_key=b'*!\xa1"^-(\xf3\x105\x05i@B\xc2\xa2\xb7\xdd\xd5\xd5\xa9\xddm\xfae\xa8\\$\xf9d\x1e(', + ), + encryption_context=_ENCRYPTION_CONTEXT, + verification_key=b"ex_verification_key", + keyring_trace=[ + KeyringTrace( + wrapping_key=MasterKeyInfo(provider_id=_PROVIDER_ID, key_info=_KEY_ID), + flags={KeyringTraceFlag.WRAPPING_KEY_DECRYPTED_DATA_KEY}, + ) + ], + ) + + +def get_decryption_materials_without_data_key(): + return DecryptionMaterials(encryption_context=_ENCRYPTION_CONTEXT, verification_key=b"ex_verification_key") + + +def get_multi_keyring_with_generator_and_children(): + return MultiKeyring( + generator=RawAESKeyring( + key_namespace=_PROVIDER_ID, + key_name=_KEY_ID, + wrapping_algorithm=WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING, + wrapping_key=_WRAPPING_KEY_AES, + ), + children=[ + RawRSAKeyring( + key_namespace=_PROVIDER_ID, + key_name=_KEY_ID, + wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, + private_wrapping_key=rsa.generate_private_key( + public_exponent=65537, key_size=2048, backend=default_backend() + ), + ), + RawRSAKeyring( + key_namespace=_PROVIDER_ID, + key_name=_KEY_ID, + wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, + private_wrapping_key=rsa.generate_private_key( + public_exponent=65537, key_size=2048, backend=default_backend() + ), + ), + ], + ) + + +def get_multi_keyring_with_no_children(): + return MultiKeyring( + generator=RawRSAKeyring( + key_namespace=_PROVIDER_ID, + key_name=_KEY_ID, + wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, + private_wrapping_key=rsa.generate_private_key( + public_exponent=65537, key_size=2048, backend=default_backend() + ), + ) + ) + + +def get_multi_keyring_with_no_generator(): + return MultiKeyring( + children=[ + RawRSAKeyring( + key_namespace=_PROVIDER_ID, + key_name=_KEY_ID, + wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, + private_wrapping_key=rsa.generate_private_key( + public_exponent=65537, key_size=2048, backend=default_backend() + ), + ), + RawAESKeyring( + key_namespace=_PROVIDER_ID, + key_name=_KEY_ID, + wrapping_algorithm=WrappingAlgorithm.AES_128_GCM_IV12_TAG16_NO_PADDING, + wrapping_key=_WRAPPING_KEY_AES, + ), + ] + ) def all_valid_kwargs(valid_kwargs): From 901a8b2d9bca389506bade1bcfde8c085d791c2d Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Wed, 31 Jul 2019 18:02:07 -0700 Subject: [PATCH 57/61] Removed unused imports --- src/aws_encryption_sdk/keyring/multi_keyring.py | 7 +++++++ test/functional/test_f_multi_keyring.py | 2 +- test/unit/test_keyring_multi.py | 1 - test/unit/unit_test_utils.py | 8 ++++++++ 4 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/aws_encryption_sdk/keyring/multi_keyring.py b/src/aws_encryption_sdk/keyring/multi_keyring.py index b494a8618..088f0e5d0 100644 --- a/src/aws_encryption_sdk/keyring/multi_keyring.py +++ b/src/aws_encryption_sdk/keyring/multi_keyring.py @@ -20,6 +20,13 @@ from aws_encryption_sdk.keyring.base import DecryptionMaterials, EncryptedDataKey, EncryptionMaterials, Keyring +try: # Python 3.5.0 and 3.5.1 have incompatible typing modules + from typing import Iterable # noqa pylint: disable=unused-import +except ImportError: # pragma: no cover + # We only actually need these imports when running the mypy checks + pass + + @attr.s class MultiKeyring(Keyring): """Public class for Multi Keyring. diff --git a/test/functional/test_f_multi_keyring.py b/test/functional/test_f_multi_keyring.py index 7984c3a70..54d519f0b 100644 --- a/test/functional/test_f_multi_keyring.py +++ b/test/functional/test_f_multi_keyring.py @@ -16,7 +16,7 @@ from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives.asymmetric import rsa -from aws_encryption_sdk.identifiers import Algorithm, KeyringTraceFlag, WrappingAlgorithm +from aws_encryption_sdk.identifiers import KeyringTraceFlag, WrappingAlgorithm from aws_encryption_sdk.internal.defaults import ALGORITHM from aws_encryption_sdk.keyring.multi_keyring import MultiKeyring from aws_encryption_sdk.keyring.raw_keyring import RawAESKeyring, RawRSAKeyring diff --git a/test/unit/test_keyring_multi.py b/test/unit/test_keyring_multi.py index e2eb3d4d2..71524a5ca 100644 --- a/test/unit/test_keyring_multi.py +++ b/test/unit/test_keyring_multi.py @@ -11,7 +11,6 @@ # ANY KIND, either express or implied. See the License for the specific # language governing permissions and limitations under the License. """Unit tests for Multi keyring.""" -import itertools import pytest from mock import MagicMock diff --git a/test/unit/unit_test_utils.py b/test/unit/unit_test_utils.py index 8c453a85b..fdfb022a9 100644 --- a/test/unit/unit_test_utils.py +++ b/test/unit/unit_test_utils.py @@ -26,6 +26,14 @@ from aws_encryption_sdk.materials_managers import DecryptionMaterials, EncryptionMaterials from aws_encryption_sdk.structures import EncryptedDataKey, KeyringTrace, MasterKeyInfo, RawDataKey + +try: # Python 3.5.0 and 3.5.1 have incompatible typing modules + from typing import Iterable # noqa pylint: disable=unused-import +except ImportError: # pragma: no cover + # We only actually need these imports when running the mypy checks + pass + + _ENCRYPTION_CONTEXT = {"encryption": "context", "values": "here"} _PROVIDER_ID = "Random Raw Keys" _KEY_ID = b"5325b043-5843-4629-869c-64794af77ada" From 91bddc7dcf58946c7c68d8d8f51f0fb73bd7ce0c Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Wed, 31 Jul 2019 18:08:08 -0700 Subject: [PATCH 58/61] Resolved formatting errors --- src/aws_encryption_sdk/keyring/multi_keyring.py | 1 - test/unit/unit_test_utils.py | 1 - 2 files changed, 2 deletions(-) diff --git a/src/aws_encryption_sdk/keyring/multi_keyring.py b/src/aws_encryption_sdk/keyring/multi_keyring.py index 088f0e5d0..9c51eefc2 100644 --- a/src/aws_encryption_sdk/keyring/multi_keyring.py +++ b/src/aws_encryption_sdk/keyring/multi_keyring.py @@ -19,7 +19,6 @@ from aws_encryption_sdk.exceptions import EncryptKeyError, GenerateKeyError from aws_encryption_sdk.keyring.base import DecryptionMaterials, EncryptedDataKey, EncryptionMaterials, Keyring - try: # Python 3.5.0 and 3.5.1 have incompatible typing modules from typing import Iterable # noqa pylint: disable=unused-import except ImportError: # pragma: no cover diff --git a/test/unit/unit_test_utils.py b/test/unit/unit_test_utils.py index fdfb022a9..ca818fdb6 100644 --- a/test/unit/unit_test_utils.py +++ b/test/unit/unit_test_utils.py @@ -26,7 +26,6 @@ from aws_encryption_sdk.materials_managers import DecryptionMaterials, EncryptionMaterials from aws_encryption_sdk.structures import EncryptedDataKey, KeyringTrace, MasterKeyInfo, RawDataKey - try: # Python 3.5.0 and 3.5.1 have incompatible typing modules from typing import Iterable # noqa pylint: disable=unused-import except ImportError: # pragma: no cover From dc0b50876048776d9081c57caace264944978aa2 Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Thu, 1 Aug 2019 15:49:24 -0700 Subject: [PATCH 59/61] Made suggested changes - partial --- test/unit/test_keyring_multi.py | 51 +++++++++++++++------------------ 1 file changed, 23 insertions(+), 28 deletions(-) diff --git a/test/unit/test_keyring_multi.py b/test/unit/test_keyring_multi.py index 71524a5ca..10d1db07e 100644 --- a/test/unit/test_keyring_multi.py +++ b/test/unit/test_keyring_multi.py @@ -58,31 +58,31 @@ def keyring_which_only_generates(): @pytest.fixture def mock_generator(): - mock_generator = MagicMock() - mock_generator.__class__ = RawAESKeyring - return mock_generator + mock_generator_keyring = MagicMock() + mock_generator_keyring.__class__ = RawAESKeyring + return mock_generator_keyring @pytest.fixture def mock_child_1(): - mock_child_1 = MagicMock() - mock_child_1.__class__ = RawAESKeyring - return mock_child_1 + mock_child_1_keyring = MagicMock() + mock_child_1_keyring.__class__ = RawAESKeyring + return mock_child_1_keyring @pytest.fixture def mock_child_2(): - mock_child_2 = MagicMock() - mock_child_2.__class__ = RawAESKeyring - return mock_child_2 + mock_child_2_keyring = MagicMock() + mock_child_2_keyring.__class__ = RawAESKeyring + return mock_child_2_keyring @pytest.fixture def mock_child_3(): - mock_child_3 = MagicMock() - mock_child_3.__class__ = RawAESKeyring - mock_child_3.on_decrypt.return_value = get_decryption_materials_with_data_key() - return mock_child_3 + mock_child_3_keyring = MagicMock() + mock_child_3_keyring.__class__ = RawAESKeyring + mock_child_3_keyring.on_decrypt.return_value = get_decryption_materials_with_data_key() + return mock_child_3_keyring @pytest.fixture @@ -96,25 +96,21 @@ def test_parent(): def test_keyring_with_generator_but_no_children(): - test_multi_keyring = MultiKeyring( - generator=RawAESKeyring( + generator_keyring = RawAESKeyring( key_namespace=_PROVIDER_ID, key_name=_KEY_ID, wrapping_key=_WRAPPING_KEY_AES, wrapping_algorithm=WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING, ) + test_multi_keyring = MultiKeyring( + generator=generator_keyring ) - assert isinstance(test_multi_keyring.generator, Keyring) - assert test_multi_keyring.generator.key_namespace == _PROVIDER_ID - assert test_multi_keyring.generator.key_name == _KEY_ID - assert test_multi_keyring.generator._wrapping_key == _WRAPPING_KEY_AES - assert test_multi_keyring.generator._wrapping_algorithm == WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING - assert test_multi_keyring.children == () + assert test_multi_keyring.generator is generator_keyring + assert not test_multi_keyring.children def test_keyring_with_children_but_no_generator(): - test_multi_keyring = MultiKeyring( - children=[ + children_keyring = [ RawAESKeyring( key_namespace=_PROVIDER_ID, key_name=_KEY_ID, @@ -122,12 +118,10 @@ def test_keyring_with_children_but_no_generator(): wrapping_algorithm=WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING, ) ] + test_multi_keyring = MultiKeyring( + children=children_keyring ) - assert len(test_multi_keyring.children) == 1 - assert test_multi_keyring.children[0].key_namespace == _PROVIDER_ID - assert test_multi_keyring.children[0].key_name == _KEY_ID - assert test_multi_keyring.children[0]._wrapping_key == _WRAPPING_KEY_AES - assert test_multi_keyring.children[0]._wrapping_algorithm == WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING + assert test_multi_keyring.children is children_keyring assert test_multi_keyring.generator is None @@ -157,6 +151,7 @@ def test_decryption_keyrings(): assert test_multi_keyring.generator in test_multi_keyring._decryption_keyrings for child_keyring in test_multi_keyring.children: assert child_keyring in test_multi_keyring._decryption_keyrings + # assert len(list(test_multi_keyring._decryption_keyrings)) == len(test_multi_keyring.children) + 1 def test_on_encrypt_with_no_generator_no_data_encryption_key(): From 66a552544c44cdeab434a675148355e164891b35 Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Thu, 1 Aug 2019 17:09:05 -0700 Subject: [PATCH 60/61] Made all suggested changes --- .../keyring/multi_keyring.py | 2 +- test/unit/test_keyring_multi.py | 32 ++++++++----------- 2 files changed, 15 insertions(+), 19 deletions(-) diff --git a/src/aws_encryption_sdk/keyring/multi_keyring.py b/src/aws_encryption_sdk/keyring/multi_keyring.py index 9c51eefc2..f43820be5 100644 --- a/src/aws_encryption_sdk/keyring/multi_keyring.py +++ b/src/aws_encryption_sdk/keyring/multi_keyring.py @@ -49,7 +49,7 @@ def __attrs_post_init__(self): raise TypeError("At least one of generator or children must be provided") _generator = (self.generator,) if self.generator is not None else () - self._decryption_keyrings = itertools.chain(_generator, self.children) + self._decryption_keyrings = list(itertools.chain(_generator, self.children)) def on_encrypt(self, encryption_materials): # type: (EncryptionMaterials) -> EncryptionMaterials diff --git a/test/unit/test_keyring_multi.py b/test/unit/test_keyring_multi.py index 10d1db07e..6b66a490f 100644 --- a/test/unit/test_keyring_multi.py +++ b/test/unit/test_keyring_multi.py @@ -97,30 +97,26 @@ def test_parent(): def test_keyring_with_generator_but_no_children(): generator_keyring = RawAESKeyring( - key_namespace=_PROVIDER_ID, - key_name=_KEY_ID, - wrapping_key=_WRAPPING_KEY_AES, - wrapping_algorithm=WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING, - ) - test_multi_keyring = MultiKeyring( - generator=generator_keyring + key_namespace=_PROVIDER_ID, + key_name=_KEY_ID, + wrapping_key=_WRAPPING_KEY_AES, + wrapping_algorithm=WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING, ) + test_multi_keyring = MultiKeyring(generator=generator_keyring) assert test_multi_keyring.generator is generator_keyring assert not test_multi_keyring.children def test_keyring_with_children_but_no_generator(): children_keyring = [ - RawAESKeyring( - key_namespace=_PROVIDER_ID, - key_name=_KEY_ID, - wrapping_key=_WRAPPING_KEY_AES, - wrapping_algorithm=WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING, - ) - ] - test_multi_keyring = MultiKeyring( - children=children_keyring - ) + RawAESKeyring( + key_namespace=_PROVIDER_ID, + key_name=_KEY_ID, + wrapping_key=_WRAPPING_KEY_AES, + wrapping_algorithm=WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING, + ) + ] + test_multi_keyring = MultiKeyring(children=children_keyring) assert test_multi_keyring.children is children_keyring assert test_multi_keyring.generator is None @@ -151,7 +147,7 @@ def test_decryption_keyrings(): assert test_multi_keyring.generator in test_multi_keyring._decryption_keyrings for child_keyring in test_multi_keyring.children: assert child_keyring in test_multi_keyring._decryption_keyrings - # assert len(list(test_multi_keyring._decryption_keyrings)) == len(test_multi_keyring.children) + 1 + assert len(test_multi_keyring._decryption_keyrings) == len(test_multi_keyring.children) + 1 def test_on_encrypt_with_no_generator_no_data_encryption_key(): From ca9b904898d742d04588acdac4e2af1b56d9507b Mon Sep 17 00:00:00 2001 From: mattsb42-aws Date: Fri, 2 Aug 2019 16:09:12 -0700 Subject: [PATCH 61/61] apply autoformatting x_x --- test/unit/unit_test_utils.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/unit/unit_test_utils.py b/test/unit/unit_test_utils.py index f2f9b3a5f..1e5d073e8 100644 --- a/test/unit/unit_test_utils.py +++ b/test/unit/unit_test_utils.py @@ -131,7 +131,6 @@ def get_encryption_materials_with_data_key(): ) - def get_encryption_materials_with_data_encryption_key(): return EncryptionMaterials( algorithm=Algorithm.AES_256_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384, @@ -242,7 +241,6 @@ def get_decryption_materials_with_data_key(): ) - def get_decryption_materials_with_data_encryption_key(): return DecryptionMaterials( algorithm=Algorithm.AES_256_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384,