From 0d2963176e4b3d4d298876189870fd7f6fbc848e Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Tue, 18 Jun 2019 14:07:50 -0700 Subject: [PATCH 001/119] 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 002/119] 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 003/119] 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 004/119] 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 005/119] 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 006/119] 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 007/119] 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 008/119] 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 009/119] 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 010/119] 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 011/119] 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 012/119] 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 013/119] 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 745c9ed34a068a702e568f759db3c4520beaacc4 Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Thu, 27 Jun 2019 16:41:21 -0700 Subject: [PATCH 014/119] Changes in raw keyrings according to new keyring materials --- src/aws_encryption_sdk/keyring/raw_keyring.py | 240 ++++++++++-------- 1 file changed, 135 insertions(+), 105 deletions(-) diff --git a/src/aws_encryption_sdk/keyring/raw_keyring.py b/src/aws_encryption_sdk/keyring/raw_keyring.py index 74e19c653..71321e08d 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,108 @@ 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) - key_provider = MasterKeyInfo(provider_id=key_namespace, key_info=key_name) + # Check if data key is generated + if not plaintext_data_key: + return EncryptKeyError("Unable to generate data encryption key.") - 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, + # 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 + + +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 + 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 + + +@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,76 +137,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 - ) - - 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 - 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) ): - 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 + 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. @@ -137,56 +197,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 - ) - - 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: - 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 + 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) + return decryption_materials From bb163bc0da10d776e5c3171cef22cb007e731c7e Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Thu, 27 Jun 2019 16:53:19 -0700 Subject: [PATCH 015/119] Updated with autoformat --- src/aws_encryption_sdk/keyring/raw_keyring.py | 41 +++++++++---------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/src/aws_encryption_sdk/keyring/raw_keyring.py b/src/aws_encryption_sdk/keyring/raw_keyring.py index 71321e08d..50b1661ca 100644 --- a/src/aws_encryption_sdk/keyring/raw_keyring.py +++ b/src/aws_encryption_sdk/keyring/raw_keyring.py @@ -13,18 +13,18 @@ """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): @@ -39,9 +39,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 +57,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 @@ -75,22 +73,19 @@ def on_decrypt_helper(decryption_materials, wrapping_key, wrapping_algorithm, ke # 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) @@ -123,7 +118,7 @@ def __attrs_post_init__(self): 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): @@ -137,8 +132,9 @@ 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 = on_encrypt_helper( + encryption_materials, self._key_provider, self._wrapping_key, self._wrapping_algorithm, self.key_name + ) return encryption_materials @@ -160,8 +156,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 @@ -197,8 +194,9 @@ 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 = on_encrypt_helper( + encryption_materials, self._key_provider, self._wrapping_key, self._wrapping_algorithm, self.key_name + ) return encryption_materials @@ -216,7 +214,8 @@ def on_decrypt(self, decryption_materials, encrypted_data_keys): # 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 27fe8d93d92c8526957a902490139777f0f143bd Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Fri, 28 Jun 2019 09:44:27 -0700 Subject: [PATCH 016/119] Modified base --- src/aws_encryption_sdk/keyring/base.py | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/aws_encryption_sdk/keyring/base.py b/src/aws_encryption_sdk/keyring/base.py index 3c4689d70..3192a5688 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. @@ -22,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 """ From e8286ac0ffaf169b7abcdb74996eb90b9059f887 Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Fri, 28 Jun 2019 16:22:38 -0700 Subject: [PATCH 017/119] Corrected tox and flake errors --- src/aws_encryption_sdk/keyring/raw_keyring.py | 57 ++++++++++++++----- 1 file changed, 42 insertions(+), 15 deletions(-) diff --git a/src/aws_encryption_sdk/keyring/raw_keyring.py b/src/aws_encryption_sdk/keyring/raw_keyring.py index 50b1661ca..25b805727 100644 --- a/src/aws_encryption_sdk/keyring/raw_keyring.py +++ b/src/aws_encryption_sdk/keyring/raw_keyring.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. """Resources required for Raw Keyrings.""" + import os import struct @@ -28,6 +29,21 @@ 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: @@ -67,6 +83,21 @@ 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 @@ -96,11 +127,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 """ @@ -124,11 +155,9 @@ def __attrs_post_init__(self): 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 """ @@ -141,11 +170,11 @@ 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, 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 """ @@ -186,11 +215,9 @@ 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 """ @@ -203,11 +230,11 @@ 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, 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 """ From eef26e7a812c94a220fd39f34280e0553581af23 Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Mon, 1 Jul 2019 09:25:38 -0700 Subject: [PATCH 018/119] Docstring error correction --- src/aws_encryption_sdk/keyring/raw_keyring.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/aws_encryption_sdk/keyring/raw_keyring.py b/src/aws_encryption_sdk/keyring/raw_keyring.py index 25b805727..ebe61f3a9 100644 --- a/src/aws_encryption_sdk/keyring/raw_keyring.py +++ b/src/aws_encryption_sdk/keyring/raw_keyring.py @@ -30,7 +30,6 @@ 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. @@ -84,7 +83,6 @@ 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. @@ -126,7 +124,6 @@ def on_decrypt_helper(decryption_materials, wrapping_key, wrapping_algorithm, ke @attr.s class RawAESKeyring(Keyring): """Public class for Raw AES 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. @@ -154,7 +151,6 @@ def __attrs_post_init__(self): def on_encrypt(self, encryption_materials): """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. :type encryption_materials: aws_encryption_sdk.materials_managers.EncryptionMaterials :returns: Optionally modified encryption materials. @@ -169,7 +165,6 @@ 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: 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. @@ -194,7 +189,6 @@ def on_decrypt(self, decryption_materials, encrypted_data_keys): class RawRSAKeyring(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 @@ -214,7 +208,6 @@ 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: Encryption materials for the keyring to modify. :type encryption_materials: aws_encryption_sdk.materials_managers.EncryptionMaterials :returns: Optionally modified encryption materials. @@ -229,7 +222,6 @@ 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: 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. From 900a06444d794ac5791dd94da0c54418c8bb63c2 Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Mon, 1 Jul 2019 10:27:41 -0700 Subject: [PATCH 019/119] Added docstrings and corrected errors --- src/aws_encryption_sdk/keyring/raw_keyring.py | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/aws_encryption_sdk/keyring/raw_keyring.py b/src/aws_encryption_sdk/keyring/raw_keyring.py index ebe61f3a9..11b442777 100644 --- a/src/aws_encryption_sdk/keyring/raw_keyring.py +++ b/src/aws_encryption_sdk/keyring/raw_keyring.py @@ -30,6 +30,7 @@ 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. @@ -42,7 +43,6 @@ 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 """ - # Check if data key already exists if not encryption_materials.data_encryption_key: @@ -83,6 +83,7 @@ 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. @@ -95,7 +96,6 @@ 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 """ - # Check if plaintext data key exists if decryption_materials.data_key: return decryption_materials @@ -124,6 +124,7 @@ def on_decrypt_helper(decryption_materials, wrapping_key, wrapping_algorithm, ke @attr.s class RawAESKeyring(Keyring): """Public class for Raw AES 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. @@ -131,17 +132,16 @@ class RawAESKeyring(Keyring): :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): + """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 @@ -151,12 +151,12 @@ def __attrs_post_init__(self): def on_encrypt(self, encryption_materials): """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. :type encryption_materials: aws_encryption_sdk.materials_managers.EncryptionMaterials :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 ) @@ -165,6 +165,7 @@ 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: 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. @@ -172,7 +173,6 @@ def on_decrypt(self, decryption_materials, encrypted_data_keys): :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 ( @@ -189,6 +189,7 @@ def on_decrypt(self, decryption_materials, encrypted_data_keys): class RawRSAKeyring(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 @@ -198,7 +199,6 @@ class RawRSAKeyring(Keyring): :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, repr=False, validator=attr.validators.instance_of(WrappingKey)) @@ -208,12 +208,12 @@ 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: Encryption materials for the keyring to modify. :type encryption_materials: aws_encryption_sdk.materials_managers.EncryptionMaterials :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 ) @@ -222,6 +222,7 @@ 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: 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. @@ -229,7 +230,6 @@ def on_decrypt(self, decryption_materials, encrypted_data_keys): :returns: Optionally modified decryption materials. :rtype: aws_encryption_sdk.materials_managers.DecryptionMaterials """ - # Decrypt data key if encrypted_data_keys.key_provider == self._key_provider: From c500970d34b3a0bfde64c6985f84e6634e11cf84 Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Mon, 1 Jul 2019 11:09:24 -0700 Subject: [PATCH 020/119] Some more changes in docstrings --- src/aws_encryption_sdk/keyring/raw_keyring.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/aws_encryption_sdk/keyring/raw_keyring.py b/src/aws_encryption_sdk/keyring/raw_keyring.py index 11b442777..a0d9de69a 100644 --- a/src/aws_encryption_sdk/keyring/raw_keyring.py +++ b/src/aws_encryption_sdk/keyring/raw_keyring.py @@ -132,6 +132,7 @@ class RawAESKeyring(Keyring): :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)) @@ -199,6 +200,7 @@ class RawRSAKeyring(Keyring): :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, repr=False, validator=attr.validators.instance_of(WrappingKey)) From 8a00e15712fe45d3639d9d16c1768a9ea15e9819 Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Mon, 1 Jul 2019 11:55:51 -0700 Subject: [PATCH 021/119] Updating base API --- src/aws_encryption_sdk/keyring/base.py | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/src/aws_encryption_sdk/keyring/base.py b/src/aws_encryption_sdk/keyring/base.py index 3192a5688..770b53c0b 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,27 +28,26 @@ 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 """ From 250f55487967293063d6cf63387a94842100f4b0 Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Tue, 2 Jul 2019 15:22:54 -0700 Subject: [PATCH 022/119] Made all suggested changes --- 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 d8a8389e9bbf480b5e94bef026cb6bfe93ba197e Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Wed, 3 Jul 2019 09:24:19 -0700 Subject: [PATCH 023/119] Corrected tox and flake8 errors --- 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 8f9f73736ad519c736fe89e02b94d0166c389be7 Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Mon, 8 Jul 2019 11:36:36 -0700 Subject: [PATCH 024/119] Minor change in raw-keyrings --- src/aws_encryption_sdk/keyring/raw_keyring.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/aws_encryption_sdk/keyring/raw_keyring.py b/src/aws_encryption_sdk/keyring/raw_keyring.py index 0831dc757..55762e684 100644 --- a/src/aws_encryption_sdk/keyring/raw_keyring.py +++ b/src/aws_encryption_sdk/keyring/raw_keyring.py @@ -254,6 +254,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 9cd81ea0a4dec7466aa8f6d68742ecf026db86c3 Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Tue, 18 Jun 2019 14:07:50 -0700 Subject: [PATCH 025/119] 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 e3d075733b90876954e96cba16b369f8f4d53dca Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Tue, 18 Jun 2019 14:51:28 -0700 Subject: [PATCH 026/119] 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 fcb03c25f801b20b7a5427bf99a2347a70c46321 Mon Sep 17 00:00:00 2001 From: MeghaShetty Date: Tue, 18 Jun 2019 14:12:41 -0700 Subject: [PATCH 027/119] 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 ae78331e43861fe765f5cbc64ae4440ef496986d Mon Sep 17 00:00:00 2001 From: MeghaShetty Date: Tue, 18 Jun 2019 14:12:53 -0700 Subject: [PATCH 028/119] 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 f668ca4efb77323d5cceff4bb9654972b046407a Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Tue, 18 Jun 2019 15:36:18 -0700 Subject: [PATCH 029/119] 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 c06b1fa695c753451b10e961382554f369dfb62b Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Tue, 18 Jun 2019 16:07:06 -0700 Subject: [PATCH 030/119] 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 1e2a6726b3d9d4330e8e27bf6c94a57d2702760a Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Wed, 19 Jun 2019 12:58:14 -0700 Subject: [PATCH 031/119] 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 82feb006e101f92ae6acff7b34e5a49b4a816440 Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Wed, 19 Jun 2019 13:06:19 -0700 Subject: [PATCH 032/119] 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 11f9ce62aeb10af5ad9a97cfbef19b4b24465792 Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Thu, 20 Jun 2019 13:53:32 -0700 Subject: [PATCH 033/119] 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 7a345a57e0aa5f2be72910c5ccc9c72647af3329 Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Thu, 20 Jun 2019 14:16:36 -0700 Subject: [PATCH 034/119] 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 6ef9ea77fb0384311b68b493a5659e01b3a74154 Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Thu, 20 Jun 2019 14:19:54 -0700 Subject: [PATCH 035/119] 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 65767313c273e9a4c1fe0ec8e567c11dcee92a70 Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Thu, 20 Jun 2019 16:17:06 -0700 Subject: [PATCH 036/119] 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 5a87c0e702e3f05aff8440eaf842af9e7f2a2c63 Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Thu, 20 Jun 2019 16:59:54 -0700 Subject: [PATCH 037/119] 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 dd01e6b79d738d208f8f79aae12d896f5e4a8a5f Mon Sep 17 00:00:00 2001 From: mattsb42-aws Date: Thu, 20 Jun 2019 17:36:09 -0700 Subject: [PATCH 038/119] bump attrs to 19.1.0 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 7540d66bf..8378d126e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,5 @@ six boto3>=1.4.4 cryptography>=1.8.1 -attrs>=17.4.0 +attrs>=19.1.0 wrapt>=1.10.11 \ No newline at end of file From 82429fe3b8abb1cf6ecad12146f04c390bc3c37d Mon Sep 17 00:00:00 2001 From: mattsb42-aws Date: Thu, 20 Jun 2019 17:36:54 -0700 Subject: [PATCH 039/119] add keyring trace and integrate into updated encrytion/decryption materials --- src/aws_encryption_sdk/identifiers.py | 10 ++ .../materials_managers/__init__.py | 150 +++++++++++++++--- src/aws_encryption_sdk/structures.py | 16 ++ test/unit/test_material_managers.py | 76 +++++++-- test/unit/test_material_managers_default.py | 6 +- 5 files changed, 217 insertions(+), 41 deletions(-) diff --git a/src/aws_encryption_sdk/identifiers.py b/src/aws_encryption_sdk/identifiers.py index 1bd9bb1f1..0add9724d 100644 --- a/src/aws_encryption_sdk/identifiers.py +++ b/src/aws_encryption_sdk/identifiers.py @@ -328,3 +328,13 @@ class ContentAADString(Enum): FRAME_STRING_ID = b"AWSKMSEncryptionClient Frame" FINAL_FRAME_STRING_ID = b"AWSKMSEncryptionClient Final Frame" NON_FRAMED_STRING_ID = b"AWSKMSEncryptionClient Single Block" + + +class KeyRingTraceFlag(Enum): + """KeyRing Trace actions.""" + + WRAPPING_KEY_GENERATED_DATA_KEY = 1 + WRAPPING_KEY_ENCRYPTED_DATA_KEY = 2 + WRAPPING_KEY_DECRYPTED_DATA_KEY = 3 + WRAPPING_KEY_SIGNED_ENC_CTX = 4 + WRAPPING_KEY_VERIFIED_ENC_CTX = 5 diff --git a/src/aws_encryption_sdk/materials_managers/__init__.py b/src/aws_encryption_sdk/materials_managers/__init__.py index bc5230c51..18ebd7898 100644 --- a/src/aws_encryption_sdk/materials_managers/__init__.py +++ b/src/aws_encryption_sdk/materials_managers/__init__.py @@ -16,10 +16,11 @@ """ import attr import six +from attr.validators import deep_iterable, deep_mapping, instance_of, optional -from ..identifiers import Algorithm +from ..identifiers import Algorithm, KeyRingTraceFlag from ..internal.utils.streams import ROStream -from ..structures import DataKey +from ..structures import DataKey, EncryptedDataKey, KeyRingTrace @attr.s(hash=False) @@ -51,28 +52,87 @@ class EncryptionMaterialsRequest(object): ) -@attr.s(hash=False) -class EncryptionMaterials(object): +@attr.s +class CryptographicMaterials(object): + """Cryptographic materials core. + + .. versionadded:: 1.5.0 + + :param Algorithm algorithm: Algorithm to use for encrypting message + :param dict encryption_context: Encryption context tied to `encrypted_data_keys` + :param DataKey data_encryption_key: Plaintext data key to use for encrypting message + :param encrypted_data_keys: List of encrypted data keys + :type encrypted_data_keys: list of :class:`EncryptedDataKey` + :param keyring_trace: Any KeyRing trace entries + :type keyring_trace: list of :class:`KeyRingTrace` + """ + + algorithm = attr.ib(validator=optional(instance_of(Algorithm))) + encryption_context = attr.ib( + validator=optional( + deep_mapping(key_validator=instance_of(six.string_types), value_validator=instance_of(six.string_types)) + ) + ) + data_encryption_key = attr.ib(default=None, validator=optional(instance_of(DataKey))) + encrypted_data_keys = attr.ib( + default=attr.Factory(list), validator=optional(deep_iterable(member_validator=instance_of(EncryptedDataKey))) + ) + keyring_trace = attr.ib( + default=attr.Factory(list), validator=optional(deep_iterable(member_validator=instance_of(KeyRingTrace))) + ) + + +@attr.s(hash=False, init=False) +class EncryptionMaterials(CryptographicMaterials): """Encryption materials returned by a crypto material manager's `get_encryption_materials` method. .. versionadded:: 1.3.0 - :param algorithm: Algorithm to use for encrypting message - :type algorithm: aws_encryption_sdk.identifiers.Algorithm - :param data_encryption_key: Plaintext data key to use for encrypting message - :type data_encryption_key: aws_encryption_sdk.structures.DataKey - :param encrypted_data_keys: List of encrypted data keys - :type encrypted_data_keys: list of `aws_encryption_sdk.structures.EncryptedDataKey` + .. versionadded:: 1.5.0 + + The **keyring_trace** parameter. + + .. versionadded:: 1.5.0 + + 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 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` - :param bytes signing_key: Encoded signing key + :param bytes signing_key: Encoded signing key (optional) + :param keyring_trace: Any KeyRing trace entries (optional) + :type keyring_trace: list of :class:`KeyRingTrace` """ - algorithm = attr.ib(validator=attr.validators.instance_of(Algorithm)) - data_encryption_key = attr.ib(validator=attr.validators.instance_of(DataKey)) - encrypted_data_keys = attr.ib(validator=attr.validators.instance_of(set)) - encryption_context = attr.ib(validator=attr.validators.instance_of(dict)) signing_key = attr.ib(default=None, validator=attr.validators.optional(attr.validators.instance_of(bytes))) + def __init__( + self, + algorithm=None, + data_encryption_key=None, + encrypted_data_keys=None, + encryption_context=None, + signing_key=None, + **kwargs + ): + if algorithm is None: + raise TypeError("algorithm must not be None") + + if encryption_context is None: + raise TypeError("encryption_context must not be None") + + super(EncryptionMaterials, self).__init__( + algorithm=algorithm, + encryption_context=encryption_context, + data_encryption_key=data_encryption_key, + encrypted_data_keys=encrypted_data_keys, + **kwargs + ) + self.signing_key = signing_key + attr.validate(self) + @attr.s(hash=False) class DecryptionMaterialsRequest(object): @@ -92,16 +152,64 @@ class DecryptionMaterialsRequest(object): encryption_context = attr.ib(validator=attr.validators.instance_of(dict)) -@attr.s(hash=False) -class DecryptionMaterials(object): +_DEFAULT_SENTINEL = object() + + +@attr.s(hash=False, init=False) +class DecryptionMaterials(CryptographicMaterials): """Decryption materials returned by a crypto material manager's `decrypt_materials` method. .. versionadded:: 1.3.0 - :param data_key: Plaintext data key to use with message decryption - :type data_key: aws_encryption_sdk.structures.DataKey - :param bytes verification_key: Raw signature verification key + .. versionadded:: 1.5.0 + + The **algorithm**, **data_encryption_key**, **encrypted_data_keys**, + **encryption_context**, and **keyring_trace** parameters. + + .. versionadded:: 1.5.0 + + 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 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` (optional) + :param bytes verification_key: Raw signature verification key (optional) + :param keyring_trace: Any KeyRing trace entries (optional) + :type keyring_trace: list of :class:`KeyRingTrace` """ - data_key = attr.ib(validator=attr.validators.instance_of(DataKey)) verification_key = attr.ib(default=None, validator=attr.validators.optional(attr.validators.instance_of(bytes))) + + def __init__(self, data_key=_DEFAULT_SENTINEL, verification_key=None, **kwargs): + if any( + ( + data_key is _DEFAULT_SENTINEL and "data_encryption_key" not in kwargs, + data_key is not _DEFAULT_SENTINEL and "data_encryption_key" in kwargs, + ) + ): + raise TypeError("Exactly one of data_key or data_encryption_key must be set") + + if data_key is not _DEFAULT_SENTINEL and "data_encryption_key" not in kwargs: + kwargs["data_encryption_key"] = data_key + + for legacy_missing in ("algorithm", "encryption_context"): + if legacy_missing not in kwargs: + kwargs[legacy_missing] = None + + super(DecryptionMaterials, self).__init__(**kwargs) + + self.verification_key = verification_key + attr.validate(self) + + @property + def data_key(self): + """Backwards-compatible shim.""" + return self.data_encryption_key + + @data_key.setter + def data_key(self, value): + # type: (DataKey) -> None + """Backwards-compatible shim.""" + self.data_encryption_key = value diff --git a/src/aws_encryption_sdk/structures.py b/src/aws_encryption_sdk/structures.py index 8229d65fb..86b87b932 100644 --- a/src/aws_encryption_sdk/structures.py +++ b/src/aws_encryption_sdk/structures.py @@ -13,6 +13,7 @@ """Public data structures for aws_encryption_sdk.""" import attr import six +from attr.validators import deep_iterable, instance_of import aws_encryption_sdk.identifiers from aws_encryption_sdk.internal.str_ops import to_bytes, to_str @@ -104,3 +105,18 @@ class EncryptedDataKey(object): key_provider = attr.ib(hash=True, validator=attr.validators.instance_of(MasterKeyInfo)) encrypted_data_key = attr.ib(hash=True, validator=attr.validators.instance_of(bytes)) + + +@attr.s +class KeyRingTrace(object): + """Record of all actions that a KeyRing performed with a wrapping key. + + :param MasterKeyInfo wrapping_key: Wrapping key used + :param flags: Actions performed + :type flags: set of :class:`KeyRingTraceFlag` + """ + + wrapping_key = attr.ib(validator=instance_of(MasterKeyInfo)) + flags = attr.ib( + validator=deep_iterable(member_validator=instance_of(aws_encryption_sdk.identifiers.KeyRingTraceFlag)) + ) diff --git a/test/unit/test_material_managers.py b/test/unit/test_material_managers.py index fcd4977f5..9eb32a125 100644 --- a/test/unit/test_material_managers.py +++ b/test/unit/test_material_managers.py @@ -12,66 +12,93 @@ # language governing permissions and limitations under the License. """Test suite for aws_encryption_sdk.materials_managers""" import pytest -from mock import MagicMock +from mock import MagicMock, sentinel from pytest_mock import mocker # noqa pylint: disable=unused-import -from aws_encryption_sdk.identifiers import Algorithm +from aws_encryption_sdk.identifiers import KeyRingTraceFlag +from aws_encryption_sdk.internal.defaults import ALGORITHM from aws_encryption_sdk.internal.utils.streams import ROStream from aws_encryption_sdk.materials_managers import ( + CryptographicMaterials, DecryptionMaterials, DecryptionMaterialsRequest, EncryptionMaterials, EncryptionMaterialsRequest, ) -from aws_encryption_sdk.structures import DataKey +from aws_encryption_sdk.structures import DataKey, KeyRingTrace, MasterKeyInfo pytestmark = [pytest.mark.unit, pytest.mark.local] +_DATA_KEY = DataKey( + key_provider=MasterKeyInfo(provider_id="Provider", key_info=b"Info"), + data_key=b"1234567890123456789012", + encrypted_data_key=b"asdf", +) _VALID_KWARGS = { + "CryptographicMaterials": dict( + algorithm=ALGORITHM, + encryption_context={"additional": "data"}, + data_encryption_key=_DATA_KEY, + encrypted_data_keys=[], + keyring_trace=[ + KeyRingTrace( + wrapping_key=MasterKeyInfo(provider_id="Provider", key_info=b"Info"), + flags={KeyRingTraceFlag.WRAPPING_KEY_GENERATED_DATA_KEY}, + ) + ], + ), "EncryptionMaterialsRequest": dict( encryption_context={}, plaintext_rostream=MagicMock(__class__=ROStream), frame_length=5, - algorithm=MagicMock(__class__=Algorithm), + algorithm=ALGORITHM, plaintext_length=5, ), "EncryptionMaterials": dict( - algorithm=MagicMock(__class__=Algorithm), - data_encryption_key=MagicMock(__class__=DataKey), + algorithm=ALGORITHM, + data_encryption_key=_DATA_KEY, encrypted_data_keys=set([]), encryption_context={}, signing_key=b"", ), - "DecryptionMaterialsRequest": dict( - algorithm=MagicMock(__class__=Algorithm), encrypted_data_keys=set([]), encryption_context={} + "DecryptionMaterialsRequest": dict(algorithm=ALGORITHM, encrypted_data_keys=set([]), encryption_context={}), + "DecryptionMaterials": dict( + data_key=_DATA_KEY, verification_key=b"ex_verification_key", algorithm=ALGORITHM, encryption_context={} ), - "DecryptionMaterials": dict(data_key=MagicMock(__class__=DataKey), verification_key=b"ex_verification_key"), } +_REMOVE = object() @pytest.mark.parametrize( "attr_class, invalid_kwargs", ( + (CryptographicMaterials, dict(algorithm=1234)), + (CryptographicMaterials, dict(encryption_context=1234)), + (CryptographicMaterials, dict(data_encryption_key=1234)), + (CryptographicMaterials, dict(encrypted_data_keys=1234)), + (CryptographicMaterials, dict(keyring_trace=1234)), (EncryptionMaterialsRequest, dict(encryption_context=None)), (EncryptionMaterialsRequest, dict(frame_length="not an int")), (EncryptionMaterialsRequest, dict(algorithm="not an Algorithm or None")), (EncryptionMaterialsRequest, dict(plaintext_length="not an int or None")), (EncryptionMaterials, dict(algorithm=None)), - (EncryptionMaterials, dict(data_encryption_key=None)), - (EncryptionMaterials, dict(encrypted_data_keys=None)), (EncryptionMaterials, dict(encryption_context=None)), (EncryptionMaterials, dict(signing_key=u"not bytes or None")), (DecryptionMaterialsRequest, dict(algorithm=None)), (DecryptionMaterialsRequest, dict(encrypted_data_keys=None)), (DecryptionMaterialsRequest, dict(encryption_context=None)), - (DecryptionMaterials, dict(data_key=None)), (DecryptionMaterials, dict(verification_key=5555)), + (DecryptionMaterials, dict(data_key=_DATA_KEY, data_encryption_key=_DATA_KEY)), + (DecryptionMaterials, dict(data_key=_REMOVE, data_encryption_key=_REMOVE)), ), ) def test_attributes_fails(attr_class, invalid_kwargs): kwargs = _VALID_KWARGS[attr_class.__name__].copy() kwargs.update(invalid_kwargs) + purge_keys = [key for key, val in kwargs.items() if val is _REMOVE] + for key in purge_keys: + del kwargs[key] with pytest.raises(TypeError): attr_class(**kwargs) @@ -85,14 +112,29 @@ def test_encryption_materials_request_attributes_defaults(): def test_encryption_materials_defaults(): test = EncryptionMaterials( - algorithm=MagicMock(__class__=Algorithm), - data_encryption_key=MagicMock(__class__=DataKey), - encrypted_data_keys=set([]), - encryption_context={}, + algorithm=ALGORITHM, data_encryption_key=_DATA_KEY, encrypted_data_keys=set([]), encryption_context={} ) assert test.signing_key is None def test_decryption_materials_defaults(): - test = DecryptionMaterials(data_key=MagicMock(__class__=DataKey)) + test = DecryptionMaterials(data_key=_DATA_KEY) assert test.verification_key is None + assert test.algorithm is None + assert test.encryption_context is None + + +def test_decryption_materials_legacy_data_key_get(): + test = DecryptionMaterials(data_encryption_key=_DATA_KEY) + + assert test.data_encryption_key is _DATA_KEY + assert test.data_key is _DATA_KEY + + +def test_decryption_materials_legacy_data_key_set(): + test = DecryptionMaterials(data_encryption_key=_DATA_KEY) + + test.data_key = sentinel.data_key + + assert test.data_encryption_key is sentinel.data_key + assert test.data_key is sentinel.data_key diff --git a/test/unit/test_material_managers_default.py b/test/unit/test_material_managers_default.py index 9d6bd949f..6eeef525b 100644 --- a/test/unit/test_material_managers_default.py +++ b/test/unit/test_material_managers_default.py @@ -22,7 +22,7 @@ from aws_encryption_sdk.key_providers.base import MasterKeyProvider from aws_encryption_sdk.materials_managers import EncryptionMaterials from aws_encryption_sdk.materials_managers.default import DefaultCryptoMaterialsManager -from aws_encryption_sdk.structures import DataKey +from aws_encryption_sdk.structures import DataKey, EncryptedDataKey pytestmark = [pytest.mark.unit, pytest.mark.local] @@ -34,7 +34,7 @@ def patch_for_dcmm_encrypt(mocker): DefaultCryptoMaterialsManager._generate_signing_key_and_update_encryption_context.return_value = mock_signing_key mocker.patch.object(aws_encryption_sdk.materials_managers.default, "prepare_data_keys") mock_data_encryption_key = MagicMock(__class__=DataKey) - mock_encrypted_data_keys = set([mock_data_encryption_key]) + mock_encrypted_data_keys = set([MagicMock(__class__=EncryptedDataKey)]) result_pair = mock_data_encryption_key, mock_encrypted_data_keys aws_encryption_sdk.materials_managers.default.prepare_data_keys.return_value = result_pair yield result_pair, mock_signing_key @@ -128,7 +128,7 @@ def test_get_encryption_materials(patch_for_dcmm_encrypt): assert isinstance(test, EncryptionMaterials) assert test.algorithm is cmm.algorithm assert test.data_encryption_key is patch_for_dcmm_encrypt[0][0] - assert test.encrypted_data_keys is patch_for_dcmm_encrypt[0][1] + assert test.encrypted_data_keys == patch_for_dcmm_encrypt[0][1] assert test.encryption_context == encryption_context assert test.signing_key == patch_for_dcmm_encrypt[1] From 0dc48a28d77782f724479c29e22068c7a68ea4bd Mon Sep 17 00:00:00 2001 From: mattsb42-aws Date: Thu, 20 Jun 2019 17:40:06 -0700 Subject: [PATCH 040/119] s/KeyRing/Keyring/g --- src/aws_encryption_sdk/identifiers.py | 2 +- .../materials_managers/__init__.py | 12 ++++++------ src/aws_encryption_sdk/structures.py | 6 +++--- test/unit/test_material_managers.py | 8 ++++---- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/aws_encryption_sdk/identifiers.py b/src/aws_encryption_sdk/identifiers.py index 0add9724d..0bec8aacd 100644 --- a/src/aws_encryption_sdk/identifiers.py +++ b/src/aws_encryption_sdk/identifiers.py @@ -330,7 +330,7 @@ class ContentAADString(Enum): NON_FRAMED_STRING_ID = b"AWSKMSEncryptionClient Single Block" -class KeyRingTraceFlag(Enum): +class KeyringTraceFlag(Enum): """KeyRing Trace actions.""" WRAPPING_KEY_GENERATED_DATA_KEY = 1 diff --git a/src/aws_encryption_sdk/materials_managers/__init__.py b/src/aws_encryption_sdk/materials_managers/__init__.py index 18ebd7898..94fd30ece 100644 --- a/src/aws_encryption_sdk/materials_managers/__init__.py +++ b/src/aws_encryption_sdk/materials_managers/__init__.py @@ -18,9 +18,9 @@ import six from attr.validators import deep_iterable, deep_mapping, instance_of, optional -from ..identifiers import Algorithm, KeyRingTraceFlag +from ..identifiers import Algorithm, KeyringTraceFlag from ..internal.utils.streams import ROStream -from ..structures import DataKey, EncryptedDataKey, KeyRingTrace +from ..structures import DataKey, EncryptedDataKey, KeyringTrace @attr.s(hash=False) @@ -64,7 +64,7 @@ class CryptographicMaterials(object): :param encrypted_data_keys: List of encrypted data keys :type encrypted_data_keys: list of :class:`EncryptedDataKey` :param keyring_trace: Any KeyRing trace entries - :type keyring_trace: list of :class:`KeyRingTrace` + :type keyring_trace: list of :class:`KeyringTrace` """ algorithm = attr.ib(validator=optional(instance_of(Algorithm))) @@ -78,7 +78,7 @@ class CryptographicMaterials(object): default=attr.Factory(list), validator=optional(deep_iterable(member_validator=instance_of(EncryptedDataKey))) ) keyring_trace = attr.ib( - default=attr.Factory(list), validator=optional(deep_iterable(member_validator=instance_of(KeyRingTrace))) + default=attr.Factory(list), validator=optional(deep_iterable(member_validator=instance_of(KeyringTrace))) ) @@ -103,7 +103,7 @@ class EncryptionMaterials(CryptographicMaterials): :param dict encryption_context: Encryption context tied to `encrypted_data_keys` :param bytes signing_key: Encoded signing key (optional) :param keyring_trace: Any KeyRing trace entries (optional) - :type keyring_trace: list of :class:`KeyRingTrace` + :type keyring_trace: list of :class:`KeyringTrace` """ signing_key = attr.ib(default=None, validator=attr.validators.optional(attr.validators.instance_of(bytes))) @@ -177,7 +177,7 @@ class DecryptionMaterials(CryptographicMaterials): :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) - :type keyring_trace: list of :class:`KeyRingTrace` + :type keyring_trace: list of :class:`KeyringTrace` """ verification_key = attr.ib(default=None, validator=attr.validators.optional(attr.validators.instance_of(bytes))) diff --git a/src/aws_encryption_sdk/structures.py b/src/aws_encryption_sdk/structures.py index 86b87b932..aed2f9163 100644 --- a/src/aws_encryption_sdk/structures.py +++ b/src/aws_encryption_sdk/structures.py @@ -108,15 +108,15 @@ class EncryptedDataKey(object): @attr.s -class KeyRingTrace(object): +class KeyringTrace(object): """Record of all actions that a KeyRing performed with a wrapping key. :param MasterKeyInfo wrapping_key: Wrapping key used :param flags: Actions performed - :type flags: set of :class:`KeyRingTraceFlag` + :type flags: set of :class:`KeyringTraceFlag` """ wrapping_key = attr.ib(validator=instance_of(MasterKeyInfo)) flags = attr.ib( - validator=deep_iterable(member_validator=instance_of(aws_encryption_sdk.identifiers.KeyRingTraceFlag)) + validator=deep_iterable(member_validator=instance_of(aws_encryption_sdk.identifiers.KeyringTraceFlag)) ) diff --git a/test/unit/test_material_managers.py b/test/unit/test_material_managers.py index 9eb32a125..fa216c8d8 100644 --- a/test/unit/test_material_managers.py +++ b/test/unit/test_material_managers.py @@ -15,7 +15,7 @@ from mock import MagicMock, sentinel from pytest_mock import mocker # noqa pylint: disable=unused-import -from aws_encryption_sdk.identifiers import KeyRingTraceFlag +from aws_encryption_sdk.identifiers import KeyringTraceFlag from aws_encryption_sdk.internal.defaults import ALGORITHM from aws_encryption_sdk.internal.utils.streams import ROStream from aws_encryption_sdk.materials_managers import ( @@ -25,7 +25,7 @@ EncryptionMaterials, EncryptionMaterialsRequest, ) -from aws_encryption_sdk.structures import DataKey, KeyRingTrace, MasterKeyInfo +from aws_encryption_sdk.structures import DataKey, KeyringTrace, MasterKeyInfo pytestmark = [pytest.mark.unit, pytest.mark.local] @@ -42,9 +42,9 @@ data_encryption_key=_DATA_KEY, encrypted_data_keys=[], keyring_trace=[ - KeyRingTrace( + KeyringTrace( wrapping_key=MasterKeyInfo(provider_id="Provider", key_info=b"Info"), - flags={KeyRingTraceFlag.WRAPPING_KEY_GENERATED_DATA_KEY}, + flags={KeyringTraceFlag.WRAPPING_KEY_GENERATED_DATA_KEY}, ) ], ), From ea0b09d365ae96539b2c67c8f0193d10d99f0679 Mon Sep 17 00:00:00 2001 From: mattsb42-aws Date: Wed, 26 Jun 2019 20:10:05 -0700 Subject: [PATCH 041/119] align cryptographic materials and add write-only interface --- src/aws_encryption_sdk/exceptions.py | 14 + .../materials_managers/__init__.py | 279 ++++++++++++++--- src/aws_encryption_sdk/structures.py | 130 +++++--- test/unit/test_material_managers.py | 282 ++++++++++++++++-- test/unit/test_material_managers_default.py | 19 +- .../test_streaming_client_stream_encryptor.py | 2 +- test/unit/test_structures.py | 27 ++ 7 files changed, 638 insertions(+), 115 deletions(-) diff --git a/src/aws_encryption_sdk/exceptions.py b/src/aws_encryption_sdk/exceptions.py index a71d414c0..cd60ab6bd 100644 --- a/src/aws_encryption_sdk/exceptions.py +++ b/src/aws_encryption_sdk/exceptions.py @@ -53,6 +53,13 @@ class InvalidDataKeyError(AWSEncryptionSDKClientError): """Exception class for Invalid Data Keys.""" +class InvalidKeyringTraceError(AWSEncryptionSDKClientError): + """Exception class for invalid Keyring Traces. + + .. versionadded:: 1.5.0 + """ + + class InvalidProviderIdError(AWSEncryptionSDKClientError): """Exception class for Invalid Provider IDs.""" @@ -73,6 +80,13 @@ class DecryptKeyError(AWSEncryptionSDKClientError): """Exception class for errors encountered when MasterKeys try to decrypt data keys.""" +class SignatureKeyError(AWSEncryptionSDKClientError): + """Exception class for errors encountered with signing or verification keys. + + .. versionadded:: 1.5.0 + """ + + class ActionNotAllowedError(AWSEncryptionSDKClientError): """Exception class for errors encountered when attempting to perform unallowed actions.""" diff --git a/src/aws_encryption_sdk/materials_managers/__init__.py b/src/aws_encryption_sdk/materials_managers/__init__.py index 94fd30ece..75589cc83 100644 --- a/src/aws_encryption_sdk/materials_managers/__init__.py +++ b/src/aws_encryption_sdk/materials_managers/__init__.py @@ -18,9 +18,16 @@ import six from attr.validators import deep_iterable, deep_mapping, instance_of, optional -from ..identifiers import Algorithm, KeyringTraceFlag -from ..internal.utils.streams import ROStream -from ..structures import DataKey, EncryptedDataKey, KeyringTrace +from aws_encryption_sdk.exceptions import InvalidDataKeyError, InvalidKeyringTraceError, SignatureKeyError +from aws_encryption_sdk.identifiers import Algorithm, KeyringTraceFlag +from aws_encryption_sdk.internal.utils.streams import ROStream +from aws_encryption_sdk.structures import DataKey, EncryptedDataKey, KeyringTrace, RawDataKey + +try: # Python 3.5.0 and 3.5.1 have incompatible typing modules + 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 @attr.s(hash=False) @@ -41,15 +48,24 @@ class EncryptionMaterialsRequest(object): :param int plaintext_length: Length of source plaintext (optional) """ - encryption_context = attr.ib(validator=attr.validators.instance_of(dict)) - frame_length = attr.ib(validator=attr.validators.instance_of(six.integer_types)) - plaintext_rostream = attr.ib( - default=None, validator=attr.validators.optional(attr.validators.instance_of(ROStream)) - ) - algorithm = attr.ib(default=None, validator=attr.validators.optional(attr.validators.instance_of(Algorithm))) - plaintext_length = attr.ib( - default=None, validator=attr.validators.optional(attr.validators.instance_of(six.integer_types)) + encryption_context = attr.ib( + validator=deep_mapping( + key_validator=instance_of(six.string_types), value_validator=instance_of(six.string_types) + ) ) + frame_length = attr.ib(validator=instance_of(six.integer_types)) + plaintext_rostream = attr.ib(default=None, validator=optional(instance_of(ROStream))) + algorithm = attr.ib(default=None, validator=optional(instance_of(Algorithm))) + plaintext_length = attr.ib(default=None, validator=optional(instance_of(six.integer_types))) + + +def _data_key_to_raw_data_key(data_key): + # type: (Union[DataKey, RawDataKey, None]) -> Union[RawDataKey, None] + """Convert a :class:`DataKey` into a :class:`RawDataKey`.""" + if isinstance(data_key, RawDataKey) or data_key is None: + return data_key + + return RawDataKey.from_data_key(data_key=data_key) @attr.s @@ -73,13 +89,87 @@ class CryptographicMaterials(object): deep_mapping(key_validator=instance_of(six.string_types), value_validator=instance_of(six.string_types)) ) ) - data_encryption_key = attr.ib(default=None, validator=optional(instance_of(DataKey))) - encrypted_data_keys = attr.ib( - default=attr.Factory(list), validator=optional(deep_iterable(member_validator=instance_of(EncryptedDataKey))) + data_encryption_key = attr.ib( + default=None, validator=optional(instance_of(RawDataKey)), converter=_data_key_to_raw_data_key ) - keyring_trace = attr.ib( + _keyring_trace = attr.ib( default=attr.Factory(list), validator=optional(deep_iterable(member_validator=instance_of(KeyringTrace))) ) + _initialized = False + + def __attrs_post_init__(self): + """Freeze attributes after initialization.""" + self._initialized = True + + def __setattr__(self, key, value): + """Do not allow attributes to be changed once an instance is initialized.""" + if self._initialized: + raise AttributeError("can't set attribute") + + self._setattr(key, value) + + def _setattr(self, key, value): + """Special __setattr__ to avoid having to perform multi-level super calls.""" + super(CryptographicMaterials, self).__setattr__(key, value) + + def _validate_data_encryption_key(self, data_encryption_key, keyring_trace, required_flags): + # type: (Union[DataKey, RawDataKey], KeyringTrace, Iterable[KeyringTraceFlag]) -> None + """Validate that the provided data encryption key and keyring trace match for each other and the materials. + + :param RawDataKey data_encryption_key: Data encryption key + :param KeyringTrace keyring_trace: Keyring trace corresponding to data_encryption_key + :param required_flags: Iterable of required flags + :type required_flags: iterable of :class:`KeyringTraceFlag` + :raises AttributeError: if data encryption key is already set + :raises InvalidKeyringTraceError: if keyring trace does not match decrypt action + :raises InvalidKeyringTraceError: if keyring trace does not match data key provider + :raises InvalidDataKeyError: if data key length does not match algorithm suite + """ + if self.data_encryption_key is not None: + raise AttributeError("Data encryption key is already set.") + + for flag in required_flags: + if flag not in keyring_trace.flags: + raise InvalidKeyringTraceError("Keyring flags do not match action.") + + if keyring_trace.wrapping_key != data_encryption_key.key_provider: + raise InvalidKeyringTraceError("Keyring trace does not match data key provider.") + + if len(data_encryption_key.data_key) != self.algorithm.kdf_input_len: + raise InvalidDataKeyError( + "Invalid data key length {actual} must be {expected}.".format( + actual=len(data_encryption_key.data_key), expected=self.algorithm.kdf_input_len + ) + ) + + def _add_data_encryption_key(self, data_encryption_key, keyring_trace, required_flags): + # type: (Union[DataKey, RawDataKey], KeyringTrace, Iterable[KeyringTraceFlag]) -> None + """Add a plaintext data encryption key. + + :param RawDataKey data_encryption_key: Data encryption key + :param KeyringTrace keyring_trace: Trace of actions that a keyring performed + while getting this data encryption key + :raises AttributeError: if data encryption key is already set + :raises InvalidKeyringTraceError: if keyring trace does not match required actions + :raises InvalidKeyringTraceError: if keyring trace does not match data key provider + :raises InvalidDataKeyError: if data key length does not match algorithm suite + """ + self._validate_data_encryption_key( + data_encryption_key=data_encryption_key, keyring_trace=keyring_trace, required_flags=required_flags + ) + + data_key = _data_key_to_raw_data_key(data_key=data_encryption_key) + + super(CryptographicMaterials, self).__setattr__("data_encryption_key", data_key) + self._keyring_trace.append(keyring_trace) + + @property + def keyring_trace(self): + """Return a read-only version of the keyring trace. + + :rtype: tuple + """ + return tuple(self._keyring_trace) @attr.s(hash=False, init=False) @@ -106,7 +196,10 @@ class EncryptionMaterials(CryptographicMaterials): :type keyring_trace: list of :class:`KeyringTrace` """ - signing_key = attr.ib(default=None, validator=attr.validators.optional(attr.validators.instance_of(bytes))) + _encrypted_data_keys = attr.ib( + default=attr.Factory(list), validator=optional(deep_iterable(member_validator=instance_of(EncryptedDataKey))) + ) + signing_key = attr.ib(default=None, repr=False, validator=optional(instance_of(bytes))) def __init__( self, @@ -116,7 +209,7 @@ def __init__( encryption_context=None, signing_key=None, **kwargs - ): + ): # noqa we define this in the class docstring if algorithm is None: raise TypeError("algorithm must not be None") @@ -127,12 +220,79 @@ def __init__( algorithm=algorithm, encryption_context=encryption_context, data_encryption_key=data_encryption_key, - encrypted_data_keys=encrypted_data_keys, **kwargs ) - self.signing_key = signing_key + self._setattr("signing_key", signing_key) + self._setattr("_encrypted_data_keys", encrypted_data_keys) attr.validate(self) + @property + def encrypted_data_keys(self): + """Return a read-only version of the encrypted data keys. + + :rtype: frozenset + """ + return frozenset(self._encrypted_data_keys) + + def add_data_encryption_key(self, data_encryption_key, keyring_trace): + # type: (Union[DataKey, RawDataKey], KeyringTrace) -> None + """Add a plaintext data encryption key. + + .. versionadded:: 1.5.0 + + :param RawDataKey data_encryption_key: Data encryption key + :param KeyringTrace keyring_trace: Trace of actions that a keyring performed + while getting this data encryption key + :raises AttributeError: if data encryption key is already set + :raises InvalidKeyringTraceError: if keyring trace does not match generate action + :raises InvalidKeyringTraceError: if keyring trace does not match data key provider + :raises InvalidDataKeyError: if data key length does not match algorithm suite + """ + self._add_data_encryption_key( + data_encryption_key=data_encryption_key, + keyring_trace=keyring_trace, + required_flags={KeyringTraceFlag.WRAPPING_KEY_GENERATED_DATA_KEY}, + ) + + def add_encrypted_data_key(self, encrypted_data_key, keyring_trace): + # type: (EncryptedDataKey, KeyringTrace) -> None + """Add an encrypted data key with corresponding keyring trace. + + .. versionadded:: 1.5.0 + + :param EncryptedDataKey encrypted_data_key: Encrypted data key to add + :param KeyringTrace keyring_trace: Trace of actions that a keyring performed + while getting this encrypted data key + :raises InvalidKeyringTraceError: if keyring trace does not match generate action + :raises InvalidKeyringTraceError: if keyring trace does not match data key encryptor + """ + if KeyringTraceFlag.WRAPPING_KEY_ENCRYPTED_DATA_KEY not in keyring_trace.flags: + raise InvalidKeyringTraceError("Keyring flags do not match action.") + + if keyring_trace.wrapping_key != encrypted_data_key.key_provider: + raise InvalidKeyringTraceError("Keyring trace does not match data key encryptor.") + + self._encrypted_data_keys.add(encrypted_data_key) + self._keyring_trace.append(keyring_trace) + + def add_signing_key(self, signing_key): + # type: (bytes) -> None + """Add a signing key. + + .. versionadded:: 1.5.0 + + :param bytes signing_key: Signing key + :raises AttributeError: if signing key is already set + :raises SignatureKeyError: if algorithm suite does not support signing keys + """ + if self.signing_key is not None: + raise AttributeError("Signing key is already set.") + + if self.algorithm.signing_algorithm_info is None: + raise SignatureKeyError("Algorithm suite does not support signing keys.") + + self._setattr("signing_key", signing_key) + @attr.s(hash=False) class DecryptionMaterialsRequest(object): @@ -147,9 +307,14 @@ class DecryptionMaterialsRequest(object): :param dict encryption_context: Encryption context to provide to master keys for underlying decrypt requests """ - algorithm = attr.ib(validator=attr.validators.instance_of(Algorithm)) - encrypted_data_keys = attr.ib(validator=attr.validators.instance_of(set)) - encryption_context = attr.ib(validator=attr.validators.instance_of(dict)) + algorithm = attr.ib(validator=instance_of(Algorithm)) + # TODO: Restrict this to only EncryptedDataKeys + encrypted_data_keys = attr.ib(validator=deep_iterable(member_validator=instance_of((EncryptedDataKey, DataKey)))) + encryption_context = attr.ib( + validator=deep_mapping( + key_validator=instance_of(six.string_types), value_validator=instance_of(six.string_types) + ) + ) _DEFAULT_SENTINEL = object() @@ -163,8 +328,7 @@ class DecryptionMaterials(CryptographicMaterials): .. versionadded:: 1.5.0 - The **algorithm**, **data_encryption_key**, **encrypted_data_keys**, - **encryption_context**, and **keyring_trace** parameters. + The **algorithm**, **data_encryption_key**, **encryption_context**, and **keyring_trace** parameters. .. versionadded:: 1.5.0 @@ -172,26 +336,25 @@ class DecryptionMaterials(CryptographicMaterials): :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 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` (optional) :param bytes verification_key: Raw signature verification key (optional) :param keyring_trace: Any KeyRing trace entries (optional) :type keyring_trace: list of :class:`KeyringTrace` """ - verification_key = attr.ib(default=None, validator=attr.validators.optional(attr.validators.instance_of(bytes))) + verification_key = attr.ib(default=None, repr=False, validator=optional(instance_of(bytes))) - def __init__(self, data_key=_DEFAULT_SENTINEL, verification_key=None, **kwargs): - if any( - ( - data_key is _DEFAULT_SENTINEL and "data_encryption_key" not in kwargs, - data_key is not _DEFAULT_SENTINEL and "data_encryption_key" in kwargs, - ) - ): - raise TypeError("Exactly one of data_key or data_encryption_key must be set") + def __init__( + self, data_key=_DEFAULT_SENTINEL, verification_key=None, **kwargs + ): # noqa we define this in the class docstring - if data_key is not _DEFAULT_SENTINEL and "data_encryption_key" not in kwargs: + legacy_data_key_set = data_key is not _DEFAULT_SENTINEL + data_encryption_key_set = "data_encryption_key" in kwargs + + if legacy_data_key_set and data_encryption_key_set: + raise TypeError("Either data_key or data_encryption_key can be used but not both") + + if legacy_data_key_set and not data_encryption_key_set: kwargs["data_encryption_key"] = data_key for legacy_missing in ("algorithm", "encryption_context"): @@ -200,16 +363,46 @@ def __init__(self, data_key=_DEFAULT_SENTINEL, verification_key=None, **kwargs): super(DecryptionMaterials, self).__init__(**kwargs) - self.verification_key = verification_key + self._setattr("verification_key", verification_key) attr.validate(self) @property def data_key(self): - """Backwards-compatible shim.""" + """Backwards-compatible shim for access to data key.""" return self.data_encryption_key - @data_key.setter - def data_key(self, value): - # type: (DataKey) -> None - """Backwards-compatible shim.""" - self.data_encryption_key = value + def add_data_encryption_key(self, data_encryption_key, keyring_trace): + # type: (Union[DataKey, RawDataKey], KeyringTrace) -> None + """Add a plaintext data encryption key. + + .. versionadded:: 1.5.0 + + :param RawDataKey data_encryption_key: Data encryption key + :param KeyringTrace keyring_trace: Trace of actions that a keyring performed + while getting this data encryption key + :raises AttributeError: if data encryption key is already set + :raises InvalidKeyringTraceError: if keyring trace does not match decrypt action + :raises InvalidKeyringTraceError: if keyring trace does not match data key provider + :raises InvalidDataKeyError: if data key length does not match algorithm suite + """ + self._add_data_encryption_key( + data_encryption_key=data_encryption_key, + keyring_trace=keyring_trace, + required_flags={KeyringTraceFlag.WRAPPING_KEY_DECRYPTED_DATA_KEY}, + ) + + def add_verification_key(self, verification_key): + # type: (bytes) -> None + """Add a verification key. + + .. versionadded:: 1.5.0 + + :param bytes verification_key: Verification key + """ + if self.verification_key is not None: + raise AttributeError("Verification key is already set.") + + if self.algorithm.signing_algorithm_info is None: + raise SignatureKeyError("Algorithm suite does not support signing keys.") + + self._setattr("verification_key", verification_key) diff --git a/src/aws_encryption_sdk/structures.py b/src/aws_encryption_sdk/structures.py index aed2f9163..f433f8d95 100644 --- a/src/aws_encryption_sdk/structures.py +++ b/src/aws_encryption_sdk/structures.py @@ -11,49 +11,16 @@ # ANY KIND, either express or implied. See the License for the specific # language governing permissions and limitations under the License. """Public data structures for aws_encryption_sdk.""" +import copy + import attr import six -from attr.validators import deep_iterable, instance_of +from attr.validators import deep_iterable, deep_mapping, instance_of -import aws_encryption_sdk.identifiers +from aws_encryption_sdk.identifiers import Algorithm, ContentType, KeyringTraceFlag, ObjectType, SerializationVersion from aws_encryption_sdk.internal.str_ops import to_bytes, to_str -@attr.s(hash=True) -class MessageHeader(object): - """Deserialized message header object. - - :param version: Message format version, per spec - :type version: aws_encryption_sdk.identifiers.SerializationVersion - :param type: Message content type, per spec - :type type: aws_encryption_sdk.identifiers.ObjectType - :param algorithm: Algorithm to use for encryption - :type algorithm: aws_encryption_sdk.identifiers.Algorithm - :param bytes message_id: Message ID - :param dict encryption_context: Dictionary defining encryption context - :param encrypted_data_keys: Encrypted data keys - :type encrypted_data_keys: set of :class:`aws_encryption_sdk.structures.EncryptedDataKey` - :param content_type: Message content framing type (framed/non-framed) - :type content_type: aws_encryption_sdk.identifiers.ContentType - :param bytes content_aad_length: empty - :param int header_iv_length: Bytes in Initialization Vector value found in header - :param int frame_length: Length of message frame in bytes - """ - - version = attr.ib( - hash=True, validator=attr.validators.instance_of(aws_encryption_sdk.identifiers.SerializationVersion) - ) - type = attr.ib(hash=True, validator=attr.validators.instance_of(aws_encryption_sdk.identifiers.ObjectType)) - algorithm = attr.ib(hash=True, validator=attr.validators.instance_of(aws_encryption_sdk.identifiers.Algorithm)) - message_id = attr.ib(hash=True, validator=attr.validators.instance_of(bytes)) - encryption_context = attr.ib(hash=True, validator=attr.validators.instance_of(dict)) - encrypted_data_keys = attr.ib(hash=True, validator=attr.validators.instance_of(set)) - content_type = attr.ib(hash=True, validator=attr.validators.instance_of(aws_encryption_sdk.identifiers.ContentType)) - content_aad_length = attr.ib(hash=True, validator=attr.validators.instance_of(six.integer_types)) - header_iv_length = attr.ib(hash=True, validator=attr.validators.instance_of(six.integer_types)) - frame_length = attr.ib(hash=True, validator=attr.validators.instance_of(six.integer_types)) - - @attr.s(hash=True) class MasterKeyInfo(object): """Contains information necessary to identify a Master Key. @@ -62,8 +29,8 @@ class MasterKeyInfo(object): :param bytes key_info: MasterKey key_info value """ - provider_id = attr.ib(hash=True, validator=attr.validators.instance_of((six.string_types, bytes)), converter=to_str) - key_info = attr.ib(hash=True, validator=attr.validators.instance_of((six.string_types, bytes)), converter=to_bytes) + provider_id = attr.ib(hash=True, validator=instance_of((six.string_types, bytes)), converter=to_str) + key_info = attr.ib(hash=True, validator=instance_of((six.string_types, bytes)), converter=to_bytes) @attr.s(hash=True) @@ -75,8 +42,20 @@ class RawDataKey(object): :param bytes data_key: Plaintext data key """ - key_provider = attr.ib(hash=True, validator=attr.validators.instance_of(MasterKeyInfo)) - data_key = attr.ib(hash=True, repr=False, validator=attr.validators.instance_of(bytes)) + key_provider = attr.ib(hash=True, validator=instance_of(MasterKeyInfo)) + data_key = attr.ib(hash=True, repr=False, validator=instance_of(bytes)) + + @classmethod + def from_data_key(cls, data_key): + # type: (DataKey) -> RawDataKey + """Build an :class:`RawDataKey` from a :class:`DataKey`. + + .. versionadded:: 1.5.0 + """ + if not isinstance(data_key, DataKey): + raise TypeError("data_key must be type DataKey not {}".format(type(data_key).__name__)) + + return RawDataKey(key_provider=copy.copy(data_key.key_provider), data_key=copy.copy(data_key.data_key)) @attr.s(hash=True) @@ -89,9 +68,9 @@ class DataKey(object): :param bytes encrypted_data_key: Encrypted data key """ - key_provider = attr.ib(hash=True, validator=attr.validators.instance_of(MasterKeyInfo)) - data_key = attr.ib(hash=True, repr=False, validator=attr.validators.instance_of(bytes)) - encrypted_data_key = attr.ib(hash=True, validator=attr.validators.instance_of(bytes)) + key_provider = attr.ib(hash=True, validator=instance_of(MasterKeyInfo)) + data_key = attr.ib(hash=True, repr=False, validator=instance_of(bytes)) + encrypted_data_key = attr.ib(hash=True, validator=instance_of(bytes)) @attr.s(hash=True) @@ -103,20 +82,75 @@ class EncryptedDataKey(object): :param bytes encrypted_data_key: Encrypted data key """ - key_provider = attr.ib(hash=True, validator=attr.validators.instance_of(MasterKeyInfo)) - encrypted_data_key = attr.ib(hash=True, validator=attr.validators.instance_of(bytes)) + key_provider = attr.ib(hash=True, validator=instance_of(MasterKeyInfo)) + encrypted_data_key = attr.ib(hash=True, validator=instance_of(bytes)) + + @classmethod + def from_data_key(cls, data_key): + # type: (DataKey) -> EncryptedDataKey + """Build an :class:`EncryptedDataKey` from a :class:`DataKey`. + + .. versionadded:: 1.5.0 + """ + if not isinstance(data_key, DataKey): + raise TypeError("data_key must be type DataKey not {}".format(type(data_key).__name__)) + + return EncryptedDataKey( + key_provider=copy.copy(data_key.key_provider), encrypted_data_key=copy.copy(data_key.encrypted_data_key) + ) @attr.s class KeyringTrace(object): """Record of all actions that a KeyRing performed with a wrapping key. + .. versionadded:: 1.5.0 + :param MasterKeyInfo wrapping_key: Wrapping key used :param flags: Actions performed :type flags: set of :class:`KeyringTraceFlag` """ wrapping_key = attr.ib(validator=instance_of(MasterKeyInfo)) - flags = attr.ib( - validator=deep_iterable(member_validator=instance_of(aws_encryption_sdk.identifiers.KeyringTraceFlag)) + flags = attr.ib(validator=deep_iterable(member_validator=instance_of(KeyringTraceFlag))) + + +@attr.s(hash=True) +class MessageHeader(object): + """Deserialized message header object. + + :param version: Message format version, per spec + :type version: SerializationVersion + :param type: Message content type, per spec + :type type: ObjectType + :param algorithm: Algorithm to use for encryption + :type algorithm: Algorithm + :param bytes message_id: Message ID + :param dict encryption_context: Dictionary defining encryption context + :param encrypted_data_keys: Encrypted data keys + :type encrypted_data_keys: set of :class:`aws_encryption_sdk.structures.EncryptedDataKey` + :param content_type: Message content framing type (framed/non-framed) + :type content_type: ContentType + :param bytes content_aad_length: empty + :param int header_iv_length: Bytes in Initialization Vector value found in header + :param int frame_length: Length of message frame in bytes + """ + + version = attr.ib(hash=True, validator=instance_of(SerializationVersion)) + type = attr.ib(hash=True, validator=instance_of(ObjectType)) + algorithm = attr.ib(hash=True, validator=instance_of(Algorithm)) + message_id = attr.ib(hash=True, validator=instance_of(bytes)) + encryption_context = attr.ib( + hash=True, + validator=deep_mapping( + key_validator=instance_of(six.string_types), value_validator=instance_of(six.string_types) + ), + ) + # TODO: Restrict this to only EncryptedDataKeys + encrypted_data_keys = attr.ib( + hash=True, validator=deep_iterable(member_validator=instance_of((EncryptedDataKey, DataKey))) ) + content_type = attr.ib(hash=True, validator=instance_of(ContentType)) + content_aad_length = attr.ib(hash=True, validator=instance_of(six.integer_types)) + header_iv_length = attr.ib(hash=True, validator=instance_of(six.integer_types)) + frame_length = attr.ib(hash=True, validator=instance_of(six.integer_types)) diff --git a/test/unit/test_material_managers.py b/test/unit/test_material_managers.py index fa216c8d8..a1816fe10 100644 --- a/test/unit/test_material_managers.py +++ b/test/unit/test_material_managers.py @@ -12,10 +12,11 @@ # language governing permissions and limitations under the License. """Test suite for aws_encryption_sdk.materials_managers""" import pytest -from mock import MagicMock, sentinel +from mock import MagicMock from pytest_mock import mocker # noqa pylint: disable=unused-import -from aws_encryption_sdk.identifiers import KeyringTraceFlag +from aws_encryption_sdk.exceptions import InvalidDataKeyError, InvalidKeyringTraceError, SignatureKeyError +from aws_encryption_sdk.identifiers import AlgorithmSuite, KeyringTraceFlag from aws_encryption_sdk.internal.defaults import ALGORITHM from aws_encryption_sdk.internal.utils.streams import ROStream from aws_encryption_sdk.materials_managers import ( @@ -24,8 +25,9 @@ DecryptionMaterialsRequest, EncryptionMaterials, EncryptionMaterialsRequest, + _data_key_to_raw_data_key, ) -from aws_encryption_sdk.structures import DataKey, KeyringTrace, MasterKeyInfo +from aws_encryption_sdk.structures import DataKey, EncryptedDataKey, KeyringTrace, MasterKeyInfo, RawDataKey pytestmark = [pytest.mark.unit, pytest.mark.local] @@ -34,13 +36,14 @@ data_key=b"1234567890123456789012", encrypted_data_key=b"asdf", ) +_RAW_DATA_KEY = RawDataKey.from_data_key(_DATA_KEY) +_ENCRYPTED_DATA_KEY = EncryptedDataKey.from_data_key(_DATA_KEY) _VALID_KWARGS = { "CryptographicMaterials": dict( algorithm=ALGORITHM, encryption_context={"additional": "data"}, data_encryption_key=_DATA_KEY, - encrypted_data_keys=[], keyring_trace=[ KeyringTrace( wrapping_key=MasterKeyInfo(provider_id="Provider", key_info=b"Info"), @@ -70,6 +73,15 @@ _REMOVE = object() +def _copy_and_update_kwargs(class_name, mod_kwargs): + kwargs = _VALID_KWARGS[class_name].copy() + kwargs.update(mod_kwargs) + purge_keys = [key for key, val in kwargs.items() if val is _REMOVE] + for key in purge_keys: + del kwargs[key] + return kwargs + + @pytest.mark.parametrize( "attr_class, invalid_kwargs", ( @@ -90,19 +102,30 @@ (DecryptionMaterialsRequest, dict(encryption_context=None)), (DecryptionMaterials, dict(verification_key=5555)), (DecryptionMaterials, dict(data_key=_DATA_KEY, data_encryption_key=_DATA_KEY)), - (DecryptionMaterials, dict(data_key=_REMOVE, data_encryption_key=_REMOVE)), ), ) def test_attributes_fails(attr_class, invalid_kwargs): - kwargs = _VALID_KWARGS[attr_class.__name__].copy() - kwargs.update(invalid_kwargs) - purge_keys = [key for key, val in kwargs.items() if val is _REMOVE] - for key in purge_keys: - del kwargs[key] + kwargs = _copy_and_update_kwargs(attr_class.__name__, invalid_kwargs) with pytest.raises(TypeError): attr_class(**kwargs) +@pytest.mark.parametrize( + "attr_class, kwargs_modification", + ( + (CryptographicMaterials, {}), + (EncryptionMaterials, {}), + (DecryptionMaterials, {}), + (DecryptionMaterials, dict(data_key=_REMOVE, data_encryption_key=_REMOVE)), + (DecryptionMaterials, dict(data_key=_REMOVE, data_encryption_key=_RAW_DATA_KEY)), + (DecryptionMaterials, dict(data_key=_RAW_DATA_KEY, data_encryption_key=_REMOVE)), + ), +) +def test_attributes_good(attr_class, kwargs_modification): + kwargs = _copy_and_update_kwargs(attr_class.__name__, kwargs_modification) + attr_class(**kwargs) + + def test_encryption_materials_request_attributes_defaults(): test = EncryptionMaterialsRequest(encryption_context={}, frame_length=5) assert test.plaintext_rostream is None @@ -127,14 +150,239 @@ def test_decryption_materials_defaults(): def test_decryption_materials_legacy_data_key_get(): test = DecryptionMaterials(data_encryption_key=_DATA_KEY) - assert test.data_encryption_key is _DATA_KEY - assert test.data_key is _DATA_KEY + assert test.data_encryption_key == _RAW_DATA_KEY + assert test.data_key == _RAW_DATA_KEY -def test_decryption_materials_legacy_data_key_set(): - test = DecryptionMaterials(data_encryption_key=_DATA_KEY) +@pytest.mark.parametrize( + "data_key, expected", ((_DATA_KEY, _RAW_DATA_KEY), (_RAW_DATA_KEY, _RAW_DATA_KEY), (None, None)) +) +def test_data_key_to_raw_data_key_success(data_key, expected): + test = _data_key_to_raw_data_key(data_key=data_key) + + assert test == expected + + +def test_data_key_to_raw_data_key_fail(): + with pytest.raises(TypeError) as excinfo: + _data_key_to_raw_data_key(data_key="not a data key") + + excinfo.match("data_key must be type DataKey not str") + + +def _cryptographic_materials_attributes(): + for material in (CryptographicMaterials, EncryptionMaterials, DecryptionMaterials): + for attribute in ( + "algorithm", + "encryption_context", + "data_encryption_key", + "_keyring_trace", + "keyring_trace", + "_initialized", + ): + yield material, attribute + + for attribute in ("_encrypted_data_keys", "encrypted_data_keys", "signing_key"): + yield EncryptionMaterials, attribute + + for attribute in ("data_key", "verification_key"): + yield DecryptionMaterials, attribute + + +@pytest.mark.parametrize("material_class, attribute_name", _cryptographic_materials_attributes()) +def test_cryptographic_materials_cannot_change_attribute(material_class, attribute_name): + test = material_class(algorithm=ALGORITHM, encryption_context={}) + + with pytest.raises(AttributeError) as excinfo: + setattr(test, attribute_name, 42) + + excinfo.match("can't set attribute") + + +@pytest.mark.parametrize("material_class", (CryptographicMaterials, EncryptionMaterials, DecryptionMaterials)) +def test_immutable_keyring_trace(material_class): + materials = material_class(**_VALID_KWARGS[material_class.__name__]) + + with pytest.raises(AttributeError): + materials.keyring_trace.append(42) + + +def test_immutable_encrypted_data_keys(): + materials = EncryptionMaterials(**_VALID_KWARGS["EncryptionMaterials"]) + + with pytest.raises(AttributeError): + materials.encrypted_data_keys.add(42) + + +@pytest.mark.parametrize( + "material_class, flag", + ( + (EncryptionMaterials, KeyringTraceFlag.WRAPPING_KEY_GENERATED_DATA_KEY), + (DecryptionMaterials, KeyringTraceFlag.WRAPPING_KEY_DECRYPTED_DATA_KEY), + ), +) +def test_add_data_encryption_key_success(material_class, flag): + kwargs = _copy_and_update_kwargs(material_class.__name__, dict(data_encryption_key=_REMOVE, data_key=_REMOVE)) + materials = material_class(**kwargs) + + materials.add_data_encryption_key( + data_encryption_key=RawDataKey( + key_provider=MasterKeyInfo(provider_id="a", key_info=b"b"), data_key=b"1" * ALGORITHM.kdf_input_len + ), + keyring_trace=KeyringTrace(wrapping_key=MasterKeyInfo(provider_id="a", key_info=b"b"), flags={flag}), + ) + + +def _add_data_encryption_key_test_cases(): + for material_class, required_flags in ( + (EncryptionMaterials, KeyringTraceFlag.WRAPPING_KEY_GENERATED_DATA_KEY), + (DecryptionMaterials, KeyringTraceFlag.WRAPPING_KEY_DECRYPTED_DATA_KEY), + ): + yield ( + material_class, + dict(data_encryption_key=_RAW_DATA_KEY, data_key=_REMOVE), + _RAW_DATA_KEY, + KeyringTrace(wrapping_key=_RAW_DATA_KEY.key_provider, flags={required_flags}), + AttributeError, + "Data encryption key is already set.", + ) + yield ( + material_class, + dict(data_encryption_key=_REMOVE, data_key=_REMOVE), + _RAW_DATA_KEY, + KeyringTrace(wrapping_key=_RAW_DATA_KEY.key_provider, flags=set()), + InvalidKeyringTraceError, + "Keyring flags do not match action.", + ) + yield ( + material_class, + dict(data_encryption_key=_REMOVE, data_key=_REMOVE), + RawDataKey(key_provider=MasterKeyInfo(provider_id="a", key_info=b"b"), data_key=b"asdf"), + KeyringTrace(wrapping_key=MasterKeyInfo(provider_id="c", key_info=b"d"), flags={required_flags}), + InvalidKeyringTraceError, + "Keyring trace does not match data key provider.", + ) + yield ( + material_class, + dict(data_encryption_key=_REMOVE, data_key=_REMOVE), + RawDataKey(key_provider=_RAW_DATA_KEY.key_provider, data_key=b"1234"), + KeyringTrace(wrapping_key=_RAW_DATA_KEY.key_provider, flags={required_flags}), + InvalidDataKeyError, + r"Invalid data key length *", + ) + + +@pytest.mark.parametrize( + "material_class, mod_kwargs, data_encryption_key, keyring_trace, exception_type, exception_message", + _add_data_encryption_key_test_cases(), +) +def test_add_data_encryption_key_fail( + material_class, mod_kwargs, data_encryption_key, keyring_trace, exception_type, exception_message +): + kwargs = _copy_and_update_kwargs(material_class.__name__, mod_kwargs) + materials = material_class(**kwargs) + + with pytest.raises(exception_type) as excinfo: + materials.add_data_encryption_key(data_encryption_key=data_encryption_key, keyring_trace=keyring_trace) + + excinfo.match(exception_message) + + +def test_add_encrypted_data_key_success(): + kwargs = _copy_and_update_kwargs("EncryptionMaterials", {}) + materials = EncryptionMaterials(**kwargs) + + materials.add_encrypted_data_key( + _ENCRYPTED_DATA_KEY, + keyring_trace=KeyringTrace( + wrapping_key=_ENCRYPTED_DATA_KEY.key_provider, flags={KeyringTraceFlag.WRAPPING_KEY_ENCRYPTED_DATA_KEY} + ), + ) + + +@pytest.mark.parametrize( + "encrypted_data_key, keyring_trace, exception_type, exception_message", + ( + ( + _ENCRYPTED_DATA_KEY, + KeyringTrace(wrapping_key=_ENCRYPTED_DATA_KEY.key_provider, flags=set()), + InvalidKeyringTraceError, + "Keyring flags do not match action.", + ), + ( + EncryptedDataKey(key_provider=MasterKeyInfo(provider_id="a", key_info=b"b"), encrypted_data_key=b"asdf"), + KeyringTrace( + wrapping_key=MasterKeyInfo(provider_id="not a match", key_info=b"really not a match"), + flags={KeyringTraceFlag.WRAPPING_KEY_ENCRYPTED_DATA_KEY}, + ), + InvalidKeyringTraceError, + "Keyring trace does not match data key encryptor.", + ), + ), +) +def test_add_encrypted_data_key_fail(encrypted_data_key, keyring_trace, exception_type, exception_message): + kwargs = _copy_and_update_kwargs("EncryptionMaterials", {}) + materials = EncryptionMaterials(**kwargs) + + with pytest.raises(exception_type) as excinfo: + materials.add_encrypted_data_key(encrypted_data_key=encrypted_data_key, keyring_trace=keyring_trace) + + excinfo.match(exception_message) + + +def test_add_signing_key_success(): + kwargs = _copy_and_update_kwargs("EncryptionMaterials", dict(signing_key=_REMOVE)) + materials = EncryptionMaterials(**kwargs) + + materials.add_signing_key(signing_key=b"") + + +@pytest.mark.parametrize( + "mod_kwargs, signing_key, exception_type, exception_message", + ( + ({}, b"", AttributeError, "Signing key is already set."), + ( + dict(signing_key=_REMOVE, algorithm=AlgorithmSuite.AES_256_GCM_IV12_TAG16), + b"", + SignatureKeyError, + "Algorithm suite does not support signing keys.", + ), + ), +) +def test_add_signing_key_fail(mod_kwargs, signing_key, exception_type, exception_message): + kwargs = _copy_and_update_kwargs("EncryptionMaterials", mod_kwargs) + materials = EncryptionMaterials(**kwargs) + + with pytest.raises(exception_type) as excinfo: + materials.add_signing_key(signing_key=signing_key) + + excinfo.match(exception_message) + + +def test_add_verification_key_success(): + kwargs = _copy_and_update_kwargs("DecryptionMaterials", dict(verification_key=_REMOVE)) + materials = DecryptionMaterials(**kwargs) + + materials.add_verification_key(verification_key=b"") + + +@pytest.mark.parametrize( + "mod_kwargs, verification_key, exception_type, exception_message", + ( + ({}, b"", AttributeError, "Verification key is already set."), + ( + dict(verification_key=_REMOVE, algorithm=AlgorithmSuite.AES_256_GCM_IV12_TAG16), + b"", + SignatureKeyError, + "Algorithm suite does not support signing keys.", + ), + ), +) +def test_add_verification_key_fail(mod_kwargs, verification_key, exception_type, exception_message): + kwargs = _copy_and_update_kwargs("DecryptionMaterials", mod_kwargs) + materials = DecryptionMaterials(**kwargs) - test.data_key = sentinel.data_key + with pytest.raises(exception_type) as excinfo: + materials.add_verification_key(verification_key=verification_key) - assert test.data_encryption_key is sentinel.data_key - assert test.data_key is sentinel.data_key + excinfo.match(exception_message) diff --git a/test/unit/test_material_managers_default.py b/test/unit/test_material_managers_default.py index 6eeef525b..20aaa8dd6 100644 --- a/test/unit/test_material_managers_default.py +++ b/test/unit/test_material_managers_default.py @@ -22,10 +22,17 @@ from aws_encryption_sdk.key_providers.base import MasterKeyProvider from aws_encryption_sdk.materials_managers import EncryptionMaterials from aws_encryption_sdk.materials_managers.default import DefaultCryptoMaterialsManager -from aws_encryption_sdk.structures import DataKey, EncryptedDataKey +from aws_encryption_sdk.structures import DataKey, EncryptedDataKey, MasterKeyInfo, RawDataKey pytestmark = [pytest.mark.unit, pytest.mark.local] +_DATA_KEY = DataKey( + key_provider=MasterKeyInfo(provider_id="Provider", key_info=b"Info"), + data_key=b"1234567890123456789012", + encrypted_data_key=b"asdf", +) +_ENCRYPTED_DATA_KEY = EncryptedDataKey.from_data_key(_DATA_KEY) + @pytest.fixture def patch_for_dcmm_encrypt(mocker): @@ -33,8 +40,8 @@ def patch_for_dcmm_encrypt(mocker): mock_signing_key = b"ex_signing_key" DefaultCryptoMaterialsManager._generate_signing_key_and_update_encryption_context.return_value = mock_signing_key mocker.patch.object(aws_encryption_sdk.materials_managers.default, "prepare_data_keys") - mock_data_encryption_key = MagicMock(__class__=DataKey) - mock_encrypted_data_keys = set([MagicMock(__class__=EncryptedDataKey)]) + mock_data_encryption_key = _DATA_KEY + mock_encrypted_data_keys = set([_ENCRYPTED_DATA_KEY]) result_pair = mock_data_encryption_key, mock_encrypted_data_keys aws_encryption_sdk.materials_managers.default.prepare_data_keys.return_value = result_pair yield result_pair, mock_signing_key @@ -50,7 +57,7 @@ def patch_for_dcmm_decrypt(mocker): def build_cmm(): mock_mkp = MagicMock(__class__=MasterKeyProvider) - mock_mkp.decrypt_data_key_from_list.return_value = MagicMock(__class__=DataKey) + mock_mkp.decrypt_data_key_from_list.return_value = _DATA_KEY mock_mkp.master_keys_for_encryption.return_value = ( sentinel.primary_mk, set([sentinel.primary_mk, sentinel.mk_a, sentinel.mk_b]), @@ -127,7 +134,7 @@ def test_get_encryption_materials(patch_for_dcmm_encrypt): ) assert isinstance(test, EncryptionMaterials) assert test.algorithm is cmm.algorithm - assert test.data_encryption_key is patch_for_dcmm_encrypt[0][0] + assert test.data_encryption_key == RawDataKey.from_data_key(patch_for_dcmm_encrypt[0][0]) assert test.encrypted_data_keys == patch_for_dcmm_encrypt[0][1] assert test.encryption_context == encryption_context assert test.signing_key == patch_for_dcmm_encrypt[1] @@ -232,5 +239,5 @@ def test_decrypt_materials(mocker, patch_for_dcmm_decrypt): cmm._load_verification_key_from_encryption_context.assert_called_once_with( algorithm=mock_request.algorithm, encryption_context=mock_request.encryption_context ) - assert test.data_key is cmm.master_key_provider.decrypt_data_key_from_list.return_value + assert test.data_key == RawDataKey.from_data_key(cmm.master_key_provider.decrypt_data_key_from_list.return_value) assert test.verification_key == patch_for_dcmm_decrypt diff --git a/test/unit/test_streaming_client_stream_encryptor.py b/test/unit/test_streaming_client_stream_encryptor.py index 501214e9f..5cb2b8e37 100644 --- a/test/unit/test_streaming_client_stream_encryptor.py +++ b/test/unit/test_streaming_client_stream_encryptor.py @@ -247,7 +247,7 @@ def test_prep_message_framed_message( encryption_context=VALUES["encryption_context"], ) test_encryptor.content_type = ContentType.FRAMED_DATA - test_encryption_context = {aws_encryption_sdk.internal.defaults.ENCODED_SIGNER_KEY: sentinel.decoded_bytes} + test_encryption_context = {aws_encryption_sdk.internal.defaults.ENCODED_SIGNER_KEY: "DECODED_BYTES"} self.mock_encryption_materials.encryption_context = test_encryption_context self.mock_encryption_materials.encrypted_data_keys = self.mock_encrypted_data_keys diff --git a/test/unit/test_structures.py b/test/unit/test_structures.py index 1a9caa01d..efce6fadc 100644 --- a/test/unit/test_structures.py +++ b/test/unit/test_structures.py @@ -107,3 +107,30 @@ def test_data_key_repr_str(cls, params): assert data_key_check not in str(test) assert data_key_check not in repr(test) + + +@pytest.fixture +def ex_data_key(): + return DataKey(**VALID_KWARGS[DataKey][0]) + + +def test_encrypted_data_key_from_data_key_success(ex_data_key): + test = EncryptedDataKey.from_data_key(ex_data_key) + + assert test.key_provider == ex_data_key.key_provider + assert test.encrypted_data_key == ex_data_key.encrypted_data_key + + +def test_raw_data_key_from_data_key_success(ex_data_key): + test = RawDataKey.from_data_key(ex_data_key) + + assert test.key_provider == ex_data_key.key_provider + assert test.data_key == ex_data_key.data_key + + +@pytest.mark.parametrize("data_key_class", (EncryptedDataKey, RawDataKey)) +def test_raw_and_encrypted_data_key_from_data_key_fail(data_key_class): + with pytest.raises(TypeError) as excinfo: + data_key_class.from_data_key(b"ahjseofij") + + excinfo.match(r"data_key must be type DataKey not bytes") From 9b3d4e2f9074fc837bd69e30ad106ca70cbbf366 Mon Sep 17 00:00:00 2001 From: mattsb42-aws Date: Wed, 26 Jun 2019 20:15:11 -0700 Subject: [PATCH 042/119] encrypted_data_keys must only contain EncryptedDataKey --- src/aws_encryption_sdk/materials_managers/__init__.py | 3 +-- src/aws_encryption_sdk/structures.py | 5 +---- test/unit/test_caches.py | 8 +++----- 3 files changed, 5 insertions(+), 11 deletions(-) diff --git a/src/aws_encryption_sdk/materials_managers/__init__.py b/src/aws_encryption_sdk/materials_managers/__init__.py index 75589cc83..4ed77e315 100644 --- a/src/aws_encryption_sdk/materials_managers/__init__.py +++ b/src/aws_encryption_sdk/materials_managers/__init__.py @@ -308,8 +308,7 @@ class DecryptionMaterialsRequest(object): """ algorithm = attr.ib(validator=instance_of(Algorithm)) - # TODO: Restrict this to only EncryptedDataKeys - encrypted_data_keys = attr.ib(validator=deep_iterable(member_validator=instance_of((EncryptedDataKey, DataKey)))) + encrypted_data_keys = attr.ib(validator=deep_iterable(member_validator=instance_of(EncryptedDataKey))) encryption_context = attr.ib( validator=deep_mapping( key_validator=instance_of(six.string_types), value_validator=instance_of(six.string_types) diff --git a/src/aws_encryption_sdk/structures.py b/src/aws_encryption_sdk/structures.py index f433f8d95..635f661ce 100644 --- a/src/aws_encryption_sdk/structures.py +++ b/src/aws_encryption_sdk/structures.py @@ -146,10 +146,7 @@ class MessageHeader(object): key_validator=instance_of(six.string_types), value_validator=instance_of(six.string_types) ), ) - # TODO: Restrict this to only EncryptedDataKeys - encrypted_data_keys = attr.ib( - hash=True, validator=deep_iterable(member_validator=instance_of((EncryptedDataKey, DataKey))) - ) + encrypted_data_keys = attr.ib(hash=True, validator=deep_iterable(member_validator=instance_of(EncryptedDataKey))) content_type = attr.ib(hash=True, validator=instance_of(ContentType)) content_aad_length = attr.ib(hash=True, validator=instance_of(six.integer_types)) header_iv_length = attr.ib(hash=True, validator=instance_of(six.integer_types)) diff --git a/test/unit/test_caches.py b/test/unit/test_caches.py index 250ad6d5b..58c1b4944 100644 --- a/test/unit/test_caches.py +++ b/test/unit/test_caches.py @@ -27,7 +27,7 @@ ) from aws_encryption_sdk.identifiers import Algorithm from aws_encryption_sdk.materials_managers import DecryptionMaterialsRequest, EncryptionMaterialsRequest -from aws_encryption_sdk.structures import DataKey, MasterKeyInfo +from aws_encryption_sdk.structures import EncryptedDataKey, MasterKeyInfo pytestmark = [pytest.mark.unit, pytest.mark.local] @@ -47,19 +47,17 @@ }, "encrypted_data_keys": [ { - "key": DataKey( + "key": EncryptedDataKey( key_provider=MasterKeyInfo(provider_id="this is a provider ID", key_info=b"this is some key info"), - data_key=b"super secret key!", encrypted_data_key=b"super secret key, now with encryption!", ), "hash": b"TYoFeYuxns/FBlaw4dsRDOv25OCEKuZG9iXt5iEdJ8LU7n5glgkDAVxWUEYC4JKKykJdHkaVpxcDvNqS6UswiQ==", }, { - "key": DataKey( + "key": EncryptedDataKey( key_provider=MasterKeyInfo( provider_id="another provider ID!", key_info=b"this is some different key info" ), - data_key=b"better super secret key!", encrypted_data_key=b"better super secret key, now with encryption!", ), "hash": b"wSrDlPM2ocIj9MAtD94ULSR0Qrt1muBovBDRL+DsSTNphJEM3CZ/h3OyvYL8BR2EIXx0m7GYwv8dGtyZL2D87w==", From ac67a6faefe891256a59d28493a35a05cec8ebbd Mon Sep 17 00:00:00 2001 From: mattsb42-aws Date: Wed, 26 Jun 2019 20:28:02 -0700 Subject: [PATCH 043/119] fix test to be Python 2 compatible --- test/unit/test_structures.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unit/test_structures.py b/test/unit/test_structures.py index efce6fadc..e1070c574 100644 --- a/test/unit/test_structures.py +++ b/test/unit/test_structures.py @@ -133,4 +133,4 @@ def test_raw_and_encrypted_data_key_from_data_key_fail(data_key_class): with pytest.raises(TypeError) as excinfo: data_key_class.from_data_key(b"ahjseofij") - excinfo.match(r"data_key must be type DataKey not bytes") + excinfo.match(r"data_key must be type DataKey not *") From 0921eff1813133c85c7f1c0a9c65d9492c8a32d9 Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Thu, 27 Jun 2019 16:41:21 -0700 Subject: [PATCH 044/119] Changes in raw keyrings according to new keyring materials --- src/aws_encryption_sdk/keyring/raw_keyring.py | 240 ++++++++++-------- 1 file changed, 135 insertions(+), 105 deletions(-) diff --git a/src/aws_encryption_sdk/keyring/raw_keyring.py b/src/aws_encryption_sdk/keyring/raw_keyring.py index 74e19c653..71321e08d 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,108 @@ 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) - key_provider = MasterKeyInfo(provider_id=key_namespace, key_info=key_name) + # Check if data key is generated + if not plaintext_data_key: + return EncryptKeyError("Unable to generate data encryption key.") - 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, + # 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 + + +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 + 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 + + +@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,76 +137,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 - ) - - 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 - 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) ): - 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 + 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. @@ -137,56 +197,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 - ) - - 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: - 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 + 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) + return decryption_materials From 8399fea1f110d7ff405e14856ed4c958644b03f7 Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Thu, 27 Jun 2019 16:53:19 -0700 Subject: [PATCH 045/119] Updated with autoformat --- src/aws_encryption_sdk/keyring/raw_keyring.py | 41 +++++++++---------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/src/aws_encryption_sdk/keyring/raw_keyring.py b/src/aws_encryption_sdk/keyring/raw_keyring.py index 71321e08d..50b1661ca 100644 --- a/src/aws_encryption_sdk/keyring/raw_keyring.py +++ b/src/aws_encryption_sdk/keyring/raw_keyring.py @@ -13,18 +13,18 @@ """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): @@ -39,9 +39,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 +57,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 @@ -75,22 +73,19 @@ def on_decrypt_helper(decryption_materials, wrapping_key, wrapping_algorithm, ke # 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) @@ -123,7 +118,7 @@ def __attrs_post_init__(self): 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): @@ -137,8 +132,9 @@ 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 = on_encrypt_helper( + encryption_materials, self._key_provider, self._wrapping_key, self._wrapping_algorithm, self.key_name + ) return encryption_materials @@ -160,8 +156,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 @@ -197,8 +194,9 @@ 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 = on_encrypt_helper( + encryption_materials, self._key_provider, self._wrapping_key, self._wrapping_algorithm, self.key_name + ) return encryption_materials @@ -216,7 +214,8 @@ def on_decrypt(self, decryption_materials, encrypted_data_keys): # 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 38c756be632f9f948a9039b73fbb056510e5b73c Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Fri, 28 Jun 2019 09:44:27 -0700 Subject: [PATCH 046/119] Modified base --- src/aws_encryption_sdk/keyring/base.py | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/aws_encryption_sdk/keyring/base.py b/src/aws_encryption_sdk/keyring/base.py index 3c4689d70..3192a5688 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. @@ -22,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 """ From 5005cfb9e69ac812aad83350e0178491fd963960 Mon Sep 17 00:00:00 2001 From: mattsb42-aws Date: Fri, 28 Jun 2019 13:34:01 -0700 Subject: [PATCH 047/119] data encryption key must be set before encrypted data keys can be added to EncryptionMaterials --- .../materials_managers/__init__.py | 4 ++++ test/unit/test_material_managers.py | 17 ++++++++++++++--- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/aws_encryption_sdk/materials_managers/__init__.py b/src/aws_encryption_sdk/materials_managers/__init__.py index 4ed77e315..916516dfc 100644 --- a/src/aws_encryption_sdk/materials_managers/__init__.py +++ b/src/aws_encryption_sdk/materials_managers/__init__.py @@ -263,9 +263,13 @@ def add_encrypted_data_key(self, encrypted_data_key, keyring_trace): :param EncryptedDataKey encrypted_data_key: Encrypted data key to add :param KeyringTrace keyring_trace: Trace of actions that a keyring performed while getting this encrypted data key + :raises AttributeError: if data encryption key is not set :raises InvalidKeyringTraceError: if keyring trace does not match generate action :raises InvalidKeyringTraceError: if keyring trace does not match data key encryptor """ + if self.data_encryption_key is None: + raise AttributeError("Data encryption key is not set.") + if KeyringTraceFlag.WRAPPING_KEY_ENCRYPTED_DATA_KEY not in keyring_trace.flags: raise InvalidKeyringTraceError("Keyring flags do not match action.") diff --git a/test/unit/test_material_managers.py b/test/unit/test_material_managers.py index a1816fe10..6e2f9330e 100644 --- a/test/unit/test_material_managers.py +++ b/test/unit/test_material_managers.py @@ -301,15 +301,17 @@ def test_add_encrypted_data_key_success(): @pytest.mark.parametrize( - "encrypted_data_key, keyring_trace, exception_type, exception_message", + "mod_kwargs, encrypted_data_key, keyring_trace, exception_type, exception_message", ( ( + {}, _ENCRYPTED_DATA_KEY, KeyringTrace(wrapping_key=_ENCRYPTED_DATA_KEY.key_provider, flags=set()), InvalidKeyringTraceError, "Keyring flags do not match action.", ), ( + {}, EncryptedDataKey(key_provider=MasterKeyInfo(provider_id="a", key_info=b"b"), encrypted_data_key=b"asdf"), KeyringTrace( wrapping_key=MasterKeyInfo(provider_id="not a match", key_info=b"really not a match"), @@ -318,10 +320,19 @@ def test_add_encrypted_data_key_success(): InvalidKeyringTraceError, "Keyring trace does not match data key encryptor.", ), + ( + dict(data_encryption_key=_REMOVE), + _ENCRYPTED_DATA_KEY, + KeyringTrace( + wrapping_key=_ENCRYPTED_DATA_KEY.key_provider, flags={KeyringTraceFlag.WRAPPING_KEY_ENCRYPTED_DATA_KEY} + ), + AttributeError, + "Data encryption key is not set.", + ), ), ) -def test_add_encrypted_data_key_fail(encrypted_data_key, keyring_trace, exception_type, exception_message): - kwargs = _copy_and_update_kwargs("EncryptionMaterials", {}) +def test_add_encrypted_data_key_fail(mod_kwargs, encrypted_data_key, keyring_trace, exception_type, exception_message): + kwargs = _copy_and_update_kwargs("EncryptionMaterials", mod_kwargs) materials = EncryptionMaterials(**kwargs) with pytest.raises(exception_type) as excinfo: From 242a3a3b101996ff950fdf58b33e266cdc557056 Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Fri, 28 Jun 2019 16:22:38 -0700 Subject: [PATCH 048/119] Corrected tox and flake errors --- src/aws_encryption_sdk/keyring/raw_keyring.py | 57 ++++++++++++++----- 1 file changed, 42 insertions(+), 15 deletions(-) diff --git a/src/aws_encryption_sdk/keyring/raw_keyring.py b/src/aws_encryption_sdk/keyring/raw_keyring.py index 50b1661ca..25b805727 100644 --- a/src/aws_encryption_sdk/keyring/raw_keyring.py +++ b/src/aws_encryption_sdk/keyring/raw_keyring.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. """Resources required for Raw Keyrings.""" + import os import struct @@ -28,6 +29,21 @@ 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: @@ -67,6 +83,21 @@ 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 @@ -96,11 +127,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 """ @@ -124,11 +155,9 @@ def __attrs_post_init__(self): 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 """ @@ -141,11 +170,11 @@ 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, 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 """ @@ -186,11 +215,9 @@ 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 """ @@ -203,11 +230,11 @@ 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, 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 """ From 26725671d11f213d150a7041130d08b8d39cf304 Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Mon, 1 Jul 2019 09:25:38 -0700 Subject: [PATCH 049/119] Docstring error correction --- src/aws_encryption_sdk/keyring/raw_keyring.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/aws_encryption_sdk/keyring/raw_keyring.py b/src/aws_encryption_sdk/keyring/raw_keyring.py index 25b805727..ebe61f3a9 100644 --- a/src/aws_encryption_sdk/keyring/raw_keyring.py +++ b/src/aws_encryption_sdk/keyring/raw_keyring.py @@ -30,7 +30,6 @@ 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. @@ -84,7 +83,6 @@ 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. @@ -126,7 +124,6 @@ def on_decrypt_helper(decryption_materials, wrapping_key, wrapping_algorithm, ke @attr.s class RawAESKeyring(Keyring): """Public class for Raw AES 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. @@ -154,7 +151,6 @@ def __attrs_post_init__(self): def on_encrypt(self, encryption_materials): """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. :type encryption_materials: aws_encryption_sdk.materials_managers.EncryptionMaterials :returns: Optionally modified encryption materials. @@ -169,7 +165,6 @@ 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: 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. @@ -194,7 +189,6 @@ def on_decrypt(self, decryption_materials, encrypted_data_keys): class RawRSAKeyring(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 @@ -214,7 +208,6 @@ 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: Encryption materials for the keyring to modify. :type encryption_materials: aws_encryption_sdk.materials_managers.EncryptionMaterials :returns: Optionally modified encryption materials. @@ -229,7 +222,6 @@ 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: 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. From 2696183ed6d188a19e8669e3de4c2e3791048699 Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Mon, 1 Jul 2019 10:27:41 -0700 Subject: [PATCH 050/119] Added docstrings and corrected errors --- src/aws_encryption_sdk/keyring/raw_keyring.py | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/aws_encryption_sdk/keyring/raw_keyring.py b/src/aws_encryption_sdk/keyring/raw_keyring.py index ebe61f3a9..11b442777 100644 --- a/src/aws_encryption_sdk/keyring/raw_keyring.py +++ b/src/aws_encryption_sdk/keyring/raw_keyring.py @@ -30,6 +30,7 @@ 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. @@ -42,7 +43,6 @@ 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 """ - # Check if data key already exists if not encryption_materials.data_encryption_key: @@ -83,6 +83,7 @@ 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. @@ -95,7 +96,6 @@ 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 """ - # Check if plaintext data key exists if decryption_materials.data_key: return decryption_materials @@ -124,6 +124,7 @@ def on_decrypt_helper(decryption_materials, wrapping_key, wrapping_algorithm, ke @attr.s class RawAESKeyring(Keyring): """Public class for Raw AES 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. @@ -131,17 +132,16 @@ class RawAESKeyring(Keyring): :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): + """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 @@ -151,12 +151,12 @@ def __attrs_post_init__(self): def on_encrypt(self, encryption_materials): """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. :type encryption_materials: aws_encryption_sdk.materials_managers.EncryptionMaterials :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 ) @@ -165,6 +165,7 @@ 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: 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. @@ -172,7 +173,6 @@ def on_decrypt(self, decryption_materials, encrypted_data_keys): :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 ( @@ -189,6 +189,7 @@ def on_decrypt(self, decryption_materials, encrypted_data_keys): class RawRSAKeyring(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 @@ -198,7 +199,6 @@ class RawRSAKeyring(Keyring): :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, repr=False, validator=attr.validators.instance_of(WrappingKey)) @@ -208,12 +208,12 @@ 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: Encryption materials for the keyring to modify. :type encryption_materials: aws_encryption_sdk.materials_managers.EncryptionMaterials :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 ) @@ -222,6 +222,7 @@ 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: 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. @@ -229,7 +230,6 @@ def on_decrypt(self, decryption_materials, encrypted_data_keys): :returns: Optionally modified decryption materials. :rtype: aws_encryption_sdk.materials_managers.DecryptionMaterials """ - # Decrypt data key if encrypted_data_keys.key_provider == self._key_provider: From f1d1977e8987c2fcd7526c0d942815d622530a8e Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Mon, 1 Jul 2019 11:09:24 -0700 Subject: [PATCH 051/119] Some more changes in docstrings --- src/aws_encryption_sdk/keyring/raw_keyring.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/aws_encryption_sdk/keyring/raw_keyring.py b/src/aws_encryption_sdk/keyring/raw_keyring.py index 11b442777..a0d9de69a 100644 --- a/src/aws_encryption_sdk/keyring/raw_keyring.py +++ b/src/aws_encryption_sdk/keyring/raw_keyring.py @@ -132,6 +132,7 @@ class RawAESKeyring(Keyring): :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)) @@ -199,6 +200,7 @@ class RawRSAKeyring(Keyring): :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, repr=False, validator=attr.validators.instance_of(WrappingKey)) From f08239c4b2ed03b6621030b5492f0166e822cc66 Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Mon, 1 Jul 2019 11:55:51 -0700 Subject: [PATCH 052/119] Updating base API --- src/aws_encryption_sdk/keyring/base.py | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/src/aws_encryption_sdk/keyring/base.py b/src/aws_encryption_sdk/keyring/base.py index 3192a5688..770b53c0b 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,27 +28,26 @@ 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 """ From 881cf5e1e3cb270f7618e4d1a99ae8fa4553d42e Mon Sep 17 00:00:00 2001 From: mattsb42-aws Date: Mon, 1 Jul 2019 17:08:19 -0700 Subject: [PATCH 053/119] add signing/verification key checks to Encryption/DecryptionMaterials --- .../materials_managers/__init__.py | 5 +++++ test/unit/test_material_managers.py | 15 +++++++++++---- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/aws_encryption_sdk/materials_managers/__init__.py b/src/aws_encryption_sdk/materials_managers/__init__.py index 916516dfc..3dff7563a 100644 --- a/src/aws_encryption_sdk/materials_managers/__init__.py +++ b/src/aws_encryption_sdk/materials_managers/__init__.py @@ -20,6 +20,7 @@ from aws_encryption_sdk.exceptions import InvalidDataKeyError, InvalidKeyringTraceError, SignatureKeyError from aws_encryption_sdk.identifiers import Algorithm, KeyringTraceFlag +from aws_encryption_sdk.internal.crypto.authentication import Signer, Verifier from aws_encryption_sdk.internal.utils.streams import ROStream from aws_encryption_sdk.structures import DataKey, EncryptedDataKey, KeyringTrace, RawDataKey @@ -295,6 +296,8 @@ def add_signing_key(self, signing_key): if self.algorithm.signing_algorithm_info is None: raise SignatureKeyError("Algorithm suite does not support signing keys.") + Signer.from_key_bytes(algorithm=self.algorithm, key_bytes=signing_key) + self._setattr("signing_key", signing_key) @@ -408,4 +411,6 @@ def add_verification_key(self, verification_key): if self.algorithm.signing_algorithm_info is None: raise SignatureKeyError("Algorithm suite does not support signing keys.") + Verifier.from_key_bytes(algorithm=self.algorithm, key_bytes=verification_key) + self._setattr("verification_key", verification_key) diff --git a/test/unit/test_material_managers.py b/test/unit/test_material_managers.py index 6e2f9330e..e0cc55972 100644 --- a/test/unit/test_material_managers.py +++ b/test/unit/test_material_managers.py @@ -11,12 +11,16 @@ # ANY KIND, either express or implied. See the License for the specific # language governing permissions and limitations under the License. """Test suite for aws_encryption_sdk.materials_managers""" + import pytest +from cryptography.hazmat.backends import default_backend +from cryptography.hazmat.primitives.asymmetric import ec from mock import MagicMock from pytest_mock import mocker # noqa pylint: disable=unused-import from aws_encryption_sdk.exceptions import InvalidDataKeyError, InvalidKeyringTraceError, SignatureKeyError from aws_encryption_sdk.identifiers import AlgorithmSuite, KeyringTraceFlag +from aws_encryption_sdk.internal.crypto.authentication import Signer, Verifier from aws_encryption_sdk.internal.defaults import ALGORITHM from aws_encryption_sdk.internal.utils.streams import ROStream from aws_encryption_sdk.materials_managers import ( @@ -38,6 +42,9 @@ ) _RAW_DATA_KEY = RawDataKey.from_data_key(_DATA_KEY) _ENCRYPTED_DATA_KEY = EncryptedDataKey.from_data_key(_DATA_KEY) +_SIGNATURE_PRIVATE_KEY = ec.generate_private_key(ALGORITHM.signing_algorithm_info(), default_backend()) +_SIGNING_KEY = Signer(algorithm=ALGORITHM, key=_SIGNATURE_PRIVATE_KEY) +_VERIFICATION_KEY = Verifier(algorithm=ALGORITHM, key=_SIGNATURE_PRIVATE_KEY.public_key()) _VALID_KWARGS = { "CryptographicMaterials": dict( @@ -63,11 +70,11 @@ data_encryption_key=_DATA_KEY, encrypted_data_keys=set([]), encryption_context={}, - signing_key=b"", + signing_key=_SIGNING_KEY.key_bytes(), ), "DecryptionMaterialsRequest": dict(algorithm=ALGORITHM, encrypted_data_keys=set([]), encryption_context={}), "DecryptionMaterials": dict( - data_key=_DATA_KEY, verification_key=b"ex_verification_key", algorithm=ALGORITHM, encryption_context={} + data_key=_DATA_KEY, verification_key=_VERIFICATION_KEY.key_bytes(), algorithm=ALGORITHM, encryption_context={} ), } _REMOVE = object() @@ -345,7 +352,7 @@ def test_add_signing_key_success(): kwargs = _copy_and_update_kwargs("EncryptionMaterials", dict(signing_key=_REMOVE)) materials = EncryptionMaterials(**kwargs) - materials.add_signing_key(signing_key=b"") + materials.add_signing_key(signing_key=_SIGNING_KEY.key_bytes()) @pytest.mark.parametrize( @@ -374,7 +381,7 @@ def test_add_verification_key_success(): kwargs = _copy_and_update_kwargs("DecryptionMaterials", dict(verification_key=_REMOVE)) materials = DecryptionMaterials(**kwargs) - materials.add_verification_key(verification_key=b"") + materials.add_verification_key(verification_key=_VERIFICATION_KEY.key_bytes()) @pytest.mark.parametrize( From 5769efaf2ac58dbfbe1cbe6ea4fbb60438ad2f5c Mon Sep 17 00:00:00 2001 From: mattsb42-aws Date: Mon, 1 Jul 2019 19:03:50 -0700 Subject: [PATCH 054/119] DecryptionMaterials.algorithm must be set before DecryptionMaterials.add_data_encryption_key can be called --- src/aws_encryption_sdk/materials_managers/__init__.py | 3 +++ test/unit/test_material_managers.py | 8 ++++++++ 2 files changed, 11 insertions(+) diff --git a/src/aws_encryption_sdk/materials_managers/__init__.py b/src/aws_encryption_sdk/materials_managers/__init__.py index 3dff7563a..6d8669b22 100644 --- a/src/aws_encryption_sdk/materials_managers/__init__.py +++ b/src/aws_encryption_sdk/materials_managers/__init__.py @@ -391,6 +391,9 @@ def add_data_encryption_key(self, data_encryption_key, keyring_trace): :raises InvalidKeyringTraceError: if keyring trace does not match data key provider :raises InvalidDataKeyError: if data key length does not match algorithm suite """ + if self.algorithm is None: + raise AttributeError("Algorithm is not set") + self._add_data_encryption_key( data_encryption_key=data_encryption_key, keyring_trace=keyring_trace, diff --git a/test/unit/test_material_managers.py b/test/unit/test_material_managers.py index e0cc55972..dcfa984bf 100644 --- a/test/unit/test_material_managers.py +++ b/test/unit/test_material_managers.py @@ -277,6 +277,14 @@ def _add_data_encryption_key_test_cases(): InvalidDataKeyError, r"Invalid data key length *", ) + yield ( + DecryptionMaterials, + dict(data_encryption_key=_REMOVE, data_key=_REMOVE, algorithm=_REMOVE), + RawDataKey(key_provider=_RAW_DATA_KEY.key_provider, data_key=b"1234"), + KeyringTrace(wrapping_key=_RAW_DATA_KEY.key_provider, flags={required_flags}), + AttributeError, + "Algorithm is not set" + ) @pytest.mark.parametrize( From 00a767883dc8891a9e80e95f18ca447866fd10b8 Mon Sep 17 00:00:00 2001 From: mattsb42-aws Date: Tue, 2 Jul 2019 11:52:29 -0700 Subject: [PATCH 055/119] update materials docs and typehints --- .../materials_managers/__init__.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/aws_encryption_sdk/materials_managers/__init__.py b/src/aws_encryption_sdk/materials_managers/__init__.py index 6d8669b22..ac63c4978 100644 --- a/src/aws_encryption_sdk/materials_managers/__init__.py +++ b/src/aws_encryption_sdk/materials_managers/__init__.py @@ -25,7 +25,7 @@ from aws_encryption_sdk.structures import DataKey, EncryptedDataKey, KeyringTrace, 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 Any, FrozenSet, Iterable, Tuple, Union # noqa pylint: disable=unused-import except ImportError: # pragma: no cover # We only actually need these imports when running the mypy checks pass @@ -77,9 +77,7 @@ class CryptographicMaterials(object): :param Algorithm algorithm: Algorithm to use for encrypting message :param dict encryption_context: Encryption context tied to `encrypted_data_keys` - :param DataKey data_encryption_key: Plaintext data key to use for encrypting message - :param encrypted_data_keys: List of encrypted data keys - :type encrypted_data_keys: list of :class:`EncryptedDataKey` + :param RawDataKey data_encryption_key: Plaintext data key to use for encrypting message :param keyring_trace: Any KeyRing trace entries :type keyring_trace: list of :class:`KeyringTrace` """ @@ -103,6 +101,7 @@ def __attrs_post_init__(self): self._initialized = True def __setattr__(self, key, value): + # type: (str, Any) -> None """Do not allow attributes to be changed once an instance is initialized.""" if self._initialized: raise AttributeError("can't set attribute") @@ -110,6 +109,7 @@ def __setattr__(self, key, value): self._setattr(key, value) def _setattr(self, key, value): + # type: (str, Any) -> None """Special __setattr__ to avoid having to perform multi-level super calls.""" super(CryptographicMaterials, self).__setattr__(key, value) @@ -150,6 +150,8 @@ def _add_data_encryption_key(self, data_encryption_key, keyring_trace, required_ :param RawDataKey data_encryption_key: Data encryption key :param KeyringTrace keyring_trace: Trace of actions that a keyring performed while getting this data encryption key + :param required_flags: Iterable of required flags + :type required_flags: iterable of :class:`KeyringTraceFlag` :raises AttributeError: if data encryption key is already set :raises InvalidKeyringTraceError: if keyring trace does not match required actions :raises InvalidKeyringTraceError: if keyring trace does not match data key provider @@ -166,6 +168,7 @@ def _add_data_encryption_key(self, data_encryption_key, keyring_trace, required_ @property def keyring_trace(self): + # type: () -> Tuple[KeyringTrace] """Return a read-only version of the keyring trace. :rtype: tuple @@ -229,6 +232,7 @@ def __init__( @property def encrypted_data_keys(self): + # type: () -> FrozenSet[EncryptedDataKey] """Return a read-only version of the encrypted data keys. :rtype: frozenset @@ -296,6 +300,7 @@ def add_signing_key(self, signing_key): if self.algorithm.signing_algorithm_info is None: raise SignatureKeyError("Algorithm suite does not support signing keys.") + # Verify that the signing key matches the algorithm Signer.from_key_bytes(algorithm=self.algorithm, key_bytes=signing_key) self._setattr("signing_key", signing_key) @@ -374,6 +379,7 @@ def __init__( @property def data_key(self): + # type: () -> RawDataKey """Backwards-compatible shim for access to data key.""" return self.data_encryption_key @@ -414,6 +420,7 @@ def add_verification_key(self, verification_key): if self.algorithm.signing_algorithm_info is None: raise SignatureKeyError("Algorithm suite does not support signing keys.") + # Verify that the verification key matches the algorithm Verifier.from_key_bytes(algorithm=self.algorithm, key_bytes=verification_key) self._setattr("verification_key", verification_key) From 36edf5b6ed8a0d463d9c01507e5ccd3c33fc4863 Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Tue, 2 Jul 2019 15:22:54 -0700 Subject: [PATCH 056/119] Made all suggested changes --- 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 98cf7918ffae2cd767c411262c5cd3c4e7a43b23 Mon Sep 17 00:00:00 2001 From: mattsb42-aws Date: Tue, 2 Jul 2019 18:11:45 -0700 Subject: [PATCH 057/119] EncryptionMaterials must not be initialized with encrypted_data_keys but no data_encryption_key --- .../materials_managers/__init__.py | 3 +++ test/unit/test_material_managers.py | 19 +++++++++++-------- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/aws_encryption_sdk/materials_managers/__init__.py b/src/aws_encryption_sdk/materials_managers/__init__.py index ac63c4978..3045d6a50 100644 --- a/src/aws_encryption_sdk/materials_managers/__init__.py +++ b/src/aws_encryption_sdk/materials_managers/__init__.py @@ -220,6 +220,9 @@ def __init__( if encryption_context is None: raise TypeError("encryption_context must not be None") + if data_encryption_key is None and encrypted_data_keys is not None: + raise TypeError("encrypted_data_keys cannot be provided without data_encryption_key") + super(EncryptionMaterials, self).__init__( algorithm=algorithm, encryption_context=encryption_context, diff --git a/test/unit/test_material_managers.py b/test/unit/test_material_managers.py index dcfa984bf..e75cd7c44 100644 --- a/test/unit/test_material_managers.py +++ b/test/unit/test_material_managers.py @@ -104,6 +104,7 @@ def _copy_and_update_kwargs(class_name, mod_kwargs): (EncryptionMaterials, dict(algorithm=None)), (EncryptionMaterials, dict(encryption_context=None)), (EncryptionMaterials, dict(signing_key=u"not bytes or None")), + (EncryptionMaterials, dict(data_encryption_key=_REMOVE)), (DecryptionMaterialsRequest, dict(algorithm=None)), (DecryptionMaterialsRequest, dict(encrypted_data_keys=None)), (DecryptionMaterialsRequest, dict(encryption_context=None)), @@ -229,7 +230,9 @@ def test_immutable_encrypted_data_keys(): ), ) def test_add_data_encryption_key_success(material_class, flag): - kwargs = _copy_and_update_kwargs(material_class.__name__, dict(data_encryption_key=_REMOVE, data_key=_REMOVE)) + kwargs = _copy_and_update_kwargs( + material_class.__name__, dict(data_encryption_key=_REMOVE, data_key=_REMOVE, encrypted_data_keys=_REMOVE) + ) materials = material_class(**kwargs) materials.add_data_encryption_key( @@ -247,7 +250,7 @@ def _add_data_encryption_key_test_cases(): ): yield ( material_class, - dict(data_encryption_key=_RAW_DATA_KEY, data_key=_REMOVE), + dict(data_encryption_key=_RAW_DATA_KEY, data_key=_REMOVE, encrypted_data_keys=_REMOVE), _RAW_DATA_KEY, KeyringTrace(wrapping_key=_RAW_DATA_KEY.key_provider, flags={required_flags}), AttributeError, @@ -255,7 +258,7 @@ def _add_data_encryption_key_test_cases(): ) yield ( material_class, - dict(data_encryption_key=_REMOVE, data_key=_REMOVE), + dict(data_encryption_key=_REMOVE, data_key=_REMOVE, encrypted_data_keys=_REMOVE), _RAW_DATA_KEY, KeyringTrace(wrapping_key=_RAW_DATA_KEY.key_provider, flags=set()), InvalidKeyringTraceError, @@ -263,7 +266,7 @@ def _add_data_encryption_key_test_cases(): ) yield ( material_class, - dict(data_encryption_key=_REMOVE, data_key=_REMOVE), + dict(data_encryption_key=_REMOVE, data_key=_REMOVE, encrypted_data_keys=_REMOVE), RawDataKey(key_provider=MasterKeyInfo(provider_id="a", key_info=b"b"), data_key=b"asdf"), KeyringTrace(wrapping_key=MasterKeyInfo(provider_id="c", key_info=b"d"), flags={required_flags}), InvalidKeyringTraceError, @@ -271,7 +274,7 @@ def _add_data_encryption_key_test_cases(): ) yield ( material_class, - dict(data_encryption_key=_REMOVE, data_key=_REMOVE), + dict(data_encryption_key=_REMOVE, data_key=_REMOVE, encrypted_data_keys=_REMOVE), RawDataKey(key_provider=_RAW_DATA_KEY.key_provider, data_key=b"1234"), KeyringTrace(wrapping_key=_RAW_DATA_KEY.key_provider, flags={required_flags}), InvalidDataKeyError, @@ -279,11 +282,11 @@ def _add_data_encryption_key_test_cases(): ) yield ( DecryptionMaterials, - dict(data_encryption_key=_REMOVE, data_key=_REMOVE, algorithm=_REMOVE), + dict(data_encryption_key=_REMOVE, data_key=_REMOVE, encrypted_data_keys=_REMOVE, algorithm=_REMOVE), RawDataKey(key_provider=_RAW_DATA_KEY.key_provider, data_key=b"1234"), KeyringTrace(wrapping_key=_RAW_DATA_KEY.key_provider, flags={required_flags}), AttributeError, - "Algorithm is not set" + "Algorithm is not set", ) @@ -336,7 +339,7 @@ def test_add_encrypted_data_key_success(): "Keyring trace does not match data key encryptor.", ), ( - dict(data_encryption_key=_REMOVE), + dict(data_encryption_key=_REMOVE, encrypted_data_keys=_REMOVE), _ENCRYPTED_DATA_KEY, KeyringTrace( wrapping_key=_ENCRYPTED_DATA_KEY.key_provider, flags={KeyringTraceFlag.WRAPPING_KEY_ENCRYPTED_DATA_KEY} From e03f38bbb7a7412f232c9daf314d58da6324cdc3 Mon Sep 17 00:00:00 2001 From: mattsb42-aws Date: Tue, 2 Jul 2019 18:44:00 -0700 Subject: [PATCH 058/119] add is_complete properties to EncryptionMaterials and DecryptionMaterials --- .../materials_managers/__init__.py | 39 ++++++++++++ test/unit/test_material_managers.py | 62 +++++++++++++++++++ 2 files changed, 101 insertions(+) diff --git a/src/aws_encryption_sdk/materials_managers/__init__.py b/src/aws_encryption_sdk/materials_managers/__init__.py index 3045d6a50..a6609199a 100644 --- a/src/aws_encryption_sdk/materials_managers/__init__.py +++ b/src/aws_encryption_sdk/materials_managers/__init__.py @@ -223,6 +223,9 @@ def __init__( if data_encryption_key is None and encrypted_data_keys is not None: raise TypeError("encrypted_data_keys cannot be provided without data_encryption_key") + if encrypted_data_keys is None: + encrypted_data_keys = [] + super(EncryptionMaterials, self).__init__( algorithm=algorithm, encryption_context=encryption_context, @@ -242,6 +245,24 @@ def encrypted_data_keys(self): """ return frozenset(self._encrypted_data_keys) + @property + def is_complete(self): + # type: () -> bool + """Determine whether these materials are sufficiently complete for use as decryption materials. + + :rtype: bool + """ + if self.data_encryption_key is None: + return False + + if not self.encrypted_data_keys: + return False + + if self.algorithm.signing_algorithm_info is not None and self.signing_key is None: + return False + + return True + def add_data_encryption_key(self, data_encryption_key, keyring_trace): # type: (Union[DataKey, RawDataKey], KeyringTrace) -> None """Add a plaintext data encryption key. @@ -380,6 +401,24 @@ def __init__( self._setattr("verification_key", verification_key) attr.validate(self) + @property + def is_complete(self): + # type: () -> bool + """Determine whether these materials are sufficiently complete for use as decryption materials. + + :rtype: bool + """ + if None in (self.algorithm, self.encryption_context): + return False + + if self.data_encryption_key is None: + return False + + if self.algorithm.signing_algorithm_info is not None and self.verification_key is None: + return False + + return True + @property def data_key(self): # type: () -> RawDataKey diff --git a/test/unit/test_material_managers.py b/test/unit/test_material_managers.py index e75cd7c44..2f64f3c74 100644 --- a/test/unit/test_material_managers.py +++ b/test/unit/test_material_managers.py @@ -215,6 +215,16 @@ def test_immutable_keyring_trace(material_class): materials.keyring_trace.append(42) +@pytest.mark.parametrize("material_class", (CryptographicMaterials, EncryptionMaterials, DecryptionMaterials)) +def test_empty_keyring_trace(material_class): + materials = material_class(**_copy_and_update_kwargs(material_class.__name__, dict(keyring_trace=_REMOVE))) + + trace = materials.keyring_trace + + assert isinstance(trace, tuple) + assert not trace + + def test_immutable_encrypted_data_keys(): materials = EncryptionMaterials(**_VALID_KWARGS["EncryptionMaterials"]) @@ -222,6 +232,15 @@ def test_immutable_encrypted_data_keys(): materials.encrypted_data_keys.add(42) +def test_empty_encrypted_data_keys(): + materials = EncryptionMaterials(**_copy_and_update_kwargs("EncryptionMaterials", dict(encrypted_data_keys=_REMOVE))) + + edks = materials.encrypted_data_keys + + assert isinstance(edks, frozenset) + assert not edks + + @pytest.mark.parametrize( "material_class, flag", ( @@ -415,3 +434,46 @@ def test_add_verification_key_fail(mod_kwargs, verification_key, exception_type, materials.add_verification_key(verification_key=verification_key) excinfo.match(exception_message) + + +def test_decryption_materials_is_complete(): + materials = DecryptionMaterials(**_copy_and_update_kwargs("DecryptionMaterials", {})) + + assert materials.is_complete + + +@pytest.mark.parametrize( + "mod_kwargs", + ( + dict(algorithm=_REMOVE), + dict(encryption_context=_REMOVE), + dict(data_encryption_key=_REMOVE, data_key=_REMOVE), + dict(verification_key=_REMOVE), + ), +) +def test_decryption_materials_is_not_complete(mod_kwargs): + kwargs = _copy_and_update_kwargs("DecryptionMaterials", mod_kwargs) + materials = DecryptionMaterials(**kwargs) + + assert not materials.is_complete + + +def test_encryption_materials_is_complete(): + materials = EncryptionMaterials(**_copy_and_update_kwargs("EncryptionMaterials", {})) + + assert materials.is_complete + + +@pytest.mark.parametrize( + "mod_kwargs", + ( + dict(data_encryption_key=_REMOVE, encrypted_data_keys=_REMOVE), + dict(encrypted_data_keys=_REMOVE), + dict(signing_key=_REMOVE), + ), +) +def test_encryption_materials_is_not_complete(mod_kwargs): + kwargs = _copy_and_update_kwargs("EncryptionMaterials", mod_kwargs) + materials = EncryptionMaterials(**kwargs) + + assert not materials.is_complete From f99ac6c19b0312d26e5a25e1ed3c603f489922a5 Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Wed, 3 Jul 2019 09:24:19 -0700 Subject: [PATCH 059/119] Corrected tox and flake8 errors --- 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 b928fd29444bc0f480a82a0d1f32c0e6121f2137 Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Mon, 8 Jul 2019 11:36:36 -0700 Subject: [PATCH 060/119] Minor change in raw-keyrings --- src/aws_encryption_sdk/keyring/raw_keyring.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/aws_encryption_sdk/keyring/raw_keyring.py b/src/aws_encryption_sdk/keyring/raw_keyring.py index 0831dc757..55762e684 100644 --- a/src/aws_encryption_sdk/keyring/raw_keyring.py +++ b/src/aws_encryption_sdk/keyring/raw_keyring.py @@ -254,6 +254,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 e92db767afb7d92277732a227cfa64701eacb261 Mon Sep 17 00:00:00 2001 From: mattsb42-aws Date: Tue, 9 Jul 2019 13:52:47 -0700 Subject: [PATCH 061/119] change KeyringTraceFlag values to bitshifted ints to match other implementations --- src/aws_encryption_sdk/identifiers.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/aws_encryption_sdk/identifiers.py b/src/aws_encryption_sdk/identifiers.py index 0bec8aacd..7f5cd3f1f 100644 --- a/src/aws_encryption_sdk/identifiers.py +++ b/src/aws_encryption_sdk/identifiers.py @@ -334,7 +334,7 @@ class KeyringTraceFlag(Enum): """KeyRing Trace actions.""" WRAPPING_KEY_GENERATED_DATA_KEY = 1 - WRAPPING_KEY_ENCRYPTED_DATA_KEY = 2 - WRAPPING_KEY_DECRYPTED_DATA_KEY = 3 - WRAPPING_KEY_SIGNED_ENC_CTX = 4 - WRAPPING_KEY_VERIFIED_ENC_CTX = 5 + WRAPPING_KEY_ENCRYPTED_DATA_KEY = 1 << 1 + WRAPPING_KEY_DECRYPTED_DATA_KEY = 1 << 2 + WRAPPING_KEY_SIGNED_ENC_CTX = 1 << 3 + WRAPPING_KEY_VERIFIED_ENC_CTX = 1 << 4 From bcd4cfec8928629c89f398351d187d962a41b0bc Mon Sep 17 00:00:00 2001 From: mattsb42-aws Date: Tue, 9 Jul 2019 14:21:12 -0700 Subject: [PATCH 062/119] normalize EncryptionMaterials._encrypted_data_keys to list and encrypted_data_keys to tuple --- src/aws_encryption_sdk/materials_managers/__init__.py | 4 ++-- test/unit/test_material_managers.py | 10 +++++----- test/unit/test_material_managers_default.py | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/aws_encryption_sdk/materials_managers/__init__.py b/src/aws_encryption_sdk/materials_managers/__init__.py index a6609199a..a1947b100 100644 --- a/src/aws_encryption_sdk/materials_managers/__init__.py +++ b/src/aws_encryption_sdk/materials_managers/__init__.py @@ -243,7 +243,7 @@ def encrypted_data_keys(self): :rtype: frozenset """ - return frozenset(self._encrypted_data_keys) + return tuple(self._encrypted_data_keys) @property def is_complete(self): @@ -305,7 +305,7 @@ def add_encrypted_data_key(self, encrypted_data_key, keyring_trace): if keyring_trace.wrapping_key != encrypted_data_key.key_provider: raise InvalidKeyringTraceError("Keyring trace does not match data key encryptor.") - self._encrypted_data_keys.add(encrypted_data_key) + self._encrypted_data_keys.append(encrypted_data_key) self._keyring_trace.append(keyring_trace) def add_signing_key(self, signing_key): diff --git a/test/unit/test_material_managers.py b/test/unit/test_material_managers.py index 2f64f3c74..975e9ffda 100644 --- a/test/unit/test_material_managers.py +++ b/test/unit/test_material_managers.py @@ -68,11 +68,11 @@ "EncryptionMaterials": dict( algorithm=ALGORITHM, data_encryption_key=_DATA_KEY, - encrypted_data_keys=set([]), + encrypted_data_keys=[], encryption_context={}, signing_key=_SIGNING_KEY.key_bytes(), ), - "DecryptionMaterialsRequest": dict(algorithm=ALGORITHM, encrypted_data_keys=set([]), encryption_context={}), + "DecryptionMaterialsRequest": dict(algorithm=ALGORITHM, encrypted_data_keys=[], encryption_context={}), "DecryptionMaterials": dict( data_key=_DATA_KEY, verification_key=_VERIFICATION_KEY.key_bytes(), algorithm=ALGORITHM, encryption_context={} ), @@ -143,7 +143,7 @@ def test_encryption_materials_request_attributes_defaults(): def test_encryption_materials_defaults(): test = EncryptionMaterials( - algorithm=ALGORITHM, data_encryption_key=_DATA_KEY, encrypted_data_keys=set([]), encryption_context={} + algorithm=ALGORITHM, data_encryption_key=_DATA_KEY, encrypted_data_keys=[], encryption_context={} ) assert test.signing_key is None @@ -229,7 +229,7 @@ def test_immutable_encrypted_data_keys(): materials = EncryptionMaterials(**_VALID_KWARGS["EncryptionMaterials"]) with pytest.raises(AttributeError): - materials.encrypted_data_keys.add(42) + materials.encrypted_data_keys.append(42) def test_empty_encrypted_data_keys(): @@ -237,7 +237,7 @@ def test_empty_encrypted_data_keys(): edks = materials.encrypted_data_keys - assert isinstance(edks, frozenset) + assert isinstance(edks, tuple) assert not edks diff --git a/test/unit/test_material_managers_default.py b/test/unit/test_material_managers_default.py index 20aaa8dd6..32fdc953a 100644 --- a/test/unit/test_material_managers_default.py +++ b/test/unit/test_material_managers_default.py @@ -41,7 +41,7 @@ def patch_for_dcmm_encrypt(mocker): DefaultCryptoMaterialsManager._generate_signing_key_and_update_encryption_context.return_value = mock_signing_key mocker.patch.object(aws_encryption_sdk.materials_managers.default, "prepare_data_keys") mock_data_encryption_key = _DATA_KEY - mock_encrypted_data_keys = set([_ENCRYPTED_DATA_KEY]) + mock_encrypted_data_keys = (_ENCRYPTED_DATA_KEY,) result_pair = mock_data_encryption_key, mock_encrypted_data_keys aws_encryption_sdk.materials_managers.default.prepare_data_keys.return_value = result_pair yield result_pair, mock_signing_key @@ -165,7 +165,7 @@ def test_get_encryption_materials_primary_mk_not_in_mks(patch_for_dcmm_encrypt): cmm = build_cmm() cmm.master_key_provider.master_keys_for_encryption.return_value = ( sentinel.primary_mk, - set([sentinel.mk_a, sentinel.mk_b]), + {sentinel.mk_a, sentinel.mk_b}, ) with pytest.raises(MasterKeyProviderError) as excinfo: From be3a39197fcb4b4b0622312b24388d1659fa0043 Mon Sep 17 00:00:00 2001 From: mattsb42-aws Date: Tue, 9 Jul 2019 14:21:38 -0700 Subject: [PATCH 063/119] temporarily pin pydocstyle at <4.0.0 to avoid issue breaking flake8-docstrings --- tox.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/tox.ini b/tox.ini index e13ea2cb8..3e5677ece 100644 --- a/tox.ini +++ b/tox.ini @@ -117,6 +117,7 @@ basepython = python3 deps = flake8 flake8-docstrings + pydocstyle < 4.0.0 # https://github.com/JBKahn/flake8-print/pull/30 flake8-print>=3.1.0 flake8-bugbear From 402af2c5fa7cccafec4fcb6fdb87c22148ad36b8 Mon Sep 17 00:00:00 2001 From: mattsb42-aws Date: Wed, 10 Jul 2019 12:22:51 -0700 Subject: [PATCH 064/119] temporarily cap pydocstyle at <4.0.0 for decrypt oracle --- decrypt_oracle/tox.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/decrypt_oracle/tox.ini b/decrypt_oracle/tox.ini index 60aea91c7..23a9ece86 100644 --- a/decrypt_oracle/tox.ini +++ b/decrypt_oracle/tox.ini @@ -156,6 +156,7 @@ basepython = python3 deps = flake8 flake8-docstrings + pydocstyle < 4.0.0 # https://github.com/JBKahn/flake8-print/pull/30 flake8-print>=3.1.0 commands = From be4f74cb5e636122eb21f21b9300e38e5d5a1d7a Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Fri, 12 Jul 2019 15:08:51 -0700 Subject: [PATCH 065/119] Changes to keyring trace in raw keyrings --- src/aws_encryption_sdk/keyring/raw_keyring.py | 27 +++++++++++++------ 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/src/aws_encryption_sdk/keyring/raw_keyring.py b/src/aws_encryption_sdk/keyring/raw_keyring.py index 55762e684..13132a0b3 100644 --- a/src/aws_encryption_sdk/keyring/raw_keyring.py +++ b/src/aws_encryption_sdk/keyring/raw_keyring.py @@ -19,14 +19,13 @@ 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.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 +from aws_encryption_sdk.structures import 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 @@ -74,12 +73,13 @@ 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: + # Create a keyring trace + keyring_trace = KeyringTrace(wrapping_key=key_provider, flags=set()) + # Generate data key plaintext_data_key = os.urandom(encryption_materials.algorithm.kdf_input_len) @@ -87,6 +87,9 @@ def on_encrypt_helper( if not plaintext_data_key: return EncryptKeyError("Unable to generate data encryption key.") + # Update Keyring Trace + keyring_trace.flags.add(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 +98,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,8 +113,13 @@ def on_encrypt_helper( encrypted_wrapped_key=encrypted_wrapped_key, ) + # Update Keyring Trace + if encrypted_data_key: + 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, keyring_trace) + encryption_materials.add_encrypted_data_key(encrypted_data_key=encrypted_data_key, + keyring_trace=keyring_trace) return encryption_materials @@ -140,13 +149,14 @@ 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: return decryption_materials + # Create a keyring trace + keyring_trace = KeyringTrace(wrapping_key=key_provider, flags=set()) + # 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 @@ -157,6 +167,7 @@ def on_decrypt_helper( plaintext_data_key = wrapping_key.decrypt( encrypted_wrapped_data_key=encrypted_wrapped_key, encryption_context=decryption_materials.encryption_context ) + keyring_trace.flags.add(KeyringTraceFlag.WRAPPING_KEY_DECRYPTED_DATA_KEY) except Exception as error: logging.ERROR(error.__class__.__name__, ":", str(error)) return decryption_materials From c01fb904489c703f61f67442e3b9dfd43cf05c29 Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Fri, 12 Jul 2019 15:46:11 -0700 Subject: [PATCH 066/119] Adding test files --- test/functional/test_f_raw_aes.py | 0 test/functional/test_f_raw_rsa.py | 0 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 test/functional/test_f_raw_aes.py create mode 100644 test/functional/test_f_raw_rsa.py diff --git a/test/functional/test_f_raw_aes.py b/test/functional/test_f_raw_aes.py new file mode 100644 index 000000000..e69de29bb diff --git a/test/functional/test_f_raw_rsa.py b/test/functional/test_f_raw_rsa.py new file mode 100644 index 000000000..e69de29bb From 85a014934ae3ac979c3ef2c0eb18e9d04b273da4 Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Fri, 12 Jul 2019 15:48:38 -0700 Subject: [PATCH 067/119] Adding tests --- test/functional/test_f_raw_aes.py | 98 +++++++++++++++++++++++++++++++ test/functional/test_f_raw_rsa.py | 97 ++++++++++++++++++++++++++++++ 2 files changed, 195 insertions(+) diff --git a/test/functional/test_f_raw_aes.py b/test/functional/test_f_raw_aes.py index e69de29bb..a4d79eab6 100644 --- a/test/functional/test_f_raw_aes.py +++ b/test/functional/test_f_raw_aes.py @@ -0,0 +1,98 @@ +# 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 Algorithm, EncryptionKeyType, WrappingAlgorithm +from aws_encryption_sdk.keyring.raw_keyring import RawAESKeyring, WrappingKey +from aws_encryption_sdk.materials_managers import DecryptionMaterials, EncryptionMaterials +from aws_encryption_sdk.structures import DataKey, EncryptedDataKey, MasterKeyInfo + +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 = 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 = [ + 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=DataKey( + # 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, + # ), + # EncryptionMaterials( + # algorithm=Algorithm.AES_256_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384, + # data_encryption_key=DataKey( + # 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, + # ), +] + + +@pytest.mark.parametrize("encryption_materials", _ENCRYPTION_MATERIALS) +def test_raw_aes_encryption_decryption(encryption_materials): + + # Initializing attributes + 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, + wrapping_key_type=EncryptionKeyType.SYMMETRIC, + ) + _wrapping_algorithm = WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING + + # Creating an instance of a raw AES keyring + fake_raw_aes_keyring = RawAESKeyring( + key_namespace=key_namespace, + key_name=key_name, + wrapping_key=_wrapping_key, + wrapping_algorithm=_wrapping_algorithm, + ) + + # Call on_encrypt function for the keyring + encryption_materials = fake_raw_aes_keyring.on_encrypt(encryption_materials=encryption_materials) + + # Generate decryption materials + decryption_materials = DecryptionMaterials(verification_key=b"ex_verification_key") + + # Call on_decrypt function for the keyring + decryption_materials = fake_raw_aes_keyring.on_decrypt( + decryption_materials=decryption_materials, encrypted_data_keys=encryption_materials.encrypted_data_keys + ) + + # Check if the data keys match + assert encryption_materials.data_encryption_key == decryption_materials.data_key + diff --git a/test/functional/test_f_raw_rsa.py b/test/functional/test_f_raw_rsa.py index e69de29bb..d798d54ef 100644 --- a/test/functional/test_f_raw_rsa.py +++ b/test/functional/test_f_raw_rsa.py @@ -0,0 +1,97 @@ +# 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 Algorithm, EncryptionKeyType, WrappingAlgorithm +from aws_encryption_sdk.keyring.raw_keyring import RawRSAKeyring, WrappingKey +from aws_encryption_sdk.materials_managers import DecryptionMaterials, EncryptionMaterials +from aws_encryption_sdk.structures import DataKey, EncryptedDataKey, MasterKeyInfo + +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 = 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 = [ + 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=DataKey( + # 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, + # ), + # EncryptionMaterials( + # algorithm=Algorithm.AES_256_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384, + # data_encryption_key=DataKey( + # 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, + # ), +] + + +@pytest.mark.parametrize("encryption_materials", _ENCRYPTION_MATERIALS) +def test_raw_rsa_encryption_decryption(encryption_materials): + + # Initializing attributes + key_namespace = _PROVIDER_ID + key_name = _KEY_ID + _wrapping_key = WrappingKey( + wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, + wrapping_key=_WRAPPING_KEY, + wrapping_key_type=EncryptionKeyType.PRIVATE, + ) + _wrapping_algorithm = WrappingAlgorithm.RSA_OAEP_SHA256_MGF1 + + # Creating an instance of a raw AES keyring + fake_raw_rsa_keyring = RawRSAKeyring( + key_namespace=key_namespace, + key_name=key_name, + wrapping_key=_wrapping_key, + wrapping_algorithm=_wrapping_algorithm, + ) + + # Call on_encrypt function for the keyring + encryption_materials = fake_raw_rsa_keyring.on_encrypt(encryption_materials=encryption_materials) + + # Generate decryption materials + decryption_materials = DecryptionMaterials(verification_key=b"ex_verification_key") + + # Call on_decrypt function for the keyring + decryption_materials = fake_raw_rsa_keyring.on_decrypt( + decryption_materials=decryption_materials, encrypted_data_keys=encryption_materials.encrypted_data_keys + ) + + # Check if the data keys match + assert encryption_materials.data_encryption_key == decryption_materials.data_key From af239f63fe6e1ccc941f7ebac190f3f22e06bb40 Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Fri, 12 Jul 2019 16:26:03 -0700 Subject: [PATCH 068/119] Changed data encryption key type to RawDataKey --- test/functional/test_f_raw_aes.py | 53 +++++++++++++++---------------- test/functional/test_f_raw_rsa.py | 52 +++++++++++++++--------------- 2 files changed, 52 insertions(+), 53 deletions(-) diff --git a/test/functional/test_f_raw_aes.py b/test/functional/test_f_raw_aes.py index a4d79eab6..905c139f5 100644 --- a/test/functional/test_f_raw_aes.py +++ b/test/functional/test_f_raw_aes.py @@ -17,7 +17,7 @@ from aws_encryption_sdk.identifiers import Algorithm, EncryptionKeyType, WrappingAlgorithm from aws_encryption_sdk.keyring.raw_keyring import RawAESKeyring, WrappingKey from aws_encryption_sdk.materials_managers import DecryptionMaterials, EncryptionMaterials -from aws_encryption_sdk.structures import DataKey, EncryptedDataKey, MasterKeyInfo +from aws_encryption_sdk.structures import RawDataKey, EncryptedDataKey, MasterKeyInfo pytestmark = [pytest.mark.functional, pytest.mark.local] @@ -33,31 +33,31 @@ encryption_context=_ENCRYPTION_CONTEXT, signing_key=_SIGNING_KEY, ), - # EncryptionMaterials( - # algorithm=Algorithm.AES_256_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384, - # data_encryption_key=DataKey( - # 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, - # ), - # EncryptionMaterials( - # algorithm=Algorithm.AES_256_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384, - # data_encryption_key=DataKey( - # 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, - # ), + 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, + ), + 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, + ), ] @@ -95,4 +95,3 @@ def test_raw_aes_encryption_decryption(encryption_materials): # Check if the data keys match assert encryption_materials.data_encryption_key == decryption_materials.data_key - diff --git a/test/functional/test_f_raw_rsa.py b/test/functional/test_f_raw_rsa.py index d798d54ef..a5fbbce7e 100644 --- a/test/functional/test_f_raw_rsa.py +++ b/test/functional/test_f_raw_rsa.py @@ -17,7 +17,7 @@ from aws_encryption_sdk.identifiers import Algorithm, EncryptionKeyType, WrappingAlgorithm from aws_encryption_sdk.keyring.raw_keyring import RawRSAKeyring, WrappingKey from aws_encryption_sdk.materials_managers import DecryptionMaterials, EncryptionMaterials -from aws_encryption_sdk.structures import DataKey, EncryptedDataKey, MasterKeyInfo +from aws_encryption_sdk.structures import RawDataKey, EncryptedDataKey, MasterKeyInfo pytestmark = [pytest.mark.functional, pytest.mark.local] @@ -33,31 +33,31 @@ encryption_context=_ENCRYPTION_CONTEXT, signing_key=_SIGNING_KEY, ), - # EncryptionMaterials( - # algorithm=Algorithm.AES_256_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384, - # data_encryption_key=DataKey( - # 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, - # ), - # EncryptionMaterials( - # algorithm=Algorithm.AES_256_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384, - # data_encryption_key=DataKey( - # 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, - # ), + 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, + ), + 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, + ), ] From 1a4942712934ff9ebf358578164c4de2dd451d16 Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Sat, 13 Jul 2019 20:55:42 -0700 Subject: [PATCH 069/119] Added keyring trace to pytest encryption materials --- src/aws_encryption_sdk/keyring/raw_keyring.py | 15 ++--- .../materials_managers/__init__.py | 2 +- test/functional/test_f_raw_aes.py | 59 ++++++++++--------- test/functional/test_f_raw_rsa.py | 59 ++++++++++--------- 4 files changed, 71 insertions(+), 64 deletions(-) diff --git a/src/aws_encryption_sdk/keyring/raw_keyring.py b/src/aws_encryption_sdk/keyring/raw_keyring.py index a02b65608..caa24685e 100644 --- a/src/aws_encryption_sdk/keyring/raw_keyring.py +++ b/src/aws_encryption_sdk/keyring/raw_keyring.py @@ -78,9 +78,6 @@ def on_encrypt_helper( # Check if data key already exists if not encryption_materials.data_encryption_key: - # Create a keyring trace - keyring_trace = KeyringTrace(wrapping_key=key_provider, flags=set()) - # Generate data key plaintext_data_key = os.urandom(encryption_materials.algorithm.kdf_input_len) @@ -88,8 +85,9 @@ def on_encrypt_helper( if not plaintext_data_key: raise EncryptKeyError("Unable to generate data encryption key.") - # Update Keyring Trace - keyring_trace.flags.add(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) @@ -158,9 +156,6 @@ def on_decrypt_helper( if decryption_materials.data_key: return decryption_materials - # Create a keyring trace - keyring_trace = KeyringTrace(wrapping_key=key_provider, flags=set()) - # 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 @@ -171,7 +166,9 @@ def on_decrypt_helper( plaintext_data_key = wrapping_key.decrypt( encrypted_wrapped_data_key=encrypted_wrapped_key, encryption_context=decryption_materials.encryption_context ) - keyring_trace.flags.add(KeyringTraceFlag.WRAPPING_KEY_DECRYPTED_DATA_KEY) + # Create a keyring trace + keyring_trace = KeyringTrace(wrapping_key=encrypted_wrapped_key.key_provider, + flags={KeyringTraceFlag.WRAPPING_KEY_DECRYPTED_DATA_KEY}) except Exception as error: logging.ERROR(error.__class__.__name__, ":", str(error)) diff --git a/src/aws_encryption_sdk/materials_managers/__init__.py b/src/aws_encryption_sdk/materials_managers/__init__.py index a1947b100..0c4459aca 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` diff --git a/test/functional/test_f_raw_aes.py b/test/functional/test_f_raw_aes.py index 905c139f5..ca58112ab 100644 --- a/test/functional/test_f_raw_aes.py +++ b/test/functional/test_f_raw_aes.py @@ -14,10 +14,10 @@ import pytest -from aws_encryption_sdk.identifiers import Algorithm, EncryptionKeyType, WrappingAlgorithm +from aws_encryption_sdk.identifiers import Algorithm, EncryptionKeyType, WrappingAlgorithm, KeyringTraceFlag from aws_encryption_sdk.keyring.raw_keyring import RawAESKeyring, WrappingKey from aws_encryption_sdk.materials_managers import DecryptionMaterials, EncryptionMaterials -from aws_encryption_sdk.structures import RawDataKey, EncryptedDataKey, MasterKeyInfo +from aws_encryption_sdk.structures import RawDataKey, EncryptedDataKey, MasterKeyInfo, KeyringTrace pytestmark = [pytest.mark.functional, pytest.mark.local] @@ -33,31 +33,36 @@ 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, - ), - 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, - ), + # 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}) + # ), ] diff --git a/test/functional/test_f_raw_rsa.py b/test/functional/test_f_raw_rsa.py index a5fbbce7e..b450e350d 100644 --- a/test/functional/test_f_raw_rsa.py +++ b/test/functional/test_f_raw_rsa.py @@ -14,10 +14,10 @@ import pytest -from aws_encryption_sdk.identifiers import Algorithm, EncryptionKeyType, WrappingAlgorithm +from aws_encryption_sdk.identifiers import Algorithm, EncryptionKeyType, WrappingAlgorithm, KeyringTraceFlag from aws_encryption_sdk.keyring.raw_keyring import RawRSAKeyring, WrappingKey from aws_encryption_sdk.materials_managers import DecryptionMaterials, EncryptionMaterials -from aws_encryption_sdk.structures import RawDataKey, EncryptedDataKey, MasterKeyInfo +from aws_encryption_sdk.structures import RawDataKey, EncryptedDataKey, MasterKeyInfo, KeyringTrace pytestmark = [pytest.mark.functional, pytest.mark.local] @@ -33,31 +33,36 @@ 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, - ), - 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, - ), + # 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}) + # ), ] From ec1d8b5aa0469114dc2dc391f4317522ba0f2ed4 Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Mon, 15 Jul 2019 10:48:05 -0700 Subject: [PATCH 070/119] Changed value of keyring_trace.wrapping_key --- src/aws_encryption_sdk/keyring/raw_keyring.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/aws_encryption_sdk/keyring/raw_keyring.py b/src/aws_encryption_sdk/keyring/raw_keyring.py index caa24685e..4bdef0d7a 100644 --- a/src/aws_encryption_sdk/keyring/raw_keyring.py +++ b/src/aws_encryption_sdk/keyring/raw_keyring.py @@ -114,6 +114,7 @@ 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 @@ -166,14 +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 ) - # Create a keyring trace - keyring_trace = KeyringTrace(wrapping_key=encrypted_wrapped_key.key_provider, - flags={KeyringTraceFlag.WRAPPING_KEY_DECRYPTED_DATA_KEY}) 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 From 5ff39d64c1848cdc449d3fec745214fedc81ea75 Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Mon, 15 Jul 2019 13:23:59 -0700 Subject: [PATCH 071/119] Few changes to match new API --- src/aws_encryption_sdk/keyring/raw_keyring.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/aws_encryption_sdk/keyring/raw_keyring.py b/src/aws_encryption_sdk/keyring/raw_keyring.py index 4bdef0d7a..fbe1d84d1 100644 --- a/src/aws_encryption_sdk/keyring/raw_keyring.py +++ b/src/aws_encryption_sdk/keyring/raw_keyring.py @@ -154,7 +154,7 @@ def on_decrypt_helper( """ # 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 @@ -177,11 +177,12 @@ def on_decrypt_helper( 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) + # 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 64298a704971a3df6f11cfbcaf9d45943e62aa5e Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Mon, 15 Jul 2019 14:52:40 -0700 Subject: [PATCH 072/119] Tox errors --- src/aws_encryption_sdk/keyring/raw_keyring.py | 24 +++++++++---------- test/functional/test_f_raw_aes.py | 4 ++-- test/functional/test_f_raw_rsa.py | 4 ++-- 3 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 fbe1d84d1..8233cba28 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_encryption_key: return decryption_materials @@ -169,18 +167,20 @@ 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: # 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( key_provider=MasterKeyInfo(provider_id=key_provider.provider_id, key_info=key_name), - data_key=plaintext_data_key + data_key=plaintext_data_key, ) decryption_materials.add_data_encryption_key(data_encryption_key, keyring_trace) diff --git a/test/functional/test_f_raw_aes.py b/test/functional/test_f_raw_aes.py index ca58112ab..5764c07e5 100644 --- a/test/functional/test_f_raw_aes.py +++ b/test/functional/test_f_raw_aes.py @@ -14,10 +14,10 @@ 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.raw_keyring import RawAESKeyring, 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] diff --git a/test/functional/test_f_raw_rsa.py b/test/functional/test_f_raw_rsa.py index b450e350d..0fefb2fba 100644 --- a/test/functional/test_f_raw_rsa.py +++ b/test/functional/test_f_raw_rsa.py @@ -14,10 +14,10 @@ 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.raw_keyring import 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] From cc5aa44d6e957eb0affa9d82f8def2d53832108a Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Tue, 16 Jul 2019 13:49:42 -0700 Subject: [PATCH 073/119] Functional tests pass --- src/aws_encryption_sdk/keyring/raw_keyring.py | 17 ++- .../materials_managers/__init__.py | 2 +- test/functional/test_f_raw_aes.py | 85 +++++++------ test/functional/test_f_raw_rsa.py | 119 ++++++++++++------ 4 files changed, 137 insertions(+), 86 deletions(-) diff --git a/src/aws_encryption_sdk/keyring/raw_keyring.py b/src/aws_encryption_sdk/keyring/raw_keyring.py index 8233cba28..e3e53d73e 100644 --- a/src/aws_encryption_sdk/keyring/raw_keyring.py +++ b/src/aws_encryption_sdk/keyring/raw_keyring.py @@ -86,7 +86,8 @@ def on_encrypt_helper( # Create a keyring trace keyring_trace = KeyringTrace( - wrapping_key=key_provider, flags={KeyringTraceFlag.WRAPPING_KEY_GENERATED_DATA_KEY} + wrapping_key=key_provider, + flags={KeyringTraceFlag.WRAPPING_KEY_GENERATED_DATA_KEY} ) # plaintext_data_key to RawDataKey @@ -96,8 +97,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 +114,11 @@ 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) + 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, 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 diff --git a/src/aws_encryption_sdk/materials_managers/__init__.py b/src/aws_encryption_sdk/materials_managers/__init__.py index 0c4459aca..0a6dcd2f0 100644 --- a/src/aws_encryption_sdk/materials_managers/__init__.py +++ b/src/aws_encryption_sdk/materials_managers/__init__.py @@ -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_raw_aes.py b/test/functional/test_f_raw_aes.py index 5764c07e5..9a92e5dea 100644 --- a/test/functional/test_f_raw_aes.py +++ b/test/functional/test_f_raw_aes.py @@ -14,7 +14,7 @@ import pytest -from aws_encryption_sdk.identifiers import Algorithm, EncryptionKeyType, KeyringTraceFlag, WrappingAlgorithm +from aws_encryption_sdk.identifiers import Algorithm, EncryptionKeyType, WrappingAlgorithm, KeyringTraceFlag from aws_encryption_sdk.keyring.raw_keyring import RawAESKeyring, WrappingKey from aws_encryption_sdk.materials_managers import DecryptionMaterials, EncryptionMaterials from aws_encryption_sdk.structures import EncryptedDataKey, KeyringTrace, MasterKeyInfo, RawDataKey @@ -33,41 +33,49 @@ 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}) - # ), + 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}), + # KeyringTrace(wrapping_key=MasterKeyInfo(provider_id=_PROVIDER_ID, + # key_info=_KEY_ID), + # flags={KeyringTraceFlag.WRAPPING_KEY_ENCRYPTED_DATA_KEY} + # ) + ] + ), ] -@pytest.mark.parametrize("encryption_materials", _ENCRYPTION_MATERIALS) -def test_raw_aes_encryption_decryption(encryption_materials): +@pytest.mark.parametrize("encryption_materials_samples", _ENCRYPTION_MATERIALS) +def test_raw_aes_encryption_decryption(encryption_materials_samples): # Initializing attributes key_namespace = _PROVIDER_ID @@ -88,15 +96,18 @@ def test_raw_aes_encryption_decryption(encryption_materials): ) # Call on_encrypt function for the keyring - encryption_materials = fake_raw_aes_keyring.on_encrypt(encryption_materials=encryption_materials) + encryption_materials = fake_raw_aes_keyring.on_encrypt(encryption_materials=encryption_materials_samples) # Generate decryption materials - decryption_materials = DecryptionMaterials(verification_key=b"ex_verification_key") + 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 = fake_raw_aes_keyring.on_decrypt( decryption_materials=decryption_materials, encrypted_data_keys=encryption_materials.encrypted_data_keys ) - # Check if the data keys match - assert encryption_materials.data_encryption_key == decryption_materials.data_key + if decryption_materials.data_encryption_key: + # Check if the data keys match + assert encryption_materials.data_encryption_key == decryption_materials.data_encryption_key + return diff --git a/test/functional/test_f_raw_rsa.py b/test/functional/test_f_raw_rsa.py index 0fefb2fba..5d3900741 100644 --- a/test/functional/test_f_raw_rsa.py +++ b/test/functional/test_f_raw_rsa.py @@ -13,8 +13,10 @@ """Functional tests for Raw AES keyring encryption decryption path.""" import pytest +from cryptography.hazmat.backends import default_backend +from cryptography.hazmat.primitives.asymmetric import rsa -from aws_encryption_sdk.identifiers import Algorithm, EncryptionKeyType, KeyringTraceFlag, WrappingAlgorithm +from aws_encryption_sdk.identifiers import Algorithm, EncryptionKeyType, WrappingAlgorithm, KeyringTraceFlag from aws_encryption_sdk.keyring.raw_keyring import RawRSAKeyring, WrappingKey from aws_encryption_sdk.materials_managers import DecryptionMaterials, EncryptionMaterials from aws_encryption_sdk.structures import EncryptedDataKey, KeyringTrace, MasterKeyInfo, RawDataKey @@ -24,7 +26,37 @@ _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" +pem = rsa.generate_private_key(public_exponent=65537, + key_size=2048, + backend=default_backend()) +_WRAPPING_KEY = ( + 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") _SIGNING_KEY = b"aws-crypto-public-key" _ENCRYPTION_MATERIALS = [ @@ -33,41 +65,49 @@ 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}) - # ), + 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}), + # KeyringTrace(wrapping_key=MasterKeyInfo(provider_id=_PROVIDER_ID, + # key_info=_KEY_ID), + # flags={KeyringTraceFlag.WRAPPING_KEY_ENCRYPTED_DATA_KEY} + # ) + ] + ), ] -@pytest.mark.parametrize("encryption_materials", _ENCRYPTION_MATERIALS) -def test_raw_rsa_encryption_decryption(encryption_materials): +@pytest.mark.parametrize("encryption_materials_samples", _ENCRYPTION_MATERIALS) +def test_raw_rsa_encryption_decryption(encryption_materials_samples): # Initializing attributes key_namespace = _PROVIDER_ID @@ -88,15 +128,18 @@ def test_raw_rsa_encryption_decryption(encryption_materials): ) # Call on_encrypt function for the keyring - encryption_materials = fake_raw_rsa_keyring.on_encrypt(encryption_materials=encryption_materials) + encryption_materials = fake_raw_rsa_keyring.on_encrypt(encryption_materials=encryption_materials_samples) # Generate decryption materials - decryption_materials = DecryptionMaterials(verification_key=b"ex_verification_key") + 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 = fake_raw_rsa_keyring.on_decrypt( decryption_materials=decryption_materials, encrypted_data_keys=encryption_materials.encrypted_data_keys ) - # Check if the data keys match - assert encryption_materials.data_encryption_key == decryption_materials.data_key + if decryption_materials.data_encryption_key: + # Check if the data keys match + assert encryption_materials.data_encryption_key == decryption_materials.data_encryption_key + return From 7d896d14a9941c5e09196fbd39a9b184b17c52a8 Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Tue, 16 Jul 2019 13:50:42 -0700 Subject: [PATCH 074/119] Formatting errors corrected and functional tests pass --- src/aws_encryption_sdk/keyring/raw_keyring.py | 8 +- test/functional/test_f_raw_aes.py | 29 +++--- test/functional/test_f_raw_rsa.py | 88 ++++++++++--------- 3 files changed, 69 insertions(+), 56 deletions(-) diff --git a/src/aws_encryption_sdk/keyring/raw_keyring.py b/src/aws_encryption_sdk/keyring/raw_keyring.py index e3e53d73e..30ec3968e 100644 --- a/src/aws_encryption_sdk/keyring/raw_keyring.py +++ b/src/aws_encryption_sdk/keyring/raw_keyring.py @@ -86,8 +86,7 @@ def on_encrypt_helper( # Create a keyring trace keyring_trace = KeyringTrace( - wrapping_key=key_provider, - flags={KeyringTraceFlag.WRAPPING_KEY_GENERATED_DATA_KEY} + wrapping_key=key_provider, flags={KeyringTraceFlag.WRAPPING_KEY_GENERATED_DATA_KEY} ) # plaintext_data_key to RawDataKey @@ -114,8 +113,9 @@ def on_encrypt_helper( # 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) diff --git a/test/functional/test_f_raw_aes.py b/test/functional/test_f_raw_aes.py index 9a92e5dea..770063cfb 100644 --- a/test/functional/test_f_raw_aes.py +++ b/test/functional/test_f_raw_aes.py @@ -14,7 +14,7 @@ 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.raw_keyring import RawAESKeyring, WrappingKey from aws_encryption_sdk.materials_managers import DecryptionMaterials, EncryptionMaterials from aws_encryption_sdk.structures import EncryptedDataKey, KeyringTrace, MasterKeyInfo, RawDataKey @@ -41,9 +41,12 @@ ), 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})] + 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, @@ -61,15 +64,18 @@ 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}), + 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, + }, + ), # KeyringTrace(wrapping_key=MasterKeyInfo(provider_id=_PROVIDER_ID, # key_info=_KEY_ID), # flags={KeyringTraceFlag.WRAPPING_KEY_ENCRYPTED_DATA_KEY} # ) - ] + ], ), ] @@ -99,8 +105,9 @@ def test_raw_aes_encryption_decryption(encryption_materials_samples): encryption_materials = fake_raw_aes_keyring.on_encrypt(encryption_materials=encryption_materials_samples) # Generate decryption materials - decryption_materials = DecryptionMaterials(algorithm=Algorithm.AES_256_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384, - verification_key=b"ex_verification_key") + 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 = fake_raw_aes_keyring.on_decrypt( diff --git a/test/functional/test_f_raw_rsa.py b/test/functional/test_f_raw_rsa.py index 5d3900741..ea3f20441 100644 --- a/test/functional/test_f_raw_rsa.py +++ b/test/functional/test_f_raw_rsa.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, EncryptionKeyType, WrappingAlgorithm, KeyringTraceFlag +from aws_encryption_sdk.identifiers import Algorithm, EncryptionKeyType, KeyringTraceFlag, WrappingAlgorithm from aws_encryption_sdk.keyring.raw_keyring import RawRSAKeyring, WrappingKey from aws_encryption_sdk.materials_managers import DecryptionMaterials, EncryptionMaterials from aws_encryption_sdk.structures import EncryptedDataKey, KeyringTrace, MasterKeyInfo, RawDataKey @@ -26,37 +26,36 @@ _ENCRYPTION_CONTEXT = {"encryption": "context", "values": "here"} _PROVIDER_ID = "Random Raw Keys" _KEY_ID = b"5325b043-5843-4629-869c-64794af77ada" -pem = rsa.generate_private_key(public_exponent=65537, - key_size=2048, - backend=default_backend()) +pem = rsa.generate_private_key(public_exponent=65537, key_size=2048, backend=default_backend()) _WRAPPING_KEY = ( - 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") + 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" +) _SIGNING_KEY = b"aws-crypto-public-key" _ENCRYPTION_MATERIALS = [ @@ -73,9 +72,12 @@ ), 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})] + 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, @@ -93,15 +95,18 @@ 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}), + 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, + }, + ), # KeyringTrace(wrapping_key=MasterKeyInfo(provider_id=_PROVIDER_ID, # key_info=_KEY_ID), # flags={KeyringTraceFlag.WRAPPING_KEY_ENCRYPTED_DATA_KEY} # ) - ] + ], ), ] @@ -131,8 +136,9 @@ def test_raw_rsa_encryption_decryption(encryption_materials_samples): encryption_materials = fake_raw_rsa_keyring.on_encrypt(encryption_materials=encryption_materials_samples) # Generate decryption materials - decryption_materials = DecryptionMaterials(algorithm=Algorithm.AES_256_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384, - verification_key=b"ex_verification_key") + 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 = fake_raw_rsa_keyring.on_decrypt( From 3eb4536f95816361775288fc2df032dbf2be0b94 Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Tue, 16 Jul 2019 14:13:26 -0700 Subject: [PATCH 075/119] Corrected too broad exception error and deleted empty return statement from tests --- src/aws_encryption_sdk/keyring/raw_keyring.py | 2 +- test/functional/test_f_raw_aes.py | 1 - test/functional/test_f_raw_rsa.py | 1 - 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/aws_encryption_sdk/keyring/raw_keyring.py b/src/aws_encryption_sdk/keyring/raw_keyring.py index 30ec3968e..b498c61f8 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 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_raw_aes.py b/test/functional/test_f_raw_aes.py index 770063cfb..62730f782 100644 --- a/test/functional/test_f_raw_aes.py +++ b/test/functional/test_f_raw_aes.py @@ -117,4 +117,3 @@ def test_raw_aes_encryption_decryption(encryption_materials_samples): if decryption_materials.data_encryption_key: # Check if the data keys match assert encryption_materials.data_encryption_key == decryption_materials.data_encryption_key - return diff --git a/test/functional/test_f_raw_rsa.py b/test/functional/test_f_raw_rsa.py index ea3f20441..247bfa75e 100644 --- a/test/functional/test_f_raw_rsa.py +++ b/test/functional/test_f_raw_rsa.py @@ -148,4 +148,3 @@ def test_raw_rsa_encryption_decryption(encryption_materials_samples): if decryption_materials.data_encryption_key: # Check if the data keys match assert encryption_materials.data_encryption_key == decryption_materials.data_encryption_key - return From b1ad3ede0c5f533cf0704c399180befef1560e85 Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Tue, 16 Jul 2019 15:51:55 -0700 Subject: [PATCH 076/119] Changed Exeception to BaseException to solve broad exception error --- src/aws_encryption_sdk/keyring/raw_keyring.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 From 03aeae344c58d158651e1a5b9b175e15d46d3a6f Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Tue, 16 Jul 2019 17:06:18 -0700 Subject: [PATCH 077/119] Added suppress broad exception --- src/aws_encryption_sdk/keyring/raw_keyring.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/aws_encryption_sdk/keyring/raw_keyring.py b/src/aws_encryption_sdk/keyring/raw_keyring.py index 3380fbad3..1c790aa43 100644 --- a/src/aws_encryption_sdk/keyring/raw_keyring.py +++ b/src/aws_encryption_sdk/keyring/raw_keyring.py @@ -158,12 +158,13 @@ def on_decrypt_helper( ) # EncryptedData to raw key string + # noinspection PyBroadException try: plaintext_data_key = wrapping_key.decrypt( encrypted_wrapped_data_key=encrypted_wrapped_key, encryption_context=decryption_materials.encryption_context ) - except BaseException as error: + except Exception as error: logger = logging.getLogger() logger.error(error.__class__.__name__, ":", str(error)) return decryption_materials From 2a248f5b0e634ef028241f7e3977af5ed3661661 Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Tue, 16 Jul 2019 17:19:25 -0700 Subject: [PATCH 078/119] Added pylint disable broad exception --- src/aws_encryption_sdk/keyring/raw_keyring.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/aws_encryption_sdk/keyring/raw_keyring.py b/src/aws_encryption_sdk/keyring/raw_keyring.py index 1c790aa43..16158a727 100644 --- a/src/aws_encryption_sdk/keyring/raw_keyring.py +++ b/src/aws_encryption_sdk/keyring/raw_keyring.py @@ -158,13 +158,12 @@ def on_decrypt_helper( ) # EncryptedData to raw key string - # noinspection PyBroadException try: plaintext_data_key = wrapping_key.decrypt( encrypted_wrapped_data_key=encrypted_wrapped_key, encryption_context=decryption_materials.encryption_context ) - except Exception as error: + except Exception as error: # pylint: disable=broad-except logger = logging.getLogger() logger.error(error.__class__.__name__, ":", str(error)) return decryption_materials From 92f419c53a91b5e291c4da46a31108745d6c0503 Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Wed, 17 Jul 2019 18:22:04 -0700 Subject: [PATCH 079/119] Changed wrapping keys for RSA keyrings from WrappingKey to cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKey/RSAPublicKey --- src/aws_encryption_sdk/keyring/raw_keyring.py | 260 ++++++++++-------- test/functional/test_f_raw_aes.py | 13 +- test/functional/test_f_raw_rsa.py | 28 +- 3 files changed, 150 insertions(+), 151 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_raw_aes.py b/test/functional/test_f_raw_aes.py index 62730f782..9fa213232 100644 --- a/test/functional/test_f_raw_aes.py +++ b/test/functional/test_f_raw_aes.py @@ -70,11 +70,7 @@ KeyringTraceFlag.WRAPPING_KEY_GENERATED_DATA_KEY, KeyringTraceFlag.WRAPPING_KEY_ENCRYPTED_DATA_KEY, }, - ), - # KeyringTrace(wrapping_key=MasterKeyInfo(provider_id=_PROVIDER_ID, - # key_info=_KEY_ID), - # flags={KeyringTraceFlag.WRAPPING_KEY_ENCRYPTED_DATA_KEY} - # ) + ) ], ), ] @@ -86,18 +82,13 @@ def test_raw_aes_encryption_decryption(encryption_materials_samples): # Initializing attributes 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, - wrapping_key_type=EncryptionKeyType.SYMMETRIC, - ) _wrapping_algorithm = WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING # Creating an instance of a raw AES keyring fake_raw_aes_keyring = RawAESKeyring( key_namespace=key_namespace, key_name=key_name, - wrapping_key=_wrapping_key, + wrapping_key=_WRAPPING_KEY, wrapping_algorithm=_wrapping_algorithm, ) diff --git a/test/functional/test_f_raw_rsa.py b/test/functional/test_f_raw_rsa.py index 247bfa75e..75f9466c8 100644 --- a/test/functional/test_f_raw_rsa.py +++ b/test/functional/test_f_raw_rsa.py @@ -14,10 +14,10 @@ import pytest from cryptography.hazmat.backends import default_backend -from cryptography.hazmat.primitives.asymmetric import rsa +from cryptography.hazmat.primitives import serialization -from aws_encryption_sdk.identifiers import Algorithm, EncryptionKeyType, KeyringTraceFlag, WrappingAlgorithm -from aws_encryption_sdk.keyring.raw_keyring import RawRSAKeyring, WrappingKey +from aws_encryption_sdk.identifiers import Algorithm, KeyringTraceFlag, WrappingAlgorithm +from aws_encryption_sdk.keyring.raw_keyring import RawRSAKeyring from aws_encryption_sdk.materials_managers import DecryptionMaterials, EncryptionMaterials from aws_encryption_sdk.structures import EncryptedDataKey, KeyringTrace, MasterKeyInfo, RawDataKey @@ -26,9 +26,8 @@ _ENCRYPTION_CONTEXT = {"encryption": "context", "values": "here"} _PROVIDER_ID = "Random Raw Keys" _KEY_ID = b"5325b043-5843-4629-869c-64794af77ada" -pem = rsa.generate_private_key(public_exponent=65537, key_size=2048, backend=default_backend()) -_WRAPPING_KEY = ( - b"-----BEGIN RSA PRIVATE KEY-----\n" +_WRAPPING_KEY = serialization.load_pem_private_key( + data=b"-----BEGIN RSA PRIVATE KEY-----\n" b"MIIEowIBAAKCAQEAo8uCyhiO4JUGZV+rtNq5DBA9Lm4xkw5kTA3v6EPybs8bVXL2\n" b"ZE6jkbo+xT4Jg/bKzUpnp1fE+T1ruGPtsPdoEmhY/P64LDNIs3sRq5U4QV9IETU1\n" b"vIcbNNkgGhRjV8J87YNY0tV0H7tuWuZRpqnS+gjV6V9lUMkbvjMCc5IBqQc3heut\n" @@ -54,7 +53,9 @@ b"ye+xgQKBgD58b+9z+PR5LAJm1tZHIwb4tnyczP28PzwknxFd2qylR4ZNgvAUqGtU\n" b"xvpUDpzMioz6zUH9YV43YNtt+5Xnzkqj+u9Mr27/H2v9XPwORGfwQ5XPwRJz/2oC\n" b"EnPmP1SZoY9lXKUpQXHXSpDZ2rE2Klt3RHMUMHt8Zpy36E8Vwx8o\n" - b"-----END RSA PRIVATE KEY-----\n" + b"-----END RSA PRIVATE KEY-----\n", + password=None, + backend=default_backend(), ) _SIGNING_KEY = b"aws-crypto-public-key" @@ -101,11 +102,7 @@ KeyringTraceFlag.WRAPPING_KEY_GENERATED_DATA_KEY, KeyringTraceFlag.WRAPPING_KEY_ENCRYPTED_DATA_KEY, }, - ), - # KeyringTrace(wrapping_key=MasterKeyInfo(provider_id=_PROVIDER_ID, - # key_info=_KEY_ID), - # flags={KeyringTraceFlag.WRAPPING_KEY_ENCRYPTED_DATA_KEY} - # ) + ) ], ), ] @@ -117,18 +114,13 @@ def test_raw_rsa_encryption_decryption(encryption_materials_samples): # Initializing attributes key_namespace = _PROVIDER_ID key_name = _KEY_ID - _wrapping_key = WrappingKey( - wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, - wrapping_key=_WRAPPING_KEY, - wrapping_key_type=EncryptionKeyType.PRIVATE, - ) _wrapping_algorithm = WrappingAlgorithm.RSA_OAEP_SHA256_MGF1 # Creating an instance of a raw AES keyring fake_raw_rsa_keyring = RawRSAKeyring( key_namespace=key_namespace, key_name=key_name, - wrapping_key=_wrapping_key, + wrapping_key=_WRAPPING_KEY, wrapping_algorithm=_wrapping_algorithm, ) From 66b56b73fb4f2de6e287d0fbf1fef7db21a86d84 Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Wed, 17 Jul 2019 18:52:00 -0700 Subject: [PATCH 080/119] Fixed tox errors --- src/aws_encryption_sdk/keyring/raw_keyring.py | 17 +++++++++-------- test/functional/test_f_raw_aes.py | 4 ++-- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/aws_encryption_sdk/keyring/raw_keyring.py b/src/aws_encryption_sdk/keyring/raw_keyring.py index 93d6fd080..74910a6b6 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 @@ -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) @@ -290,9 +289,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, ) @@ -340,12 +339,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) diff --git a/test/functional/test_f_raw_aes.py b/test/functional/test_f_raw_aes.py index 9fa213232..df295208b 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.identifiers import Algorithm, EncryptionKeyType, KeyringTraceFlag, WrappingAlgorithm -from aws_encryption_sdk.keyring.raw_keyring import RawAESKeyring, WrappingKey +from aws_encryption_sdk.identifiers import Algorithm, KeyringTraceFlag, WrappingAlgorithm +from aws_encryption_sdk.keyring.raw_keyring import RawAESKeyring from aws_encryption_sdk.materials_managers import DecryptionMaterials, EncryptionMaterials from aws_encryption_sdk.structures import EncryptedDataKey, KeyringTrace, MasterKeyInfo, RawDataKey From 0295db5a343c2616d70370c079506824389c057e Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Wed, 17 Jul 2019 19:03:06 -0700 Subject: [PATCH 081/119] More tox errors --- src/aws_encryption_sdk/keyring/raw_keyring.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/aws_encryption_sdk/keyring/raw_keyring.py b/src/aws_encryption_sdk/keyring/raw_keyring.py index 74910a6b6..c96932eeb 100644 --- a/src/aws_encryption_sdk/keyring/raw_keyring.py +++ b/src/aws_encryption_sdk/keyring/raw_keyring.py @@ -214,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, ) From 4adec205f4a2fd3939ef9c14bc91951e0e817ab4 Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Wed, 17 Jul 2019 22:54:03 -0700 Subject: [PATCH 082/119] Moved code for generation of plaintext to be before the check for key being private or public --- src/aws_encryption_sdk/keyring/raw_keyring.py | 26 +++++++++---------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/src/aws_encryption_sdk/keyring/raw_keyring.py b/src/aws_encryption_sdk/keyring/raw_keyring.py index c96932eeb..f3c7de88a 100644 --- a/src/aws_encryption_sdk/keyring/raw_keyring.py +++ b/src/aws_encryption_sdk/keyring/raw_keyring.py @@ -110,6 +110,7 @@ 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 @@ -214,7 +215,7 @@ def on_decrypt(self, decryption_materials, encrypted_data_keys): ) # EncryptedData to raw key string try: - plaintext_data_key = self._wrapping_key_structure.decrypt( + plaintext_data_key = wrapping_key.decrypt( encrypted_wrapped_data_key=encrypted_wrapped_key, encryption_context=decryption_materials.encryption_context, ) @@ -227,12 +228,12 @@ def on_decrypt(self, decryption_materials, encrypted_data_keys): if plaintext_data_key: # Create a keyring trace keyring_trace = KeyringTrace( - wrapping_key=self._key_provider, flags={KeyringTraceFlag.WRAPPING_KEY_DECRYPTED_DATA_KEY} + wrapping_key=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), + 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) @@ -276,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 @@ -289,9 +289,9 @@ def on_encrypt(self, 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, + key_provider=key_provider, + wrapping_algorithm=wrapping_algorithm, + wrapping_key_id=key_name, encrypted_wrapped_key=encrypted_wrapped_key, ) @@ -339,14 +339,12 @@ def on_decrypt(self, decryption_materials, encrypted_data_keys): if plaintext_data_key: # Create a keyring trace keyring_trace = KeyringTrace( - wrapping_key=self._key_provider, flags={KeyringTraceFlag.WRAPPING_KEY_DECRYPTED_DATA_KEY} + wrapping_key=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 - ), + 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) From 22243dc61080b1e06fff6b03673afc5555014d41 Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Wed, 17 Jul 2019 23:04:42 -0700 Subject: [PATCH 083/119] Tox errors --- src/aws_encryption_sdk/keyring/raw_keyring.py | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/aws_encryption_sdk/keyring/raw_keyring.py b/src/aws_encryption_sdk/keyring/raw_keyring.py index f3c7de88a..f50d96618 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) @@ -289,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, ) @@ -339,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 07d05f7ea4b60ce6a42a96319bca58f827f9f8cd Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Thu, 18 Jul 2019 14:23:12 -0700 Subject: [PATCH 084/119] Added metaclass to base API and unit tests for base API --- src/aws_encryption_sdk/keyring/base.py | 6 ++- test/unit/test_base_keyring.py | 62 ++++++++++++++++++++++++++ test/unit/test_raw_aes_keyring.py | 0 3 files changed, 67 insertions(+), 1 deletion(-) create mode 100644 test/unit/test_base_keyring.py create mode 100644 test/unit/test_raw_aes_keyring.py diff --git a/src/aws_encryption_sdk/keyring/base.py b/src/aws_encryption_sdk/keyring/base.py index 770b53c0b..8ccf2af09 100644 --- a/src/aws_encryption_sdk/keyring/base.py +++ b/src/aws_encryption_sdk/keyring/base.py @@ -11,6 +11,8 @@ # 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.""" +import abc + from aws_encryption_sdk.materials_managers import DecryptionMaterials, EncryptionMaterials from aws_encryption_sdk.structures import EncryptedDataKey @@ -21,12 +23,13 @@ pass -class Keyring(object): +class Keyring(object, metaclass=abc.ABCMeta): """Parent interface for Keyring classes. .. versionadded:: 1.5.0 """ + @abc.abstractmethod def on_encrypt(self, encryption_materials): # type: (EncryptionMaterials) -> EncryptionMaterials """Generate a data key if not present and encrypt it using any available wrapping key. @@ -39,6 +42,7 @@ def on_encrypt(self, encryption_materials): """ raise NotImplementedError("Keyring does not implement on_encrypt function") + @abc.abstractmethod def on_decrypt(self, decryption_materials, encrypted_data_keys): # type: (DecryptionMaterials, Iterable[EncryptedDataKey]) -> DecryptionMaterials """Attempt to decrypt the encrypted data keys. diff --git a/test/unit/test_base_keyring.py b/test/unit/test_base_keyring.py new file mode 100644 index 000000000..1c35f966b --- /dev/null +++ b/test/unit/test_base_keyring.py @@ -0,0 +1,62 @@ +# 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 base keyring.""" + +import pytest + +from aws_encryption_sdk.identifiers import Algorithm +from aws_encryption_sdk.keyring.base import Keyring +from aws_encryption_sdk.keyring.raw_keyring import RawAESKeyring +from aws_encryption_sdk.materials_managers import DecryptionMaterials, EncryptionMaterials + +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_materials = EncryptionMaterials( + algorithm=Algorithm.AES_256_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384, + encryption_context={"encryption": "context", "values": "here"}, + signing_key=b"aws-crypto-public-key", +) + +_decryption_materials = DecryptionMaterials( + algorithm=Algorithm.AES_256_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384, verification_key=b"ex_verification_key" +) + + +def test_keyring_no_encrypt(): + class KeyringNoEncrypt(Keyring): + def on_decrypt(self, _decryption_materials, encrypted_data_keys): + # type: (DecryptionMaterials, Iterable[EncryptedDataKey]) -> DecryptionMaterials + decryption_materials = RawAESKeyring.on_decrypt(decryption_materials=_decryption_materials) + return decryption_materials + + with pytest.raises(TypeError) as exc_info: + KeyringNoEncrypt() + exc_info.match("Can't instantiate abstract class KeyringNoEncrypt with abstract methods on_encrypt") + + +def test_keyring_no_decrypt(): + class KeyringNoDecrypt(Keyring): + def on_encrypt(self, _encryption_materials): + # type: (EncryptionMaterials) -> EncryptionMaterials + encryption_materials = RawAESKeyring.on_encrypt(encryption_materials=_encryption_materials) + return encryption_materials + + with pytest.raises(TypeError) as exc_info: + KeyringNoDecrypt() + exc_info.match("Can't instantiate abstract class KeyringNoDecrypt with abstract methods on_decrypt") diff --git a/test/unit/test_raw_aes_keyring.py b/test/unit/test_raw_aes_keyring.py new file mode 100644 index 000000000..e69de29bb From 6df10d5c8af2a7950e7b5fa2666134f7e2435b37 Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Thu, 18 Jul 2019 14:28:11 -0700 Subject: [PATCH 085/119] Changed metaclass to six.add_metaclass in base API --- 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 8ccf2af09..f253ce500 100644 --- a/src/aws_encryption_sdk/keyring/base.py +++ b/src/aws_encryption_sdk/keyring/base.py @@ -13,6 +13,8 @@ """Base class interface for Keyrings.""" import abc +import six + from aws_encryption_sdk.materials_managers import DecryptionMaterials, EncryptionMaterials from aws_encryption_sdk.structures import EncryptedDataKey @@ -23,7 +25,8 @@ pass -class Keyring(object, metaclass=abc.ABCMeta): +@six.add_metaclass(abc.ABCMeta) +class Keyring(object): """Parent interface for Keyring classes. .. versionadded:: 1.5.0 From 8e47badaa68b1244ba65b2087910eca386850a9f Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Thu, 18 Jul 2019 15:18:25 -0700 Subject: [PATCH 086/119] Fixed pylint errors --- test/unit/test_base_keyring.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unit/test_base_keyring.py b/test/unit/test_base_keyring.py index 1c35f966b..025373c28 100644 --- a/test/unit/test_base_keyring.py +++ b/test/unit/test_base_keyring.py @@ -15,7 +15,7 @@ import pytest from aws_encryption_sdk.identifiers import Algorithm -from aws_encryption_sdk.keyring.base import Keyring +from aws_encryption_sdk.keyring.base import Keyring, EncryptedDataKey from aws_encryption_sdk.keyring.raw_keyring import RawAESKeyring from aws_encryption_sdk.materials_managers import DecryptionMaterials, EncryptionMaterials From 4aae643993862aacb22c300466c650682d9ee0ce Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Thu, 18 Jul 2019 16:08:48 -0700 Subject: [PATCH 087/119] Fixed more pylint errors --- test/unit/test_base_keyring.py | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/test/unit/test_base_keyring.py b/test/unit/test_base_keyring.py index 025373c28..30594ddd8 100644 --- a/test/unit/test_base_keyring.py +++ b/test/unit/test_base_keyring.py @@ -13,11 +13,13 @@ """Unit tests for base keyring.""" import pytest +import six from aws_encryption_sdk.identifiers import Algorithm -from aws_encryption_sdk.keyring.base import Keyring, EncryptedDataKey +from aws_encryption_sdk.keyring.base import EncryptedDataKey, Keyring from aws_encryption_sdk.keyring.raw_keyring import RawAESKeyring from aws_encryption_sdk.materials_managers import DecryptionMaterials, EncryptionMaterials +from aws_encryption_sdk.structures import MasterKeyInfo try: # Python 3.5.0 and 3.5.1 have incompatible typing modules from typing import Iterable # noqa pylint: disable=unused-import @@ -37,10 +39,28 @@ algorithm=Algorithm.AES_256_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384, verification_key=b"ex_verification_key" ) +_encrypted_data_keys = [ + EncryptedDataKey( + key_provider=MasterKeyInfo(provider_id="Random Raw Keys", key_info=b"5325b043-5843-4629-869c-64794af77ada"), + encrypted_data_key=six.b( + "\n \x8b\xc6\xfd\x91\xc7\xd5\xdc+S\x15n\xd9P\x99n\x1d\xb2\xdd\x15\xeaW" + "\xc3\x13k2\xf6\x02\xd0\x0f\x85\xec\x9e\x12\xa7\x01\x01\x01\x01\x00x" + "\x8b\xc6\xfd\x91\xc7\xd5\xdc+S\x15n\xd9P\x99n\x1d\xb2\xdd\x15\xeaW" + "\xc3\x13k2\xf6\x02\xd0\x0f\x85\xec\x9e\x00\x00\x00~0|\x06\t*\x86H" + "\x86\xf7\r\x01\x07\x06\xa0o0m\x02\x01\x000h\x06\t*\x86H\x86\xf7\r" + "\x01\x07\x010\x1e\x06\t`\x86H\x01e\x03\x04\x01.0\x11\x04\x0c\xc9rP" + "\xa1\x08t6{\xf2\xfd\xf1\xb3\x02\x01\x10\x80;D\xa4\xed`qP~c\x0f\xa0d" + "\xd5\xa2Kj\xc7\xb2\xc6\x1e\xec\xfb\x0fK\xb2*\xd5\t2\x81pR\xee\xd1" + '\x1a\xde<"\x1b\x98\x88\x8b\xf4&\xdaB\x95I\xd2\xff\x10\x13\xfc\x1aX' + "\x08,/\x8b\x8b" + ), + ) +] + def test_keyring_no_encrypt(): class KeyringNoEncrypt(Keyring): - def on_decrypt(self, _decryption_materials, encrypted_data_keys): + def on_decrypt(self, _decryption_materials, _encrypted_data_keys): # type: (DecryptionMaterials, Iterable[EncryptedDataKey]) -> DecryptionMaterials decryption_materials = RawAESKeyring.on_decrypt(decryption_materials=_decryption_materials) return decryption_materials From ede165addb9eb19ea12fc63b007c2fe5eee7cf00 Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Thu, 18 Jul 2019 16:29:49 -0700 Subject: [PATCH 088/119] Removed RawAESKeyring instance --- test/unit/test_base_keyring.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/test/unit/test_base_keyring.py b/test/unit/test_base_keyring.py index 30594ddd8..02ebc0a98 100644 --- a/test/unit/test_base_keyring.py +++ b/test/unit/test_base_keyring.py @@ -17,7 +17,6 @@ from aws_encryption_sdk.identifiers import Algorithm from aws_encryption_sdk.keyring.base import EncryptedDataKey, Keyring -from aws_encryption_sdk.keyring.raw_keyring import RawAESKeyring from aws_encryption_sdk.materials_managers import DecryptionMaterials, EncryptionMaterials from aws_encryption_sdk.structures import MasterKeyInfo @@ -62,8 +61,7 @@ def test_keyring_no_encrypt(): class KeyringNoEncrypt(Keyring): def on_decrypt(self, _decryption_materials, _encrypted_data_keys): # type: (DecryptionMaterials, Iterable[EncryptedDataKey]) -> DecryptionMaterials - decryption_materials = RawAESKeyring.on_decrypt(decryption_materials=_decryption_materials) - return decryption_materials + return _decryption_materials with pytest.raises(TypeError) as exc_info: KeyringNoEncrypt() @@ -74,8 +72,7 @@ def test_keyring_no_decrypt(): class KeyringNoDecrypt(Keyring): def on_encrypt(self, _encryption_materials): # type: (EncryptionMaterials) -> EncryptionMaterials - encryption_materials = RawAESKeyring.on_encrypt(encryption_materials=_encryption_materials) - return encryption_materials + return _encryption_materials with pytest.raises(TypeError) as exc_info: KeyringNoDecrypt() From 39dbfd31528181fd4fd5e5af44eb083ef102ab41 Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Thu, 18 Jul 2019 21:24:06 -0700 Subject: [PATCH 089/119] Changed on_encrypt_helper to generate_data_key and removed on_decrypt_helper. Renamed base API unit test file --- src/aws_encryption_sdk/keyring/raw_keyring.py | 90 ++++++++----------- ...t_base_keyring.py => test_keyring_base.py} | 0 ...aes_keyring.py => test_keyring_raw_aes.py} | 0 3 files changed, 35 insertions(+), 55 deletions(-) rename test/unit/{test_base_keyring.py => test_keyring_base.py} (100%) rename test/unit/{test_raw_aes_keyring.py => test_keyring_raw_aes.py} (100%) diff --git a/src/aws_encryption_sdk/keyring/raw_keyring.py b/src/aws_encryption_sdk/keyring/raw_keyring.py index f50d96618..ddd036581 100644 --- a/src/aws_encryption_sdk/keyring/raw_keyring.py +++ b/src/aws_encryption_sdk/keyring/raw_keyring.py @@ -20,7 +20,7 @@ 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.exceptions import EncryptKeyError, 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 @@ -54,7 +54,7 @@ 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 ): @@ -67,57 +67,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: + 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) + # 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) - - 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 +126,12 @@ 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 # Encrypt data key encrypted_wrapped_key = self._wrapping_key_structure.encrypt( @@ -209,8 +180,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: @@ -276,9 +250,12 @@ 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 if isinstance(self._wrapping_key, RSAPublicKey): # Encrypt data key @@ -323,8 +300,11 @@ def on_decrypt(self, decryption_materials, encrypted_data_keys): # 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( diff --git a/test/unit/test_base_keyring.py b/test/unit/test_keyring_base.py similarity index 100% rename from test/unit/test_base_keyring.py rename to test/unit/test_keyring_base.py diff --git a/test/unit/test_raw_aes_keyring.py b/test/unit/test_keyring_raw_aes.py similarity index 100% rename from test/unit/test_raw_aes_keyring.py rename to test/unit/test_keyring_raw_aes.py From 61e8fe5fc2a7d1ee0d892b7e387e4c7a780b6c37 Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Thu, 18 Jul 2019 21:27:15 -0700 Subject: [PATCH 090/119] Changed docstring for generate_data_key --- src/aws_encryption_sdk/keyring/raw_keyring.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/aws_encryption_sdk/keyring/raw_keyring.py b/src/aws_encryption_sdk/keyring/raw_keyring.py index ddd036581..3678d1401 100644 --- a/src/aws_encryption_sdk/keyring/raw_keyring.py +++ b/src/aws_encryption_sdk/keyring/raw_keyring.py @@ -59,7 +59,7 @@ def generate_data_key( 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 From e61f4a2fcf2babddd2df9368066022b3038c990c Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Thu, 18 Jul 2019 22:17:41 -0700 Subject: [PATCH 091/119] Changed decryption_materials.data_key to decryption_materials.data_encryption_key and fixed pylint errors --- src/aws_encryption_sdk/keyring/raw_keyring.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/aws_encryption_sdk/keyring/raw_keyring.py b/src/aws_encryption_sdk/keyring/raw_keyring.py index 3678d1401..8e113dfde 100644 --- a/src/aws_encryption_sdk/keyring/raw_keyring.py +++ b/src/aws_encryption_sdk/keyring/raw_keyring.py @@ -20,7 +20,7 @@ from cryptography.hazmat.primitives.asymmetric.padding import OAEP from cryptography.hazmat.primitives.asymmetric.rsa import RSAPrivateKey, RSAPublicKey -from aws_encryption_sdk.exceptions import EncryptKeyError, GenerateKeyError +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 @@ -211,11 +211,15 @@ 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 + @property + def key_provider(self): + return self._key_provider + @attr.s class RawRSAKeyring(Keyring): @@ -329,5 +333,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 From 89f8a2c09dfdfac36c5a1e472fc23b318fb72f4a Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Thu, 18 Jul 2019 22:30:45 -0700 Subject: [PATCH 092/119] Fixed pylint errors --- src/aws_encryption_sdk/keyring/raw_keyring.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/aws_encryption_sdk/keyring/raw_keyring.py b/src/aws_encryption_sdk/keyring/raw_keyring.py index 8e113dfde..ba0566c0a 100644 --- a/src/aws_encryption_sdk/keyring/raw_keyring.py +++ b/src/aws_encryption_sdk/keyring/raw_keyring.py @@ -216,10 +216,6 @@ def on_decrypt(self, decryption_materials, encrypted_data_keys): return decryption_materials - @property - def key_provider(self): - return self._key_provider - @attr.s class RawRSAKeyring(Keyring): From fbf351f4e2fd1ab3ae6c3f136e14c50707fced1f Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Sat, 20 Jul 2019 01:24:12 -0700 Subject: [PATCH 093/119] Changed raw keyrings to have class methods for PEM and DER encoded keys --- src/aws_encryption_sdk/keyring/raw_keyring.py | 103 ++++++++--- test/functional/test_f_raw_rsa.py | 60 ++---- test/unit/test_keyring_raw_aes.py | 174 ++++++++++++++++++ 3 files changed, 267 insertions(+), 70 deletions(-) diff --git a/src/aws_encryption_sdk/keyring/raw_keyring.py b/src/aws_encryption_sdk/keyring/raw_keyring.py index ba0566c0a..05f3f76ed 100644 --- a/src/aws_encryption_sdk/keyring/raw_keyring.py +++ b/src/aws_encryption_sdk/keyring/raw_keyring.py @@ -17,8 +17,9 @@ 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 GenerateKeyError from aws_encryption_sdk.identifiers import EncryptionKeyType, KeyringTraceFlag, WrappingAlgorithm @@ -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 @@ -233,9 +234,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 = 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 RawRSAKeyring( + key_namespace=key_namespace, + key_name=key_name, + wrapping_key=loaded_wrapping_key, + wrapping_algorithm=_wrapping_algorithm, + ) + + @classmethod + def fromDEREncoding(cls): + 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 RawRSAKeyring( + 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.""" @@ -256,32 +299,44 @@ def on_encrypt(self, encryption_materials): ) else: plaintext_data_key = encryption_materials.data_encryption_key.data_key - if isinstance(self._wrapping_key, RSAPublicKey): + 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 @@ -296,7 +351,7 @@ 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: @@ -308,7 +363,7 @@ def on_decrypt(self, decryption_materials, encrypted_data_keys): ) 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() diff --git a/test/functional/test_f_raw_rsa.py b/test/functional/test_f_raw_rsa.py index 75f9466c8..3ebb5510f 100644 --- a/test/functional/test_f_raw_rsa.py +++ b/test/functional/test_f_raw_rsa.py @@ -14,7 +14,7 @@ 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, KeyringTraceFlag, WrappingAlgorithm from aws_encryption_sdk.keyring.raw_keyring import RawRSAKeyring @@ -26,38 +26,8 @@ _ENCRYPTION_CONTEXT = {"encryption": "context", "values": "here"} _PROVIDER_ID = "Random Raw Keys" _KEY_ID = b"5325b043-5843-4629-869c-64794af77ada" -_WRAPPING_KEY = serialization.load_pem_private_key( - data=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", - password=None, - backend=default_backend(), -) _SIGNING_KEY = b"aws-crypto-public-key" +_WRAPPING_ALGORITHM = WrappingAlgorithm.RSA_OAEP_SHA256_MGF1 _ENCRYPTION_MATERIALS = [ EncryptionMaterials( @@ -107,22 +77,20 @@ ), ] - -@pytest.mark.parametrize("encryption_materials_samples", _ENCRYPTION_MATERIALS) -def test_raw_rsa_encryption_decryption(encryption_materials_samples): - - # Initializing attributes - key_namespace = _PROVIDER_ID - key_name = _KEY_ID - _wrapping_algorithm = WrappingAlgorithm.RSA_OAEP_SHA256_MGF1 - - # Creating an instance of a raw AES keyring - fake_raw_rsa_keyring = RawRSAKeyring( +_RAW_RSA_KEYRINGS = [ + RawRSAKeyring( key_namespace=key_namespace, key_name=key_name, - wrapping_key=_WRAPPING_KEY, - wrapping_algorithm=_wrapping_algorithm, - ) + wrapping_key=rsa.generate_private_key(public_exponent=65537, key_size=2048, backend=default_backend()), + wrapping_algorithm=_WRAPPING_ALGORITHM, + ), + RawRSAKeyring.fromPEMEncoding() +] + + +@pytest.mark.parametrize("encryption_materials_samples", _ENCRYPTION_MATERIALS) +@pytest.mark.parametrize("fake_raw_rsa_keyring", _RAW_RSA_KEYRINGS) +def test_raw_rsa_encryption_decryption(encryption_materials_samples, fake_raw_rsa_keyring): # Call on_encrypt function for the keyring encryption_materials = fake_raw_rsa_keyring.on_encrypt(encryption_materials=encryption_materials_samples) diff --git a/test/unit/test_keyring_raw_aes.py b/test/unit/test_keyring_raw_aes.py index e69de29bb..b202f805c 100644 --- a/test/unit/test_keyring_raw_aes.py +++ b/test/unit/test_keyring_raw_aes.py @@ -0,0 +1,174 @@ +# 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 Raw AES keyring.""" + +import pytest +import six +from mock import MagicMock, patch, sentinel + +from aws_encryption_sdk.exceptions import GenerateKeyError +from aws_encryption_sdk.identifiers import Algorithm, KeyringTraceFlag, WrappingAlgorithm +from aws_encryption_sdk.keyring.base import EncryptedDataKey, Keyring +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 + +from .test_values import VALUES + +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" +_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" +) +_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}, + ) + ], +) + + +class TestRawAESKeyring(object): + @pytest.fixture(autouse=True) + def apply_fixtures(self): + self.mock_encrypted_data_key = EncryptedDataKey( + key_provider=MasterKeyInfo(provider_id=_PROVIDER_ID, key_info=_KEY_ID), + encrypted_data_key=VALUES["encrypted_data_key"], + ) + self.mock_encryption_materials = MagicMock() + self.mock_encryption_materials.__class__ = EncryptionMaterials + + def test_parent(self): + assert issubclass(RawAESKeyring, Keyring) + + # def test_initialization(self): + # test = RawAESKeyring( + # key_namespace=_PROVIDER_ID, + # key_name=_KEY_ID, + # wrapping_algorithm=WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING, + # wrapping_key=_WRAPPING_KEY, + # ) + # assert test.key_provider() == self.mock_encrypted_data_key.key_provider + + @patch("aws_encryption_sdk.keyring.raw_keyring.generate_data_key") + def test_data_encryption_key_provided(self, mock_generate_data_key): + mock_generate_data_key.return_value = _DATA_KEY + test_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, + ) + + test = test_raw_aes_keyring.on_encrypt(encryption_materials=_ENCRYPTION_MATERIALS_WITH_DATA_KEY) + # Check if keyring is generated + assert not mock_generate_data_key.called + + # Check if data encryption key is encrypted + assert test.encrypted_data_keys is not None + + def test_data_encryption_key_generated(self): + test_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, + ) + test = test_raw_aes_keyring.on_encrypt(encryption_materials=_ENCRYPTION_MATERIALS_WITHOUT_DATA_KEY) + + # Check if key is generated + if not test.data_encryption_key: + # Check if error thrown if data key is not generated + assert pytest.raises(GenerateKeyError, "Unable to generate data encryption key.") + else: + # Check if data key is generated + assert test.data_encryption_key and test.data_encryption_key is not None + assert test.encrypted_data_keys and test.encrypted_data_keys is not None + + @patch("aws_encryption_sdk.keyring.raw_keyring.generate_data_key") + def test_encrypted_data_key_provided(self, mock_generate_data_key): + mock_generate_data_key.return_value = _DATA_KEY + test_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, + ) + test = test_raw_aes_keyring.on_encrypt(encryption_materials=_ENCRYPTION_MATERIALS_WITH_ENCRYPTED_DATA_KEY) + + # Check if generate_data_key is called + assert not mock_generate_data_key.called + # + # Check if encrypt is called + assert len(test.encrypted_data_keys) == len(_ENCRYPTION_MATERIALS_WITH_ENCRYPTED_DATA_KEY.encrypted_data_keys) + + # @patch("aws_encryption_sdk.key_providers.raw.os.urandom") + # def test_data_key_not_generated(self, mock_os_urandom): + # mock_os_urandom.return_value = None + # test_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, + # ) + # test = test_raw_aes_keyring.on_encrypt(encryption_materials=_ENCRYPTION_MATERIALS_WITHOUT_DATA_KEY) + # assert pytest.raises(GenerateKeyError, "Unable to generate data encryption key.") From fb8b7b8f1ee1407c81cfdde0d4d172a26d3e33db Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Mon, 22 Jul 2019 13:17:55 -0700 Subject: [PATCH 094/119] Unit tests for raw keyrings --- examples/src/sample_aes.py | 78 ++++++ src/aws_encryption_sdk/keyring/raw_keyring.py | 52 ++-- ...f_raw_aes.py => test_f_keyring_raw_aes.py} | 11 +- ...f_raw_rsa.py => test_f_keyring_raw_rsa.py} | 62 ++++- test/unit/test_keyring_raw_aes.py | 73 +++++- test/unit/test_keyring_raw_rsa.py | 244 ++++++++++++++++++ test/unit/test_utils.py | 27 ++ 7 files changed, 514 insertions(+), 33 deletions(-) create mode 100644 examples/src/sample_aes.py rename test/functional/{test_f_raw_aes.py => test_f_keyring_raw_aes.py} (93%) rename test/functional/{test_f_raw_rsa.py => test_f_keyring_raw_rsa.py} (53%) create mode 100644 test/unit/test_keyring_raw_rsa.py diff --git a/examples/src/sample_aes.py b/examples/src/sample_aes.py new file mode 100644 index 000000000..d9d37f37a --- /dev/null +++ b/examples/src/sample_aes.py @@ -0,0 +1,78 @@ +# 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 Algorithm, WrappingAlgorithm +from aws_encryption_sdk.keyring.raw_keyring import RawAESKeyring +from aws_encryption_sdk.materials_managers import DecryptionMaterials, EncryptionMaterials + +pytestmark = [pytest.mark.functional, pytest.mark.local] + +_ENCRYPTION_CONTEXT = {"key_a": "value_a", "key_b": "value_b", "key_c": "value_c"} +_PROVIDER_ID = "Random Raw Keys" +_KEY_ID = b"5325b043-5843-4629-869c-64794af77ada" +_WRAPPING_KEY = b"12345678901234567890123456789012" +_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, + ) + + +def sample_aes_encryption_decryption(): + + # Initializing attributes + key_namespace = _PROVIDER_ID + key_name = _KEY_ID + _wrapping_algorithm = WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING + + # Creating an instance of a raw AES keyring + fake_raw_aes_keyring = RawAESKeyring( + key_namespace=key_namespace, + key_name=key_name, + wrapping_key=_WRAPPING_KEY, + wrapping_algorithm=_wrapping_algorithm, + ) + + # Call on_encrypt function for the keyring + encryption_materials = fake_raw_aes_keyring.on_encrypt(encryption_materials=_ENCRYPTION_MATERIALS) + + print("PLAINTEXT DATA KEY") + print(encryption_materials.data_encryption_key.data_key) + + print("ENCRYPTED DATA KEY") + print(encryption_materials.encrypted_data_keys) + + # 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 = fake_raw_aes_keyring.on_decrypt( + decryption_materials=decryption_materials, encrypted_data_keys=encryption_materials.encrypted_data_keys + ) + + print("DECRYPTED DATA KEY") + print(decryption_materials.data_encryption_key.data_key) + + if decryption_materials.data_encryption_key: + # Check if the data keys match + assert encryption_materials.data_encryption_key == decryption_materials.data_encryption_key + + +sample_aes_encryption_decryption() diff --git a/src/aws_encryption_sdk/keyring/raw_keyring.py b/src/aws_encryption_sdk/keyring/raw_keyring.py index 05f3f76ed..3cfdf9c21 100644 --- a/src/aws_encryption_sdk/keyring/raw_keyring.py +++ b/src/aws_encryption_sdk/keyring/raw_keyring.py @@ -72,7 +72,7 @@ def 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: + if not plaintext_data_key or plaintext_data_key is None: raise GenerateKeyError("Unable to generate data encryption key.") # Create a keyring trace @@ -134,6 +134,10 @@ def on_encrypt(self, encryption_materials): 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( plaintext_data_key=plaintext_data_key, encryption_context=encryption_materials.encryption_context @@ -195,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 @@ -240,43 +244,43 @@ class RawRSAKeyring(Keyring): _wrapping_algorithm = attr.ib(repr=False, validator=attr.validators.instance_of(WrappingAlgorithm)) @classmethod - def fromPEMEncoding(cls): - 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: + 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() + data=encoded_key, password=password, backend=default_backend() ) else: - loaded_wrapping_key = serialization.load_pem_public_key(data=_encoded_key, backend=default_backend()) - return RawRSAKeyring( + 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, + wrapping_algorithm=wrapping_algorithm, ) @classmethod - def fromDEREncoding(cls): - 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: + 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() + data=encoded_key, password=password, backend=default_backend() ) else: - loaded_wrapping_key = serialization.load_der_public_key(data=_encoded_key, backend=default_backend()) - return RawRSAKeyring( + 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, + wrapping_algorithm=wrapping_algorithm, ) def __attrs_post_init__(self): diff --git a/test/functional/test_f_raw_aes.py b/test/functional/test_f_keyring_raw_aes.py similarity index 93% rename from test/functional/test_f_raw_aes.py rename to test/functional/test_f_keyring_raw_aes.py index df295208b..18c0638bc 100644 --- a/test/functional/test_f_raw_aes.py +++ b/test/functional/test_f_keyring_raw_aes.py @@ -24,7 +24,7 @@ _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 = b"12345678901234567890123456789012" _SIGNING_KEY = b"aws-crypto-public-key" _ENCRYPTION_MATERIALS = [ @@ -95,6 +95,9 @@ def test_raw_aes_encryption_decryption(encryption_materials_samples): # Call on_encrypt function for the keyring encryption_materials = fake_raw_aes_keyring.on_encrypt(encryption_materials=encryption_materials_samples) + print("PLAINTEXT DATA KEY") + print(encryption_materials.data_encryption_key) + # Generate decryption materials decryption_materials = DecryptionMaterials( algorithm=Algorithm.AES_256_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384, verification_key=b"ex_verification_key" @@ -105,6 +108,6 @@ def test_raw_aes_encryption_decryption(encryption_materials_samples): 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 diff --git a/test/functional/test_f_raw_rsa.py b/test/functional/test_f_keyring_raw_rsa.py similarity index 53% rename from test/functional/test_f_raw_rsa.py rename to test/functional/test_f_keyring_raw_rsa.py index 3ebb5510f..7b39e01e0 100644 --- a/test/functional/test_f_raw_rsa.py +++ b/test/functional/test_f_keyring_raw_rsa.py @@ -79,12 +79,68 @@ _RAW_RSA_KEYRINGS = [ RawRSAKeyring( - key_namespace=key_namespace, - key_name=key_name, + key_namespace=_PROVIDER_ID, + key_name=_KEY_ID, wrapping_key=rsa.generate_private_key(public_exponent=65537, key_size=2048, backend=default_backend()), wrapping_algorithm=_WRAPPING_ALGORITHM, ), - RawRSAKeyring.fromPEMEncoding() + # RawRSAKeyring.fromPEMEncoding( + # key_namespace=_PROVIDER_ID, + # key_name=_KEY_ID, + # encoded_key=( + # 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-----" + # ), + # password=None, + # wrapping_algorithm=_WRAPPING_ALGORITHM, + # ), + # RawRSAKeyring.fromDEREncoding( + # key_namespace=_PROVIDER_ID, + # key_name=_KEY_ID, + # encoded_key=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", + # password=None, + # wrapping_algorithm=_WRAPPING_ALGORITHM, + # ) ] diff --git a/test/unit/test_keyring_raw_aes.py b/test/unit/test_keyring_raw_aes.py index b202f805c..85b483b10 100644 --- a/test/unit/test_keyring_raw_aes.py +++ b/test/unit/test_keyring_raw_aes.py @@ -19,11 +19,12 @@ from aws_encryption_sdk.exceptions import GenerateKeyError from aws_encryption_sdk.identifiers import Algorithm, KeyringTraceFlag, WrappingAlgorithm from aws_encryption_sdk.keyring.base import EncryptedDataKey, Keyring -from aws_encryption_sdk.keyring.raw_keyring import RawAESKeyring +from aws_encryption_sdk.keyring.raw_keyring import RawAESKeyring, generate_data_key from aws_encryption_sdk.materials_managers import DecryptionMaterials, EncryptionMaterials from aws_encryption_sdk.structures import KeyringTrace, MasterKeyInfo, RawDataKey from .test_values import VALUES +# from .test_utils import NullRawAESKeyring try: # Python 3.5.0 and 3.5.1 have incompatible typing modules from typing import Iterable # noqa pylint: disable=unused-import @@ -86,6 +87,24 @@ ], ) +_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", +) + class TestRawAESKeyring(object): @pytest.fixture(autouse=True) @@ -107,7 +126,7 @@ def test_parent(self): # wrapping_algorithm=WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING, # wrapping_key=_WRAPPING_KEY, # ) - # assert test.key_provider() == self.mock_encrypted_data_key.key_provider + # assert test.__getattribute__(key_provider) == self.mock_encrypted_data_key.key_provider @patch("aws_encryption_sdk.keyring.raw_keyring.generate_data_key") def test_data_encryption_key_provided(self, mock_generate_data_key): @@ -172,3 +191,53 @@ def test_encrypted_data_key_provided(self, mock_generate_data_key): # ) # test = test_raw_aes_keyring.on_encrypt(encryption_materials=_ENCRYPTION_MATERIALS_WITHOUT_DATA_KEY) # assert pytest.raises(GenerateKeyError, "Unable to generate data encryption key.") + + @patch("aws_encryption_sdk.keyring.raw_keyring.generate_data_key") + def test_data_key_not_generated(self, mock_generate_data_key): + mock_generate_data_key.return_value = None + test_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, + ) + test = test_raw_aes_keyring.on_encrypt(encryption_materials=_ENCRYPTION_MATERIALS_WITHOUT_DATA_KEY) + assert pytest.raises(GenerateKeyError) + + @patch("aws_encryption_sdk.internal.crypto.wrapping_keys.WrappingKey.decrypt") + def test_decrypt_when_data_key_provided(self, mock_decrypt): + mock_decrypt.return_value = _DATA_KEY + test_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, + ) + test = test_raw_aes_keyring.on_decrypt(decryption_materials=_DECRYPTION_MATERIALS_WITH_DATA_KEY, + encrypted_data_keys=[self.mock_encrypted_data_key]) + assert not mock_decrypt.called + + # @patch("aws_encryption_sdk.internal.crypto.wrapping_keys.WrappingKey.decrypt") + # def test_decrypt_when_data_key_not_provided(self, mock_decrypt): + # mock_decrypt.return_value = _DATA_KEY + # test_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, + # ) + # + # test = test_raw_aes_keyring.on_decrypt(decryption_materials=_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\x7f.}\x87\x16,\x11n#\xc8p" + # b"\xdb\xbf\x94\x86*Q\x06\xd2\xf5\xdah\x08\xa4p\x81\xf7\xf4G\ + # x07FzE\xde", + # ) + # ] + # ) + # assert mock_decrypt.called diff --git a/test/unit/test_keyring_raw_rsa.py b/test/unit/test_keyring_raw_rsa.py new file mode 100644 index 000000000..532cfc01e --- /dev/null +++ b/test/unit/test_keyring_raw_rsa.py @@ -0,0 +1,244 @@ +# 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 Raw AES keyring.""" + +import pytest +from cryptography.hazmat.backends import default_backend +from cryptography.hazmat.primitives.asymmetric import rsa +from mock import MagicMock, patch, sentinel + +from aws_encryption_sdk.exceptions import GenerateKeyError +from aws_encryption_sdk.identifiers import Algorithm, KeyringTraceFlag, WrappingAlgorithm +from aws_encryption_sdk.keyring.base import EncryptedDataKey, Keyring +from aws_encryption_sdk.keyring.raw_keyring import RawRSAKeyring, generate_data_key +from aws_encryption_sdk.materials_managers import DecryptionMaterials, EncryptionMaterials +from aws_encryption_sdk.structures import KeyringTrace, MasterKeyInfo, RawDataKey + +from .test_values import VALUES +# from .test_utils import NullRawAESKeyring + +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 = rsa.generate_private_key(public_exponent=65537, key_size=2048, backend=default_backend()) +_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" +) +_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", +) + + +class TestRawRSAKeyring(object): + @pytest.fixture(autouse=True) + def apply_fixtures(self): + self.mock_encrypted_data_key = EncryptedDataKey( + key_provider=MasterKeyInfo(provider_id=_PROVIDER_ID, key_info=_KEY_ID), + encrypted_data_key=VALUES["encrypted_data_key"], + ) + self.mock_encryption_materials = MagicMock() + self.mock_encryption_materials.__class__ = EncryptionMaterials + + def test_parent(self): + assert issubclass(RawRSAKeyring, Keyring) + + # def test_initialization(self): + # test = RawAESKeyring( + # key_namespace=_PROVIDER_ID, + # key_name=_KEY_ID, + # wrapping_algorithm=WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING, + # wrapping_key=_WRAPPING_KEY, + # ) + # assert test.__getattribute__(key_provider) == self.mock_encrypted_data_key.key_provider + + @patch("aws_encryption_sdk.keyring.raw_keyring.generate_data_key") + def test_data_encryption_key_provided(self, mock_generate_data_key): + mock_generate_data_key.return_value = _DATA_KEY + test_raw_rsa_keyring = RawRSAKeyring( + key_namespace=_PROVIDER_ID, + key_name=_KEY_ID, + wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, + wrapping_key=_WRAPPING_KEY, + ) + + test = test_raw_rsa_keyring.on_encrypt(encryption_materials=_ENCRYPTION_MATERIALS_WITH_DATA_KEY) + # Check if keyring is generated + assert not mock_generate_data_key.called + + # Check if data encryption key is encrypted + assert test.encrypted_data_keys is not None + + def test_data_encryption_key_generated(self): + test_raw_rsa_keyring = RawRSAKeyring( + key_namespace=_PROVIDER_ID, + key_name=_KEY_ID, + wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, + wrapping_key=_WRAPPING_KEY, + ) + test = test_raw_rsa_keyring.on_encrypt(encryption_materials=_ENCRYPTION_MATERIALS_WITHOUT_DATA_KEY) + + # Check if key is generated + if not test.data_encryption_key: + # Check if error thrown if data key is not generated + assert pytest.raises(GenerateKeyError, "Unable to generate data encryption key.") + else: + # Check if data key is generated + assert test.data_encryption_key and test.data_encryption_key is not None + assert test.encrypted_data_keys and test.encrypted_data_keys is not None + + @patch("aws_encryption_sdk.keyring.raw_keyring.generate_data_key") + def test_encrypted_data_key_provided(self, mock_generate_data_key): + mock_generate_data_key.return_value = _DATA_KEY + test_raw_rsa_keyring = RawRSAKeyring( + key_namespace=_PROVIDER_ID, + key_name=_KEY_ID, + wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, + wrapping_key=_WRAPPING_KEY, + ) + test = test_raw_rsa_keyring.on_encrypt(encryption_materials=_ENCRYPTION_MATERIALS_WITH_ENCRYPTED_DATA_KEY) + + # Check if generate_data_key is called + assert not mock_generate_data_key.called + # + # Check if encrypt is called + assert len(test.encrypted_data_keys) == len(_ENCRYPTION_MATERIALS_WITH_ENCRYPTED_DATA_KEY.encrypted_data_keys) + + # @patch("aws_encryption_sdk.key_providers.raw.os.urandom") + # def test_data_key_not_generated(self, mock_os_urandom): + # mock_os_urandom.return_value = None + # test_raw_aes_keyring = RawAESKeyring( + # key_namespace=_PROVIDER_ID, + # key_name=_KEY_ID, + # wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, + # wrapping_key=_WRAPPING_KEY, + # ) + # test = test_raw_aes_keyring.on_encrypt(encryption_materials=_ENCRYPTION_MATERIALS_WITHOUT_DATA_KEY) + # assert pytest.raises(GenerateKeyError, "Unable to generate data encryption key.") + + @patch("aws_encryption_sdk.keyring.raw_keyring.generate_data_key") + def test_data_key_not_generated(self, mock_generate_data_key): + mock_generate_data_key.return_value = None + test_raw_rsa_keyring = RawRSAKeyring( + key_namespace=_PROVIDER_ID, + key_name=_KEY_ID, + wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, + wrapping_key=_WRAPPING_KEY, + ) + test = test_raw_rsa_keyring.on_encrypt(encryption_materials=_ENCRYPTION_MATERIALS_WITHOUT_DATA_KEY) + assert pytest.raises(GenerateKeyError) + + @patch("aws_encryption_sdk.internal.crypto.wrapping_keys.WrappingKey.decrypt") + def test_decrypt_when_data_key_provided(self, mock_decrypt): + mock_decrypt.return_value = _DATA_KEY + test_raw_rsa_keyring = RawRSAKeyring( + key_namespace=_PROVIDER_ID, + key_name=_KEY_ID, + wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, + wrapping_key=_WRAPPING_KEY, + ) + test = test_raw_rsa_keyring.on_decrypt(decryption_materials=_DECRYPTION_MATERIALS_WITH_DATA_KEY, + encrypted_data_keys=[self.mock_encrypted_data_key]) + assert not mock_decrypt.called + + # @patch("aws_encryption_sdk.internal.crypto.wrapping_keys.WrappingKey.decrypt") + # def test_decrypt_when_data_key_not_provided(self, mock_decrypt): + # mock_decrypt.return_value = _DATA_KEY + # test_raw_aes_keyring = RawAESKeyring( + # key_namespace=_PROVIDER_ID, + # key_name=_KEY_ID, + # wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, + # wrapping_key=_WRAPPING_KEY, + # ) + # + # test = test_raw_aes_keyring.on_decrypt(decryption_materials=_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\x7f.}\x87\x16,\x11n#\xc8p" + # b"\xdb\xbf\x94\x86*Q\x06\xd2\xf5\xdah\x08\xa4p\x81\xf7\xf4G\ + # x07FzE\xde", + # ) + # ] + # ) + # assert mock_decrypt.called diff --git a/test/unit/test_utils.py b/test/unit/test_utils.py index b1374a09d..0da12a869 100644 --- a/test/unit/test_utils.py +++ b/test/unit/test_utils.py @@ -21,11 +21,19 @@ 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.materials_managers import EncryptionMaterials, DecryptionMaterials, EncryptedDataKey from aws_encryption_sdk.structures import DataKey, EncryptedDataKey, MasterKeyInfo, RawDataKey +from aws_encryption_sdk.keyring.raw_keyring import RawRSAKeyring, RawAESKeyring from .test_values import VALUES from .unit_test_utils import assert_prepped_stream_identity +try: # Python 3.5.0 and 3.5.1 have incompatible typing modules + 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 + pytestmark = [pytest.mark.unit, pytest.mark.local] @@ -42,6 +50,24 @@ def test_prep_stream_data_wrap(source): assert_prepped_stream_identity(test, io.BytesIO) +class NullRawRSAKeyring(RawRSAKeyring): + 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 NullRawAESKeyring(RawAESKeyring): + def on_encrypt(self): + return + + def on_decrypt(self): + return + + class TestUtils(object): @pytest.fixture(autouse=True) def apply_fixtures(self): @@ -265,3 +291,4 @@ def test_source_data_key_length_check_invalid(self): source_data_key=mock_data_key, algorithm=mock_algorithm ) excinfo.match("Invalid Source Data Key length 4 for algorithm required: 5") + From 41dd1408e6b7c741a5fb1ee4567d2b915a2310d9 Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Mon, 22 Jul 2019 14:30:35 -0700 Subject: [PATCH 095/119] Changes for PEM encoding --- test/functional/test_f_keyring_raw_rsa.py | 53 +++++++++++------------ test/unit/test_values.py | 48 ++++++++++++++++++++ 2 files changed, 74 insertions(+), 27 deletions(-) diff --git a/test/functional/test_f_keyring_raw_rsa.py b/test/functional/test_f_keyring_raw_rsa.py index 7b39e01e0..0ce72b23c 100644 --- a/test/functional/test_f_keyring_raw_rsa.py +++ b/test/functional/test_f_keyring_raw_rsa.py @@ -28,6 +28,22 @@ _KEY_ID = b"5325b043-5843-4629-869c-64794af77ada" _SIGNING_KEY = b"aws-crypto-public-key" _WRAPPING_ALGORITHM = WrappingAlgorithm.RSA_OAEP_SHA256_MGF1 +_PRIVATE_KEY = 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-----" _ENCRYPTION_MATERIALS = [ EncryptionMaterials( @@ -84,30 +100,13 @@ wrapping_key=rsa.generate_private_key(public_exponent=65537, key_size=2048, backend=default_backend()), wrapping_algorithm=_WRAPPING_ALGORITHM, ), - # RawRSAKeyring.fromPEMEncoding( - # key_namespace=_PROVIDER_ID, - # key_name=_KEY_ID, - # encoded_key=( - # 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-----" - # ), - # password=None, - # wrapping_algorithm=_WRAPPING_ALGORITHM, - # ), + RawRSAKeyring.fromPEMEncoding( + key_namespace=_PROVIDER_ID, + key_name=_KEY_ID, + encoded_key=_PRIVATE_KEY, + password=None, + wrapping_algorithm=_WRAPPING_ALGORITHM, + ), # RawRSAKeyring.fromDEREncoding( # key_namespace=_PROVIDER_ID, # key_name=_KEY_ID, @@ -161,6 +160,6 @@ def test_raw_rsa_encryption_decryption(encryption_materials_samples, fake_raw_rs 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 diff --git a/test/unit/test_values.py b/test/unit/test_values.py index 26eff1341..acd09db2a 100644 --- a/test/unit/test_values.py +++ b/test/unit/test_values.py @@ -187,6 +187,54 @@ def array_byte(source): "\xff\x8fn\x95\xf0\xf0E\x91Uj\xb0E3=\x0e\x1a\xf1'4\xf6" ), "signature_len": b"\x00h", + "private_rsa_key_bytes": [ + ( + 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"-----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" + ) + ] } VALUES["updated_encryption_context"] = copy.deepcopy(VALUES["encryption_context"]) VALUES["updated_encryption_context"]["aws-crypto-public-key"] = VALUES["encoded_curve_point"] From 9fa50cf9652ab9dbf3254665f7e7c0f8889b15a4 Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Tue, 23 Jul 2019 14:37:16 -0700 Subject: [PATCH 096/119] Made suggested changes to raw keyrings --- examples/src/sample_aes.py | 8 +- src/aws_encryption_sdk/keyring/raw_keyring.py | 407 ++++++++++-------- test/functional/test_f_keyring_raw_aes.py | 5 +- test/functional/test_f_keyring_raw_rsa.py | 55 +-- test/unit/test_keyring_raw_aes.py | 20 +- test/unit/test_keyring_raw_rsa.py | 30 +- test/unit/test_utils.py | 5 +- test/unit/test_values.py | 7 +- 8 files changed, 300 insertions(+), 237 deletions(-) diff --git a/examples/src/sample_aes.py b/examples/src/sample_aes.py index d9d37f37a..a78cac354 100644 --- a/examples/src/sample_aes.py +++ b/examples/src/sample_aes.py @@ -27,10 +27,10 @@ _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, - ) + algorithm=Algorithm.AES_256_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384, + encryption_context=_ENCRYPTION_CONTEXT, + signing_key=_SIGNING_KEY, +) def sample_aes_encryption_decryption(): diff --git a/src/aws_encryption_sdk/keyring/raw_keyring.py b/src/aws_encryption_sdk/keyring/raw_keyring.py index 3cfdf9c21..15d196a71 100644 --- a/src/aws_encryption_sdk/keyring/raw_keyring.py +++ b/src/aws_encryption_sdk/keyring/raw_keyring.py @@ -17,6 +17,8 @@ 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,34 +34,19 @@ 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( encryption_materials, # type: EncryptionMaterials key_provider, # type: MasterKeyInfo ): - # type: (...) -> bytes + # type: (...) -> bool """Generates plaintext data key for the keyring. :param encryption_materials: Encryption materials for the keyring to modify. @@ -84,7 +71,7 @@ def generate_data_key( # Add generated data key to encryption_materials encryption_materials.add_data_encryption_key(data_encryption_key, keyring_trace) - return plaintext_data_key + return True @attr.s @@ -98,10 +85,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 +118,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 +131,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: + 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 +183,58 @@ 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: + print("Data key already present") return decryption_materials # Decrypt data key expected_key_info_len = len(self._key_info_prefix) + self._wrapping_algorithm.algorithm.iv_len + print("expected_key_info_len=", expected_key_info_len) + count = 0 for key in encrypted_data_keys: + count += 1 + print("Key no = ", count) + 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, + print("If condition did not match") + 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) + continue + + # Create a keyring trace + keyring_trace = KeyringTrace( + wrapping_key=self._key_provider, flags={KeyringTraceFlag.WRAPPING_KEY_DECRYPTED_DATA_KEY} + ) + + print("Keyring trace made") + + # 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) + print("Done") return decryption_materials @@ -228,65 +245,111 @@ 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()) + if public_encoded_key is None and private_encoded_key is None: + raise TypeError("At least one of public key or private key must be provided.") + 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() + ) + if public_encoded_key is None and private_encoded_key is None: + raise TypeError("At least one of public key or private key must be provided.") + 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): # type: () -> None """Prepares initial values not handled by attrs.""" self._key_provider = MasterKeyInfo(provider_id=self.key_namespace, key_info=self.key_name) + 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 @@ -297,31 +360,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: + 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 +396,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 +416,38 @@ 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: + return decryption_materials + if key.key_provider != self._key_provider: + 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_keyring_raw_aes.py b/test/functional/test_f_keyring_raw_aes.py index 18c0638bc..8b05ba914 100644 --- a/test/functional/test_f_keyring_raw_aes.py +++ b/test/functional/test_f_keyring_raw_aes.py @@ -108,6 +108,5 @@ def test_raw_aes_encryption_decryption(encryption_materials_samples): 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.data_key == decryption_materials.data_encryption_key.data_key diff --git a/test/functional/test_f_keyring_raw_rsa.py b/test/functional/test_f_keyring_raw_rsa.py index 0ce72b23c..bfaf34a72 100644 --- a/test/functional/test_f_keyring_raw_rsa.py +++ b/test/functional/test_f_keyring_raw_rsa.py @@ -28,22 +28,24 @@ _KEY_ID = b"5325b043-5843-4629-869c-64794af77ada" _SIGNING_KEY = b"aws-crypto-public-key" _WRAPPING_ALGORITHM = WrappingAlgorithm.RSA_OAEP_SHA256_MGF1 -_PRIVATE_KEY = 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-----" +_PRIVATE_KEY = ( + 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-----" +) _ENCRYPTION_MATERIALS = [ EncryptionMaterials( @@ -97,16 +99,16 @@ RawRSAKeyring( key_namespace=_PROVIDER_ID, key_name=_KEY_ID, - wrapping_key=rsa.generate_private_key(public_exponent=65537, key_size=2048, backend=default_backend()), - wrapping_algorithm=_WRAPPING_ALGORITHM, - ), - RawRSAKeyring.fromPEMEncoding( - key_namespace=_PROVIDER_ID, - key_name=_KEY_ID, - encoded_key=_PRIVATE_KEY, - password=None, wrapping_algorithm=_WRAPPING_ALGORITHM, + private_wrapping_key=rsa.generate_private_key(public_exponent=65537, key_size=2048, backend=default_backend()), ), + # RawRSAKeyring.fromPEMEncoding( + # key_namespace=_PROVIDER_ID, + # key_name=_KEY_ID, + # encoded_key=_PRIVATE_KEY, + # password=None, + # wrapping_algorithm=_WRAPPING_ALGORITHM, + # ), # RawRSAKeyring.fromDEREncoding( # key_namespace=_PROVIDER_ID, # key_name=_KEY_ID, @@ -160,6 +162,5 @@ def test_raw_rsa_encryption_decryption(encryption_materials_samples, fake_raw_rs 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.data_key == decryption_materials.data_encryption_key.data_key diff --git a/test/unit/test_keyring_raw_aes.py b/test/unit/test_keyring_raw_aes.py index 85b483b10..a623b4739 100644 --- a/test/unit/test_keyring_raw_aes.py +++ b/test/unit/test_keyring_raw_aes.py @@ -24,6 +24,7 @@ from aws_encryption_sdk.structures import KeyringTrace, MasterKeyInfo, RawDataKey from .test_values import VALUES + # from .test_utils import NullRawAESKeyring try: # Python 3.5.0 and 3.5.1 have incompatible typing modules @@ -95,15 +96,15 @@ ), 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}, + ) + ], ) -_DECRYPTION_MATERIALS_WITHOUT_DATA_KEY = DecryptionMaterials( - verification_key=b"ex_verification_key", -) +_DECRYPTION_MATERIALS_WITHOUT_DATA_KEY = DecryptionMaterials(verification_key=b"ex_verification_key") class TestRawAESKeyring(object): @@ -213,8 +214,9 @@ def test_decrypt_when_data_key_provided(self, mock_decrypt): wrapping_algorithm=WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING, wrapping_key=_WRAPPING_KEY, ) - test = test_raw_aes_keyring.on_decrypt(decryption_materials=_DECRYPTION_MATERIALS_WITH_DATA_KEY, - encrypted_data_keys=[self.mock_encrypted_data_key]) + test = test_raw_aes_keyring.on_decrypt( + decryption_materials=_DECRYPTION_MATERIALS_WITH_DATA_KEY, encrypted_data_keys=[self.mock_encrypted_data_key] + ) assert not mock_decrypt.called # @patch("aws_encryption_sdk.internal.crypto.wrapping_keys.WrappingKey.decrypt") diff --git a/test/unit/test_keyring_raw_rsa.py b/test/unit/test_keyring_raw_rsa.py index 532cfc01e..ba68ae151 100644 --- a/test/unit/test_keyring_raw_rsa.py +++ b/test/unit/test_keyring_raw_rsa.py @@ -25,6 +25,7 @@ from aws_encryption_sdk.structures import KeyringTrace, MasterKeyInfo, RawDataKey from .test_values import VALUES + # from .test_utils import NullRawAESKeyring try: # Python 3.5.0 and 3.5.1 have incompatible typing modules @@ -96,15 +97,15 @@ ), 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}, + ) + ], ) -_DECRYPTION_MATERIALS_WITHOUT_DATA_KEY = DecryptionMaterials( - verification_key=b"ex_verification_key", -) +_DECRYPTION_MATERIALS_WITHOUT_DATA_KEY = DecryptionMaterials(verification_key=b"ex_verification_key") class TestRawRSAKeyring(object): @@ -136,7 +137,7 @@ def test_data_encryption_key_provided(self, mock_generate_data_key): key_namespace=_PROVIDER_ID, key_name=_KEY_ID, wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, - wrapping_key=_WRAPPING_KEY, + private_wrapping_key=_WRAPPING_KEY, ) test = test_raw_rsa_keyring.on_encrypt(encryption_materials=_ENCRYPTION_MATERIALS_WITH_DATA_KEY) @@ -151,7 +152,7 @@ def test_data_encryption_key_generated(self): key_namespace=_PROVIDER_ID, key_name=_KEY_ID, wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, - wrapping_key=_WRAPPING_KEY, + private_wrapping_key=_WRAPPING_KEY, ) test = test_raw_rsa_keyring.on_encrypt(encryption_materials=_ENCRYPTION_MATERIALS_WITHOUT_DATA_KEY) @@ -171,7 +172,7 @@ def test_encrypted_data_key_provided(self, mock_generate_data_key): key_namespace=_PROVIDER_ID, key_name=_KEY_ID, wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, - wrapping_key=_WRAPPING_KEY, + private_wrapping_key=_WRAPPING_KEY, ) test = test_raw_rsa_keyring.on_encrypt(encryption_materials=_ENCRYPTION_MATERIALS_WITH_ENCRYPTED_DATA_KEY) @@ -200,7 +201,7 @@ def test_data_key_not_generated(self, mock_generate_data_key): key_namespace=_PROVIDER_ID, key_name=_KEY_ID, wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, - wrapping_key=_WRAPPING_KEY, + private_wrapping_key=_WRAPPING_KEY, ) test = test_raw_rsa_keyring.on_encrypt(encryption_materials=_ENCRYPTION_MATERIALS_WITHOUT_DATA_KEY) assert pytest.raises(GenerateKeyError) @@ -212,10 +213,11 @@ def test_decrypt_when_data_key_provided(self, mock_decrypt): key_namespace=_PROVIDER_ID, key_name=_KEY_ID, wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, - wrapping_key=_WRAPPING_KEY, + private_wrapping_key=_WRAPPING_KEY, + ) + test = test_raw_rsa_keyring.on_decrypt( + decryption_materials=_DECRYPTION_MATERIALS_WITH_DATA_KEY, encrypted_data_keys=[self.mock_encrypted_data_key] ) - test = test_raw_rsa_keyring.on_decrypt(decryption_materials=_DECRYPTION_MATERIALS_WITH_DATA_KEY, - encrypted_data_keys=[self.mock_encrypted_data_key]) assert not mock_decrypt.called # @patch("aws_encryption_sdk.internal.crypto.wrapping_keys.WrappingKey.decrypt") diff --git a/test/unit/test_utils.py b/test/unit/test_utils.py index 0da12a869..2742b77f4 100644 --- a/test/unit/test_utils.py +++ b/test/unit/test_utils.py @@ -21,9 +21,9 @@ 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.materials_managers import EncryptionMaterials, DecryptionMaterials, EncryptedDataKey +from aws_encryption_sdk.keyring.raw_keyring import RawAESKeyring, RawRSAKeyring +from aws_encryption_sdk.materials_managers import DecryptionMaterials, EncryptedDataKey, EncryptionMaterials from aws_encryption_sdk.structures import DataKey, EncryptedDataKey, MasterKeyInfo, RawDataKey -from aws_encryption_sdk.keyring.raw_keyring import RawRSAKeyring, RawAESKeyring from .test_values import VALUES from .unit_test_utils import assert_prepped_stream_identity @@ -291,4 +291,3 @@ def test_source_data_key_length_check_invalid(self): source_data_key=mock_data_key, algorithm=mock_algorithm ) excinfo.match("Invalid Source Data Key length 4 for algorithm required: 5") - diff --git a/test/unit/test_values.py b/test/unit/test_values.py index acd09db2a..b9aba0c02 100644 --- a/test/unit/test_values.py +++ b/test/unit/test_values.py @@ -189,7 +189,8 @@ def array_byte(source): "signature_len": b"\x00h", "private_rsa_key_bytes": [ ( - b"-----BEGIN RSA PRIVATE KEY-----"b"MIICXgIBAAKBgQCUjhI8YRPXV8Gfofbg/" + b"-----BEGIN RSA PRIVATE KEY-----" + b"MIICXgIBAAKBgQCUjhI8YRPXV8Gfofbg/" b"PLjWw2AzowQTPErLU2z3+xGqElMdzdiC4Ta43DFWZg34Eg0X8kQPAeoe8h3cRSMo" b"77eSOHt2dPo7OfTfZqsH8766fivHIKVxBYPX8SZYIUhMtRnlg3uqch9BksfRop+h" b"f8h/H3lfervJoevS2CXYB9/iwIDAQABAoGBAIqeGzQOHbaGI51yQ2zjez1dPDdiB" @@ -233,8 +234,8 @@ def array_byte(source): b"xvpUDpzMioz6zUH9YV43YNtt+5Xnzkqj+u9Mr27/H2v9XPwORGfwQ5XPwRJz/2oC\n" b"EnPmP1SZoY9lXKUpQXHXSpDZ2rE2Klt3RHMUMHt8Zpy36E8Vwx8o\n" b"-----END RSA PRIVATE KEY-----\n" - ) - ] + ), + ], } VALUES["updated_encryption_context"] = copy.deepcopy(VALUES["encryption_context"]) VALUES["updated_encryption_context"]["aws-crypto-public-key"] = VALUES["encoded_curve_point"] From 3b28bea996a8364276e4890d7ac6da3c208f57f8 Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Tue, 23 Jul 2019 15:42:05 -0700 Subject: [PATCH 097/119] partial commit for raw keyrings --- src/aws_encryption_sdk/keyring/raw_keyring.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/aws_encryption_sdk/keyring/raw_keyring.py b/src/aws_encryption_sdk/keyring/raw_keyring.py index 15d196a71..4b3aec159 100644 --- a/src/aws_encryption_sdk/keyring/raw_keyring.py +++ b/src/aws_encryption_sdk/keyring/raw_keyring.py @@ -190,23 +190,23 @@ 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 print("expected_key_info_len=", expected_key_info_len) - count = 0 for key in encrypted_data_keys: - count += 1 - print("Key no = ", count) + if decryption_materials.data_encryption_key is not None: return decryption_materials + if ( 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) ): - print("If condition did not match") + print("If condition matched") 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 + wrapping_algorithm=self._wrapping_algorithm, wrapping_key_id=key.key_provider.key_info, + wrapped_encrypted_key=key ) # EncryptedData to raw key string @@ -219,7 +219,7 @@ def on_decrypt(self, decryption_materials, encrypted_data_keys): except Exception: # pylint: disable=broad-except error_message = "Raw AES Keyring unable to decrypt data key" _LOGGER.exception(error_message) - continue + return decryption_materials # Create a keyring trace keyring_trace = KeyringTrace( @@ -427,7 +427,8 @@ def on_decrypt(self, decryption_materials, encrypted_data_keys): 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 + wrapping_algorithm=self._wrapping_algorithm, wrapping_key_id=key.key_provider.key_info, + wrapped_encrypted_key=key ) try: plaintext_data_key = self._private_wrapping_key.decrypt( From 8f659473640c95c21098aa4dc6f1e2976976ddb4 Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Tue, 23 Jul 2019 15:57:09 -0700 Subject: [PATCH 098/119] Made suggested changes --- src/aws_encryption_sdk/keyring/raw_keyring.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/aws_encryption_sdk/keyring/raw_keyring.py b/src/aws_encryption_sdk/keyring/raw_keyring.py index 4b3aec159..c5642546c 100644 --- a/src/aws_encryption_sdk/keyring/raw_keyring.py +++ b/src/aws_encryption_sdk/keyring/raw_keyring.py @@ -17,7 +17,6 @@ import attr import six - from attr.validators import instance_of, optional from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives import serialization @@ -205,8 +204,9 @@ def on_decrypt(self, decryption_materials, encrypted_data_keys): # Wrapped EncryptedDataKey to deserialized EncryptedData encrypted_wrapped_key = deserialize_wrapped_key( - wrapping_algorithm=self._wrapping_algorithm, wrapping_key_id=key.key_provider.key_info, - wrapped_encrypted_key=key + wrapping_algorithm=self._wrapping_algorithm, + wrapping_key_id=key.key_provider.key_info, + wrapped_encrypted_key=key, ) # EncryptedData to raw key string @@ -378,7 +378,7 @@ def on_encrypt(self, encryption_materials): iv=None, ciphertext=self._public_wrapping_key.encrypt( plaintext=encryption_materials.data_encryption_key.data_key, - padding=self._wrapping_algorithm.padding + padding=self._wrapping_algorithm.padding, ), tag=None, ) @@ -427,8 +427,9 @@ def on_decrypt(self, decryption_materials, encrypted_data_keys): continue # Wrapped EncryptedDataKey to deserialized EncryptedData encrypted_wrapped_key = deserialize_wrapped_key( - wrapping_algorithm=self._wrapping_algorithm, wrapping_key_id=key.key_provider.key_info, - wrapped_encrypted_key=key + wrapping_algorithm=self._wrapping_algorithm, + wrapping_key_id=key.key_provider.key_info, + wrapped_encrypted_key=key, ) try: plaintext_data_key = self._private_wrapping_key.decrypt( From 40eb8cc3e33ce02bb174442e1ed930c32871b25b Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Tue, 23 Jul 2019 16:32:32 -0700 Subject: [PATCH 099/119] Changed wrapping_key_id in deserialize_wrapped_key() back to self.key_name --- src/aws_encryption_sdk/keyring/raw_keyring.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/aws_encryption_sdk/keyring/raw_keyring.py b/src/aws_encryption_sdk/keyring/raw_keyring.py index c5642546c..591d930ac 100644 --- a/src/aws_encryption_sdk/keyring/raw_keyring.py +++ b/src/aws_encryption_sdk/keyring/raw_keyring.py @@ -205,7 +205,7 @@ def on_decrypt(self, decryption_materials, encrypted_data_keys): # Wrapped EncryptedDataKey to deserialized EncryptedData encrypted_wrapped_key = deserialize_wrapped_key( wrapping_algorithm=self._wrapping_algorithm, - wrapping_key_id=key.key_provider.key_info, + wrapping_key_id=self.key_name, wrapped_encrypted_key=key, ) @@ -428,7 +428,7 @@ def on_decrypt(self, decryption_materials, encrypted_data_keys): # Wrapped EncryptedDataKey to deserialized EncryptedData encrypted_wrapped_key = deserialize_wrapped_key( wrapping_algorithm=self._wrapping_algorithm, - wrapping_key_id=key.key_provider.key_info, + wrapping_key_id=self.key_name, wrapped_encrypted_key=key, ) try: From 96979b1d1d551666a27d737978256b77279ec65d Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Tue, 23 Jul 2019 18:25:32 -0700 Subject: [PATCH 100/119] Decryption and PEM input now works --- test/functional/test_f_keyring_raw_aes.py | 3 +- test/functional/test_f_keyring_raw_rsa.py | 59 ++++++++++++++--------- test/unit/test_keyring_raw_aes.py | 6 ++- test/unit/test_utils.py | 45 ++++++++++++----- 4 files changed, 77 insertions(+), 36 deletions(-) diff --git a/test/functional/test_f_keyring_raw_aes.py b/test/functional/test_f_keyring_raw_aes.py index 8b05ba914..4c3bbc2a0 100644 --- a/test/functional/test_f_keyring_raw_aes.py +++ b/test/functional/test_f_keyring_raw_aes.py @@ -100,7 +100,8 @@ def test_raw_aes_encryption_decryption(encryption_materials_samples): # 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 diff --git a/test/functional/test_f_keyring_raw_rsa.py b/test/functional/test_f_keyring_raw_rsa.py index bfaf34a72..64e04dc88 100644 --- a/test/functional/test_f_keyring_raw_rsa.py +++ b/test/functional/test_f_keyring_raw_rsa.py @@ -28,25 +28,38 @@ _KEY_ID = b"5325b043-5843-4629-869c-64794af77ada" _SIGNING_KEY = b"aws-crypto-public-key" _WRAPPING_ALGORITHM = WrappingAlgorithm.RSA_OAEP_SHA256_MGF1 + _PRIVATE_KEY = ( - 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"-----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" ) + _ENCRYPTION_MATERIALS = [ EncryptionMaterials( algorithm=Algorithm.AES_256_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384, @@ -102,13 +115,13 @@ wrapping_algorithm=_WRAPPING_ALGORITHM, private_wrapping_key=rsa.generate_private_key(public_exponent=65537, key_size=2048, backend=default_backend()), ), - # RawRSAKeyring.fromPEMEncoding( - # key_namespace=_PROVIDER_ID, - # key_name=_KEY_ID, - # encoded_key=_PRIVATE_KEY, - # password=None, - # wrapping_algorithm=_WRAPPING_ALGORITHM, - # ), + RawRSAKeyring.fromPEMEncoding( + key_namespace=_PROVIDER_ID, + key_name=_KEY_ID, + private_encoded_key=_PRIVATE_KEY, + password=None, + wrapping_algorithm=_WRAPPING_ALGORITHM, + ), # RawRSAKeyring.fromDEREncoding( # key_namespace=_PROVIDER_ID, # key_name=_KEY_ID, diff --git a/test/unit/test_keyring_raw_aes.py b/test/unit/test_keyring_raw_aes.py index a623b4739..e25338e56 100644 --- a/test/unit/test_keyring_raw_aes.py +++ b/test/unit/test_keyring_raw_aes.py @@ -104,7 +104,11 @@ ], ) -_DECRYPTION_MATERIALS_WITHOUT_DATA_KEY = DecryptionMaterials(verification_key=b"ex_verification_key") +_DECRYPTION_MATERIALS_WITHOUT_DATA_KEY = DecryptionMaterials( + algorithm=Algorithm.AES_256_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384, + verification_key=b"ex_verification_key", + encryption_context=_ENCRYPTION_CONTEXT +) class TestRawAESKeyring(object): diff --git a/test/unit/test_utils.py b/test/unit/test_utils.py index 2742b77f4..d448a4da7 100644 --- a/test/unit/test_utils.py +++ b/test/unit/test_utils.py @@ -21,8 +21,8 @@ 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.keyring.raw_keyring import RawAESKeyring, RawRSAKeyring -from aws_encryption_sdk.materials_managers import DecryptionMaterials, EncryptedDataKey, EncryptionMaterials +from aws_encryption_sdk.keyring.base import Keyring +from aws_encryption_sdk.materials_managers import DecryptionMaterials, EncryptionMaterials from aws_encryption_sdk.structures import DataKey, EncryptedDataKey, MasterKeyInfo, RawDataKey from .test_values import VALUES @@ -37,6 +37,37 @@ pytestmark = [pytest.mark.unit, pytest.mark.local] +_RAW_RSA_PRIVATE_KEY_PEM_ENCODED = ( + 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" +) + + def test_prep_stream_data_passthrough(): test = aws_encryption_sdk.internal.utils.prep_stream_data(io.BytesIO(b"some data")) @@ -50,7 +81,7 @@ def test_prep_stream_data_wrap(source): assert_prepped_stream_identity(test, io.BytesIO) -class NullRawRSAKeyring(RawRSAKeyring): +class IdentityKeyring(Keyring): def on_encrypt(self, encryption_materials): # type: (EncryptionMaterials) -> EncryptionMaterials return encryption_materials @@ -60,14 +91,6 @@ def on_decrypt(self, decryption_materials, encrypted_data_keys): return decryption_materials -class NullRawAESKeyring(RawAESKeyring): - def on_encrypt(self): - return - - def on_decrypt(self): - return - - class TestUtils(object): @pytest.fixture(autouse=True) def apply_fixtures(self): From f592956ff2ac0b20f6f6a60f01c96ef5279c27ff Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Tue, 23 Jul 2019 18:33:02 -0700 Subject: [PATCH 101/119] Adding sample --- examples/src/sample_aes.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/src/sample_aes.py b/examples/src/sample_aes.py index a78cac354..26b08eb9b 100644 --- a/examples/src/sample_aes.py +++ b/examples/src/sample_aes.py @@ -59,20 +59,20 @@ def sample_aes_encryption_decryption(): # 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 decryption_materials = fake_raw_aes_keyring.on_decrypt( - decryption_materials=decryption_materials, encrypted_data_keys=encryption_materials.encrypted_data_keys + decryption_materials=decryption_materials, encrypted_data_keys=encryption_materials.encrypted_data_keys, ) print("DECRYPTED DATA KEY") print(decryption_materials.data_encryption_key.data_key) - 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 sample_aes_encryption_decryption() From dbbb840cbb0c582d195813c5a785eff9c4fb6cb1 Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Wed, 24 Jul 2019 16:44:09 -0700 Subject: [PATCH 102/119] Removed test comments --- examples/src/sample_aes.py | 8 ++++---- src/aws_encryption_sdk/keyring/raw_keyring.py | 6 ------ 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/examples/src/sample_aes.py b/examples/src/sample_aes.py index 26b08eb9b..fe491188e 100644 --- a/examples/src/sample_aes.py +++ b/examples/src/sample_aes.py @@ -41,7 +41,7 @@ def sample_aes_encryption_decryption(): _wrapping_algorithm = WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING # Creating an instance of a raw AES keyring - fake_raw_aes_keyring = RawAESKeyring( + sample_raw_aes_keyring = RawAESKeyring( key_namespace=key_namespace, key_name=key_name, wrapping_key=_WRAPPING_KEY, @@ -49,13 +49,13 @@ def sample_aes_encryption_decryption(): ) # Call on_encrypt function for the keyring - encryption_materials = fake_raw_aes_keyring.on_encrypt(encryption_materials=_ENCRYPTION_MATERIALS) + encryption_materials = sample_raw_aes_keyring.on_encrypt(encryption_materials=_ENCRYPTION_MATERIALS) print("PLAINTEXT DATA KEY") print(encryption_materials.data_encryption_key.data_key) print("ENCRYPTED DATA KEY") - print(encryption_materials.encrypted_data_keys) + print(encryption_materials.encrypted_data_keys[0].encrypted_data_key) # Generate decryption materials decryption_materials = DecryptionMaterials( @@ -64,7 +64,7 @@ def sample_aes_encryption_decryption(): ) # Call on_decrypt function for the keyring - decryption_materials = fake_raw_aes_keyring.on_decrypt( + decryption_materials = sample_raw_aes_keyring.on_decrypt( decryption_materials=decryption_materials, encrypted_data_keys=encryption_materials.encrypted_data_keys, ) diff --git a/src/aws_encryption_sdk/keyring/raw_keyring.py b/src/aws_encryption_sdk/keyring/raw_keyring.py index 591d930ac..861b5fc1a 100644 --- a/src/aws_encryption_sdk/keyring/raw_keyring.py +++ b/src/aws_encryption_sdk/keyring/raw_keyring.py @@ -183,12 +183,10 @@ def on_decrypt(self, decryption_materials, encrypted_data_keys): :rtype: aws_encryption_sdk.materials_managers.DecryptionMaterials """ if decryption_materials.data_encryption_key is not None: - print("Data key already present") return decryption_materials # Decrypt data key expected_key_info_len = len(self._key_info_prefix) + self._wrapping_algorithm.algorithm.iv_len - print("expected_key_info_len=", expected_key_info_len) for key in encrypted_data_keys: if decryption_materials.data_encryption_key is not None: @@ -199,7 +197,6 @@ def on_decrypt(self, decryption_materials, encrypted_data_keys): or len(key.key_provider.key_info) != expected_key_info_len or not key.key_provider.key_info.startswith(self._key_info_prefix) ): - print("If condition matched") continue # Wrapped EncryptedDataKey to deserialized EncryptedData @@ -226,15 +223,12 @@ def on_decrypt(self, decryption_materials, encrypted_data_keys): wrapping_key=self._key_provider, flags={KeyringTraceFlag.WRAPPING_KEY_DECRYPTED_DATA_KEY} ) - print("Keyring trace made") - # 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) - print("Done") return decryption_materials From b71e09c322a3c35762e1e31afc2e1c4b7a790cde Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Fri, 26 Jul 2019 01:52:41 -0700 Subject: [PATCH 103/119] Unit tests for raw aes and rsa --- examples/src/sample_aes.py | 9 +- src/aws_encryption_sdk/keyring/raw_keyring.py | 39 +- test/functional/test_f_keyring_raw_aes.py | 22 +- test/unit/test_keyring_raw_aes.py | 497 ++++++++------- test/unit/test_keyring_raw_rsa.py | 580 +++++++++++++----- test/unit/test_utils.py | 182 +++++- 6 files changed, 925 insertions(+), 404 deletions(-) diff --git a/examples/src/sample_aes.py b/examples/src/sample_aes.py index fe491188e..23d91e1a1 100644 --- a/examples/src/sample_aes.py +++ b/examples/src/sample_aes.py @@ -59,15 +59,18 @@ def sample_aes_encryption_decryption(): # 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.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 decryption_materials = sample_raw_aes_keyring.on_decrypt( - decryption_materials=decryption_materials, encrypted_data_keys=encryption_materials.encrypted_data_keys, + decryption_materials=decryption_materials, encrypted_data_keys=encryption_materials.encrypted_data_keys ) + print(decryption_materials.keyring_trace) + print("DECRYPTED DATA KEY") print(decryption_materials.data_encryption_key.data_key) diff --git a/src/aws_encryption_sdk/keyring/raw_keyring.py b/src/aws_encryption_sdk/keyring/raw_keyring.py index 861b5fc1a..da4d93707 100644 --- a/src/aws_encryption_sdk/keyring/raw_keyring.py +++ b/src/aws_encryption_sdk/keyring/raw_keyring.py @@ -45,7 +45,7 @@ def generate_data_key( encryption_materials, # type: EncryptionMaterials key_provider, # type: MasterKeyInfo ): - # type: (...) -> bool + # type: (...) -> bytes """Generates plaintext data key for the keyring. :param encryption_materials: Encryption materials for the keyring to modify. @@ -54,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 @@ -70,7 +75,7 @@ def generate_data_key( # Add generated data key to encryption_materials encryption_materials.add_data_encryption_key(data_encryption_key, keyring_trace) - return True + return plaintext_data_key @attr.s @@ -136,7 +141,7 @@ def on_encrypt(self, encryption_materials): ) # Check if data key exists - if not plaintext_generated: + if not plaintext_generated or plaintext_generated is None: raise GenerateKeyError("Unable to generate data encryption key.") # Encrypt data key @@ -201,9 +206,7 @@ def on_decrypt(self, decryption_materials, encrypted_data_keys): # 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, + wrapping_algorithm=self._wrapping_algorithm, wrapping_key_id=self.key_name, wrapped_encrypted_key=key ) # EncryptedData to raw key string @@ -286,8 +289,6 @@ def fromPEMEncoding( loaded_public_wrapping_key = serialization.load_pem_public_key( data=public_encoded_key, backend=default_backend() ) - if public_encoded_key is None and private_encoded_key is None: - raise TypeError("At least one of public key or private key must be provided.") return cls( key_namespace=key_namespace, @@ -327,8 +328,6 @@ def fromDEREncoding( loaded_public_wrapping_key = serialization.load_der_public_key( data=public_encoded_key, backend=default_backend() ) - if public_encoded_key is None and private_encoded_key is None: - raise TypeError("At least one of public key or private key must be provided.") return cls( key_namespace=key_namespace, @@ -342,6 +341,10 @@ 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) + + 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() @@ -360,7 +363,7 @@ def on_encrypt(self, encryption_materials): ) # Check if data key exists - if not plaintext_generated: + if not plaintext_generated or plaintext_generated is None: raise GenerateKeyError("Unable to generate data encryption key.") if self._public_wrapping_key is None: @@ -416,14 +419,14 @@ 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( - wrapping_algorithm=self._wrapping_algorithm, - wrapping_key_id=self.key_name, - wrapped_encrypted_key=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( diff --git a/test/functional/test_f_keyring_raw_aes.py b/test/functional/test_f_keyring_raw_aes.py index 4c3bbc2a0..699b594b6 100644 --- a/test/functional/test_f_keyring_raw_aes.py +++ b/test/functional/test_f_keyring_raw_aes.py @@ -27,6 +27,12 @@ _WRAPPING_KEY = b"12345678901234567890123456789012" _SIGNING_KEY = b"aws-crypto-public-key" +_WRAPPING_ALGORITHM = [ + WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING, + WrappingAlgorithm.AES_128_GCM_IV12_TAG16_NO_PADDING, + WrappingAlgorithm.AES_192_GCM_IV12_TAG16_NO_PADDING +] + _ENCRYPTION_MATERIALS = [ EncryptionMaterials( algorithm=Algorithm.AES_256_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384, @@ -77,15 +83,16 @@ @pytest.mark.parametrize("encryption_materials_samples", _ENCRYPTION_MATERIALS) -def test_raw_aes_encryption_decryption(encryption_materials_samples): +@pytest.mark.parametrize("wrapping_algorithm_samples", _WRAPPING_ALGORITHM) +def test_raw_aes_encryption_decryption(encryption_materials_samples, wrapping_algorithm_samples): # Initializing attributes key_namespace = _PROVIDER_ID key_name = _KEY_ID - _wrapping_algorithm = WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING + _wrapping_algorithm = wrapping_algorithm_samples # Creating an instance of a raw AES keyring - fake_raw_aes_keyring = RawAESKeyring( + sample_raw_aes_keyring = RawAESKeyring( key_namespace=key_namespace, key_name=key_name, wrapping_key=_WRAPPING_KEY, @@ -93,19 +100,20 @@ def test_raw_aes_encryption_decryption(encryption_materials_samples): ) # Call on_encrypt function for the keyring - encryption_materials = fake_raw_aes_keyring.on_encrypt(encryption_materials=encryption_materials_samples) + encryption_materials = sample_raw_aes_keyring.on_encrypt(encryption_materials=encryption_materials_samples) print("PLAINTEXT DATA KEY") print(encryption_materials.data_encryption_key) # 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.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 - decryption_materials = fake_raw_aes_keyring.on_decrypt( + decryption_materials = sample_raw_aes_keyring.on_decrypt( decryption_materials=decryption_materials, encrypted_data_keys=encryption_materials.encrypted_data_keys ) diff --git a/test/unit/test_keyring_raw_aes.py b/test/unit/test_keyring_raw_aes.py index e25338e56..8f6e32605 100644 --- a/test/unit/test_keyring_raw_aes.py +++ b/test/unit/test_keyring_raw_aes.py @@ -13,19 +13,16 @@ """Unit tests for Raw AES keyring.""" import pytest -import six -from mock import MagicMock, patch, sentinel +from mock import MagicMock, patch, sentinel, Mock -from aws_encryption_sdk.exceptions import GenerateKeyError -from aws_encryption_sdk.identifiers import Algorithm, KeyringTraceFlag, WrappingAlgorithm +from aws_encryption_sdk.identifiers import KeyringTraceFlag, WrappingAlgorithm, Algorithm from aws_encryption_sdk.keyring.base import EncryptedDataKey, Keyring -from aws_encryption_sdk.keyring.raw_keyring import RawAESKeyring, generate_data_key -from aws_encryption_sdk.materials_managers import DecryptionMaterials, EncryptionMaterials -from aws_encryption_sdk.structures import KeyringTrace, MasterKeyInfo, RawDataKey - -from .test_values import VALUES - -# from .test_utils import NullRawAESKeyring +from aws_encryption_sdk.keyring.raw_keyring import RawAESKeyring, generate_data_key, GenerateKeyError +from aws_encryption_sdk.structures import MasterKeyInfo +from aws_encryption_sdk.materials_managers import EncryptionMaterials +from .test_utils import _ENCRYPTION_MATERIALS_WITHOUT_DATA_KEY, _ENCRYPTION_MATERIALS_WITH_DATA_KEY, _PROVIDER_ID, \ + _WRAPPING_KEY, _DATA_KEY, _KEY_ID, _DECRYPTION_MATERIALS_WITH_DATA_KEY, _DECRYPTION_MATERIALS_WITHOUT_DATA_KEY, \ + _ENCRYPTION_CONTEXT, _ENCRYPTED_DATA_KEY_AES, _SIGNING_KEY try: # Python 3.5.0 and 3.5.1 have incompatible typing modules from typing import Iterable # noqa pylint: disable=unused-import @@ -35,215 +32,291 @@ 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" -) -_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( - algorithm=Algorithm.AES_256_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384, - verification_key=b"ex_verification_key", - encryption_context=_ENCRYPTION_CONTEXT -) - - -class TestRawAESKeyring(object): - @pytest.fixture(autouse=True) - def apply_fixtures(self): - self.mock_encrypted_data_key = EncryptedDataKey( - key_provider=MasterKeyInfo(provider_id=_PROVIDER_ID, key_info=_KEY_ID), - encrypted_data_key=VALUES["encrypted_data_key"], - ) - self.mock_encryption_materials = MagicMock() - self.mock_encryption_materials.__class__ = EncryptionMaterials - - def test_parent(self): - assert issubclass(RawAESKeyring, Keyring) - - # def test_initialization(self): - # test = RawAESKeyring( - # key_namespace=_PROVIDER_ID, - # key_name=_KEY_ID, - # wrapping_algorithm=WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING, - # wrapping_key=_WRAPPING_KEY, - # ) - # assert test.__getattribute__(key_provider) == self.mock_encrypted_data_key.key_provider - - @patch("aws_encryption_sdk.keyring.raw_keyring.generate_data_key") - def test_data_encryption_key_provided(self, mock_generate_data_key): - mock_generate_data_key.return_value = _DATA_KEY - test_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, - ) - test = test_raw_aes_keyring.on_encrypt(encryption_materials=_ENCRYPTION_MATERIALS_WITH_DATA_KEY) - # Check if keyring is generated - assert not mock_generate_data_key.called +def test_parent(): + assert issubclass(RawAESKeyring, Keyring) - # Check if data encryption key is encrypted - assert test.encrypted_data_keys is not None - def test_data_encryption_key_generated(self): - test_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, - ) - test = test_raw_aes_keyring.on_encrypt(encryption_materials=_ENCRYPTION_MATERIALS_WITHOUT_DATA_KEY) - - # Check if key is generated - if not test.data_encryption_key: - # Check if error thrown if data key is not generated - assert pytest.raises(GenerateKeyError, "Unable to generate data encryption key.") - else: - # Check if data key is generated - assert test.data_encryption_key and test.data_encryption_key is not None - assert test.encrypted_data_keys and test.encrypted_data_keys is not None - - @patch("aws_encryption_sdk.keyring.raw_keyring.generate_data_key") - def test_encrypted_data_key_provided(self, mock_generate_data_key): - mock_generate_data_key.return_value = _DATA_KEY - test_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, - ) - test = test_raw_aes_keyring.on_encrypt(encryption_materials=_ENCRYPTION_MATERIALS_WITH_ENCRYPTED_DATA_KEY) - - # Check if generate_data_key is called - assert not mock_generate_data_key.called - # - # Check if encrypt is called - assert len(test.encrypted_data_keys) == len(_ENCRYPTION_MATERIALS_WITH_ENCRYPTED_DATA_KEY.encrypted_data_keys) - - # @patch("aws_encryption_sdk.key_providers.raw.os.urandom") - # def test_data_key_not_generated(self, mock_os_urandom): - # mock_os_urandom.return_value = None - # test_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, - # ) - # test = test_raw_aes_keyring.on_encrypt(encryption_materials=_ENCRYPTION_MATERIALS_WITHOUT_DATA_KEY) - # assert pytest.raises(GenerateKeyError, "Unable to generate data encryption key.") - - @patch("aws_encryption_sdk.keyring.raw_keyring.generate_data_key") - def test_data_key_not_generated(self, mock_generate_data_key): - mock_generate_data_key.return_value = None - test_raw_aes_keyring = RawAESKeyring( +def test_valid_parameters(): + test = RawAESKeyring( + key_namespace=_PROVIDER_ID, + key_name=_KEY_ID, + wrapping_algorithm=WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING, + wrapping_key=_WRAPPING_KEY, + ) + assert test.key_name == _KEY_ID + assert test.key_namespace == _PROVIDER_ID + assert test._wrapping_algorithm == WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING + assert test._wrapping_key == _WRAPPING_KEY + + +def test_missing_required_parameters(): + with pytest.raises(Exception) as exc_info: + RawAESKeyring( key_namespace=_PROVIDER_ID, - key_name=_KEY_ID, wrapping_algorithm=WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING, - wrapping_key=_WRAPPING_KEY, ) - test = test_raw_aes_keyring.on_encrypt(encryption_materials=_ENCRYPTION_MATERIALS_WITHOUT_DATA_KEY) - assert pytest.raises(GenerateKeyError) + assert exc_info.errisinstance(TypeError) + - @patch("aws_encryption_sdk.internal.crypto.wrapping_keys.WrappingKey.decrypt") - def test_decrypt_when_data_key_provided(self, mock_decrypt): - mock_decrypt.return_value = _DATA_KEY - test_raw_aes_keyring = RawAESKeyring( +def test_invalid_values_as_parameter(): + with pytest.raises(Exception) as exc_info: + RawAESKeyring( key_namespace=_PROVIDER_ID, key_name=_KEY_ID, wrapping_algorithm=WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING, - wrapping_key=_WRAPPING_KEY, + wrapping_key=WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING, ) - test = test_raw_aes_keyring.on_decrypt( - decryption_materials=_DECRYPTION_MATERIALS_WITH_DATA_KEY, encrypted_data_keys=[self.mock_encrypted_data_key] - ) - assert not mock_decrypt.called - - # @patch("aws_encryption_sdk.internal.crypto.wrapping_keys.WrappingKey.decrypt") - # def test_decrypt_when_data_key_not_provided(self, mock_decrypt): - # mock_decrypt.return_value = _DATA_KEY - # test_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, - # ) - # - # test = test_raw_aes_keyring.on_decrypt(decryption_materials=_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\x7f.}\x87\x16,\x11n#\xc8p" - # b"\xdb\xbf\x94\x86*Q\x06\xd2\xf5\xdah\x08\xa4p\x81\xf7\xf4G\ - # x07FzE\xde", - # ) - # ] - # ) - # assert mock_decrypt.called + assert exc_info.errisinstance(TypeError) + + +@patch("aws_encryption_sdk.keyring.raw_keyring.generate_data_key") +def test_on_encrypt_when_data_encryption_key_given(mock_generate_data_key): + mock_generate_data_key.return_value = _DATA_KEY + test_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, + ) + + test = test_raw_aes_keyring.on_encrypt(encryption_materials=_ENCRYPTION_MATERIALS_WITH_DATA_KEY) + # Check if keyring is generated + assert not mock_generate_data_key.called + + +def test_keyring_trace_on_encrypt_when_data_encryption_key_given(): + test_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, + ) + + test = test_raw_aes_keyring.on_encrypt(encryption_materials=_ENCRYPTION_MATERIALS_WITH_DATA_KEY) + + for keyring_trace in test.keyring_trace: + if keyring_trace.wrapping_key.key_info == _KEY_ID: + # Check keyring trace does not contain KeyringTraceFlag.WRAPPING_KEY_GENERATED_DATA_KEY + assert KeyringTraceFlag.WRAPPING_KEY_GENERATED_DATA_KEY not in keyring_trace.flags + + +def test_on_encrypt_when_data_encryption_key_not_given(): + test_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, + ) + + original_number_of_encrypted_data_keys = len(_ENCRYPTION_MATERIALS_WITHOUT_DATA_KEY.encrypted_data_keys) + + test = test_raw_aes_keyring.on_encrypt(encryption_materials=_ENCRYPTION_MATERIALS_WITHOUT_DATA_KEY) + + # Check if data key is generated + assert test.data_encryption_key and test.data_encryption_key is not None + + generated_flag_count = 0 + encrypted_flag_count = 0 + + for keyring_trace in test.keyring_trace: + if keyring_trace.wrapping_key.key_info == _KEY_ID and KeyringTraceFlag.WRAPPING_KEY_GENERATED_DATA_KEY \ + in keyring_trace.flags: + # Check keyring trace contains KeyringTraceFlag.WRAPPING_KEY_GENERATED_DATA_KEY + generated_flag_count += 1 + if KeyringTraceFlag.WRAPPING_KEY_ENCRYPTED_DATA_KEY in keyring_trace.flags: + encrypted_flag_count += 1 + + assert generated_flag_count == 1 + + assert len(test.encrypted_data_keys) == original_number_of_encrypted_data_keys + 1 + + assert encrypted_flag_count == 1 + + +@patch("aws_encryption_sdk.internal.crypto.wrapping_keys.WrappingKey.decrypt") +def test_on_decrypt_when_data_key_given(mock_decrypt): + mock_decrypt.return_value = _DATA_KEY + test_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, + ) + test = test_raw_aes_keyring.on_decrypt( + decryption_materials=_DECRYPTION_MATERIALS_WITH_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\x7f.}\x87\x16,\x11n#\xc8p" + b"\xdb\xbf\x94\x86*Q\x06\xd2\xf5\xdah\x08\xa4p\x81\xf7\xf4G\ + x07FzE\xde", + ) + ] + ) + assert not mock_decrypt.called + + +def test_keyring_trace_on_decrypt_when_data_key_given(): + test_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, + ) + test = test_raw_aes_keyring.on_decrypt( + decryption_materials=_DECRYPTION_MATERIALS_WITH_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\x7f.}\x87\x16,\x11n#\xc8p" + b"\xdb\xbf\x94\x86*Q\x06\xd2\xf5\xdah\x08\xa4p\x81\xf7\xf4G\ + x07FzE\xde", + ) + ] + ) + for keyring_trace in test.keyring_trace: + if keyring_trace.wrapping_key.key_info == _KEY_ID: + # Check keyring trace does not contain KeyringTraceFlag.WRAPPING_KEY_DECRYPTED_DATA_KEY + assert KeyringTraceFlag.WRAPPING_KEY_DECRYPTED_DATA_KEY not in keyring_trace.flags + + +@patch("aws_encryption_sdk.internal.crypto.wrapping_keys.WrappingKey.decrypt") +def test_on_decrypt_when_data_key_and_edk_not_provided(mock_decrypt): + mock_decrypt.return_value = _DATA_KEY + test_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, + ) + + test = test_raw_aes_keyring.on_decrypt(decryption_materials=_DECRYPTION_MATERIALS_WITHOUT_DATA_KEY, + encrypted_data_keys=[]) + assert not mock_decrypt.called + + for keyring_trace in test.keyring_trace: + if keyring_trace.wrapping_key.key_info == _KEY_ID: + assert KeyringTraceFlag.WRAPPING_KEY_DECRYPTED_DATA_KEY not in keyring_trace.flags + + assert test.data_encryption_key is None + + +@patch("aws_encryption_sdk.internal.crypto.wrapping_keys.WrappingKey.decrypt") +def test_on_decrypt_when_data_key_not_provided_and_edk_not_in_keyring(mock_decrypt): + mock_decrypt.return_value = _DATA_KEY + test_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, + ) + + test = test_raw_aes_keyring.on_decrypt(decryption_materials=_DECRYPTION_MATERIALS_WITHOUT_DATA_KEY, + encrypted_data_keys=[ + EncryptedDataKey( + key_provider=MasterKeyInfo( + provider_id=_PROVIDER_ID, + key_info=b"5430b043-5843-4629-869c-64794af77ada"), + 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", + ) + ] + ) + assert not mock_decrypt.called + + for keyring_trace in test.keyring_trace: + if keyring_trace.wrapping_key.key_info == _KEY_ID: + assert KeyringTraceFlag.WRAPPING_KEY_DECRYPTED_DATA_KEY not in keyring_trace.flags + + assert test.data_encryption_key is None + + +@patch("aws_encryption_sdk.internal.crypto.wrapping_keys.WrappingKey.decrypt") +def test_on_decrypt_when_data_key_not_provided_and_edk_provided(mock_decrypt): + mock_decrypt.return_value = _DATA_KEY + test_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, + ) + + test = test_raw_aes_keyring.on_decrypt(decryption_materials=_DECRYPTION_MATERIALS_WITHOUT_DATA_KEY, + encrypted_data_keys=[_ENCRYPTED_DATA_KEY_AES] + ) + assert mock_decrypt.called_once_with(encrypted_wrapped_data_key=_ENCRYPTED_DATA_KEY_AES, + encryption_context=_ENCRYPTION_CONTEXT + ) + + +def test_keyring_trace_when_data_key_not_provided_and_edk_provided(): + test_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, + ) + + test = test_raw_aes_keyring.on_decrypt(decryption_materials=_DECRYPTION_MATERIALS_WITHOUT_DATA_KEY, + encrypted_data_keys=[_ENCRYPTED_DATA_KEY_AES] + ) + decrypted_flag_count = 0 + + for keyring_trace in test.keyring_trace: + if KeyringTraceFlag.WRAPPING_KEY_DECRYPTED_DATA_KEY in keyring_trace.flags: + decrypted_flag_count += 1 + + assert decrypted_flag_count == 1 + + +# @patch("aws_encryption_sdk.key_providers.raw.os.urandom") +# def test_error_when_data_key_not_generated(mock_os_urandom): +# mock_os_urandom.side_effect = Exception() +# test_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, +# ) +# with pytest.raises(GenerateKeyError) as exc_info: +# test_raw_aes_keyring.on_encrypt(encryption_materials=_ENCRYPTION_MATERIALS_WITHOUT_DATA_KEY) +# assert exc_info.match("Unable to generate data encryption key.") + + +def test_generate_data_key_error_when_data_key_exists(): + with pytest.raises(TypeError) as exc_info: + generate_data_key(encryption_materials=_ENCRYPTION_MATERIALS_WITHOUT_DATA_KEY, + key_provider=MasterKeyInfo( + provider_id=_PROVIDER_ID, + key_info=_KEY_ID + ) + ) + assert exc_info.match("Data encryption key already exists.") + + +def test_generate_data_key_keyring_trace(): + 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, + ) + plaintext = generate_data_key(encryption_materials=encryption_materials_without_data_key, + key_provider=MasterKeyInfo( + provider_id=_PROVIDER_ID, + key_info=_KEY_ID + ) + ) + + generate_flag_count = 0 + for keyring_trace in encryption_materials_without_data_key.keyring_trace: + if KeyringTraceFlag.WRAPPING_KEY_GENERATED_DATA_KEY in keyring_trace.flags: + generate_flag_count += 1 + assert generate_flag_count == 1 diff --git a/test/unit/test_keyring_raw_rsa.py b/test/unit/test_keyring_raw_rsa.py index ba68ae151..50c2f43f1 100644 --- a/test/unit/test_keyring_raw_rsa.py +++ b/test/unit/test_keyring_raw_rsa.py @@ -17,16 +17,14 @@ from cryptography.hazmat.primitives.asymmetric import rsa from mock import MagicMock, patch, sentinel -from aws_encryption_sdk.exceptions import GenerateKeyError from aws_encryption_sdk.identifiers import Algorithm, KeyringTraceFlag, WrappingAlgorithm from aws_encryption_sdk.keyring.base import EncryptedDataKey, Keyring -from aws_encryption_sdk.keyring.raw_keyring import RawRSAKeyring, generate_data_key +from aws_encryption_sdk.keyring.raw_keyring import RawRSAKeyring from aws_encryption_sdk.materials_managers import DecryptionMaterials, EncryptionMaterials from aws_encryption_sdk.structures import KeyringTrace, MasterKeyInfo, RawDataKey - -from .test_values import VALUES - -# from .test_utils import NullRawAESKeyring +from .test_utils import _KEY_ID, _ENCRYPTION_CONTEXT, _SIGNING_KEY, _DATA_KEY, _PROVIDER_ID, _ENCRYPTED_DATA_KEY_RSA + # _ENCRYPTION_MATERIALS_WITHOUT_DATA_KEY, _ENCRYPTION_MATERIALS_WITH_DATA_KEY, _DECRYPTION_MATERIALS_WITHOUT_DATA_KEY,\ + # _DECRYPTION_MATERIALS_WITH_DATA_KEY, _ENCRYPTED_DATA_KEY_RSA try: # Python 3.5.0 and 3.5.1 have incompatible typing modules from typing import Iterable # noqa pylint: disable=unused-import @@ -36,25 +34,17 @@ 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 = rsa.generate_private_key(public_exponent=65537, key_size=2048, backend=default_backend()) -_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" -) _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), + key_provider=MasterKeyInfo(provider_id=_PROVIDER_ID, key_info=b"5430b043-5843-4629-869c-64794af77ada"), 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), + wrapping_key=MasterKeyInfo(provider_id=_PROVIDER_ID, key_info=b"5430b043-5843-4629-869c-64794af77ada"), flags={KeyringTraceFlag.WRAPPING_KEY_GENERATED_DATA_KEY}, ) ], @@ -72,13 +62,7 @@ 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", - ) - ], + encrypted_data_keys=[_ENCRYPTED_DATA_KEY_RSA], encryption_context=_ENCRYPTION_CONTEXT, signing_key=_SIGNING_KEY, keyring_trace=[ @@ -89,158 +73,432 @@ ], ) -_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") +# # _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=b"5430b043-5843-4629-869c-64794af77ada"), +# # 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=b"5430b043-5843-4629-869c-64794af77ada"), +# # flags={KeyringTraceFlag.WRAPPING_KEY_DECRYPTED_DATA_KEY}, +# # ) +# # ], +# # ) +# # +# # _DECRYPTION_MATERIALS_WITHOUT_DATA_KEY = DecryptionMaterials( +# # algorithm=Algorithm.AES_256_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384, +# # verification_key=b"ex_verification_key", +# # encryption_context=_ENCRYPTION_CONTEXT, +# # ) +# +# # def apply_fixtures(self): +# # self.mock_encrypted_data_key = EncryptedDataKey( +# # key_provider=MasterKeyInfo(provider_id=_PROVIDER_ID, key_info=_KEY_ID), +# # encrypted_data_key=VALUES["encrypted_data_key"], +# # ) +# # self.mock_encryption_materials = MagicMock() +# # self.mock_encryption_materials.__class__ = EncryptionMaterials +# +# +def test_parent(): + assert issubclass(RawRSAKeyring, Keyring) -class TestRawRSAKeyring(object): - @pytest.fixture(autouse=True) - def apply_fixtures(self): - self.mock_encrypted_data_key = EncryptedDataKey( - key_provider=MasterKeyInfo(provider_id=_PROVIDER_ID, key_info=_KEY_ID), - encrypted_data_key=VALUES["encrypted_data_key"], - ) - self.mock_encryption_materials = MagicMock() - self.mock_encryption_materials.__class__ = EncryptionMaterials - - def test_parent(self): - assert issubclass(RawRSAKeyring, Keyring) - - # def test_initialization(self): - # test = RawAESKeyring( - # key_namespace=_PROVIDER_ID, - # key_name=_KEY_ID, - # wrapping_algorithm=WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING, - # wrapping_key=_WRAPPING_KEY, - # ) - # assert test.__getattribute__(key_provider) == self.mock_encrypted_data_key.key_provider - - @patch("aws_encryption_sdk.keyring.raw_keyring.generate_data_key") - def test_data_encryption_key_provided(self, mock_generate_data_key): - mock_generate_data_key.return_value = _DATA_KEY - test_raw_rsa_keyring = RawRSAKeyring( - key_namespace=_PROVIDER_ID, - key_name=_KEY_ID, - wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, - private_wrapping_key=_WRAPPING_KEY, - ) +def test_valid_parameters(): + test = 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()) + ) + assert test.key_namespace == _PROVIDER_ID + assert test.key_name == _KEY_ID + assert test._wrapping_algorithm == WrappingAlgorithm.RSA_OAEP_SHA256_MGF1 + assert isinstance(test._private_wrapping_key, rsa.RSAPrivateKey) - test = test_raw_rsa_keyring.on_encrypt(encryption_materials=_ENCRYPTION_MATERIALS_WITH_DATA_KEY) - # Check if keyring is generated - assert not mock_generate_data_key.called - # Check if data encryption key is encrypted - assert test.encrypted_data_keys is not None - - def test_data_encryption_key_generated(self): - test_raw_rsa_keyring = RawRSAKeyring( +def test_missing_required_parameters(): + with pytest.raises(Exception) as exc_info: + RawRSAKeyring( key_namespace=_PROVIDER_ID, - key_name=_KEY_ID, wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, - private_wrapping_key=_WRAPPING_KEY, + private_wrapping_key=rsa.generate_private_key(public_exponent=65537, key_size=2048, + backend=default_backend()) ) - test = test_raw_rsa_keyring.on_encrypt(encryption_materials=_ENCRYPTION_MATERIALS_WITHOUT_DATA_KEY) - - # Check if key is generated - if not test.data_encryption_key: - # Check if error thrown if data key is not generated - assert pytest.raises(GenerateKeyError, "Unable to generate data encryption key.") - else: - # Check if data key is generated - assert test.data_encryption_key and test.data_encryption_key is not None - assert test.encrypted_data_keys and test.encrypted_data_keys is not None - - @patch("aws_encryption_sdk.keyring.raw_keyring.generate_data_key") - def test_encrypted_data_key_provided(self, mock_generate_data_key): - mock_generate_data_key.return_value = _DATA_KEY - test_raw_rsa_keyring = RawRSAKeyring( - key_namespace=_PROVIDER_ID, - key_name=_KEY_ID, - wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, - private_wrapping_key=_WRAPPING_KEY, - ) - test = test_raw_rsa_keyring.on_encrypt(encryption_materials=_ENCRYPTION_MATERIALS_WITH_ENCRYPTED_DATA_KEY) - - # Check if generate_data_key is called - assert not mock_generate_data_key.called - # - # Check if encrypt is called - assert len(test.encrypted_data_keys) == len(_ENCRYPTION_MATERIALS_WITH_ENCRYPTED_DATA_KEY.encrypted_data_keys) - - # @patch("aws_encryption_sdk.key_providers.raw.os.urandom") - # def test_data_key_not_generated(self, mock_os_urandom): - # mock_os_urandom.return_value = None - # test_raw_aes_keyring = RawAESKeyring( - # key_namespace=_PROVIDER_ID, - # key_name=_KEY_ID, - # wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, - # wrapping_key=_WRAPPING_KEY, - # ) - # test = test_raw_aes_keyring.on_encrypt(encryption_materials=_ENCRYPTION_MATERIALS_WITHOUT_DATA_KEY) - # assert pytest.raises(GenerateKeyError, "Unable to generate data encryption key.") - - @patch("aws_encryption_sdk.keyring.raw_keyring.generate_data_key") - def test_data_key_not_generated(self, mock_generate_data_key): - mock_generate_data_key.return_value = None - test_raw_rsa_keyring = RawRSAKeyring( + assert exc_info.errisinstance(TypeError) + + +def test_invalid_values_as_parameter(): + with pytest.raises(Exception) as exc_info: + RawRSAKeyring( key_namespace=_PROVIDER_ID, key_name=_KEY_ID, wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, - private_wrapping_key=_WRAPPING_KEY, + private_wrapping_key=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, ) - test = test_raw_rsa_keyring.on_encrypt(encryption_materials=_ENCRYPTION_MATERIALS_WITHOUT_DATA_KEY) - assert pytest.raises(GenerateKeyError) + assert exc_info.errisinstance(TypeError) + - @patch("aws_encryption_sdk.internal.crypto.wrapping_keys.WrappingKey.decrypt") - def test_decrypt_when_data_key_provided(self, mock_decrypt): - mock_decrypt.return_value = _DATA_KEY - test_raw_rsa_keyring = RawRSAKeyring( +def test_public_and_private_key_not_provided(): + with pytest.raises(TypeError) as exc_info: + RawRSAKeyring( key_namespace=_PROVIDER_ID, key_name=_KEY_ID, wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, - private_wrapping_key=_WRAPPING_KEY, - ) - test = test_raw_rsa_keyring.on_decrypt( - decryption_materials=_DECRYPTION_MATERIALS_WITH_DATA_KEY, encrypted_data_keys=[self.mock_encrypted_data_key] ) - assert not mock_decrypt.called - - # @patch("aws_encryption_sdk.internal.crypto.wrapping_keys.WrappingKey.decrypt") - # def test_decrypt_when_data_key_not_provided(self, mock_decrypt): - # mock_decrypt.return_value = _DATA_KEY - # test_raw_aes_keyring = RawAESKeyring( - # key_namespace=_PROVIDER_ID, - # key_name=_KEY_ID, - # wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, - # wrapping_key=_WRAPPING_KEY, - # ) - # - # test = test_raw_aes_keyring.on_decrypt(decryption_materials=_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\x7f.}\x87\x16,\x11n#\xc8p" - # b"\xdb\xbf\x94\x86*Q\x06\xd2\xf5\xdah\x08\xa4p\x81\xf7\xf4G\ - # x07FzE\xde", - # ) - # ] - # ) - # assert mock_decrypt.called + assert exc_info.match("At least one of public key or private key must be provided.") + + +@patch("aws_encryption_sdk.keyring.raw_keyring.generate_data_key") +def test_on_encrypt_when_data_encryption_key_given(mock_generate_data_key): + mock_generate_data_key.return_value = _DATA_KEY + test_raw_rsa_keyring = 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()) + ) + + test = test_raw_rsa_keyring.on_encrypt(encryption_materials=_ENCRYPTION_MATERIALS_WITH_DATA_KEY) + # Check if keyring is generated + assert not mock_generate_data_key.called + + +def test_keyring_trace_on_encrypt_when_data_encryption_key_given(): + test_raw_rsa_keyring = 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()), + ) + + test = test_raw_rsa_keyring.on_encrypt(encryption_materials=_ENCRYPTION_MATERIALS_WITH_DATA_KEY) + + for keyring_trace in test.keyring_trace: + if keyring_trace.wrapping_key.key_info == _KEY_ID: + # Check keyring trace does not contain KeyringTraceFlag.WRAPPING_KEY_GENERATED_DATA_KEY + assert KeyringTraceFlag.WRAPPING_KEY_GENERATED_DATA_KEY not in keyring_trace.flags + + +def test_on_encrypt_when_data_encryption_key_not_given(): + test_raw_rsa_keyring = 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()), + ) + + original_number_of_encrypted_data_keys = len(_ENCRYPTION_MATERIALS_WITHOUT_DATA_KEY.encrypted_data_keys) + + test = test_raw_rsa_keyring.on_encrypt(encryption_materials=_ENCRYPTION_MATERIALS_WITHOUT_DATA_KEY) + + # Check if data key is generated + assert test.data_encryption_key and test.data_encryption_key is not None + + generated_flag_count = 0 + encrypted_flag_count = 0 + + for keyring_trace in test.keyring_trace: + if keyring_trace.wrapping_key.key_info == _KEY_ID and KeyringTraceFlag.WRAPPING_KEY_GENERATED_DATA_KEY \ + in keyring_trace.flags: + # Check keyring trace contains KeyringTraceFlag.WRAPPING_KEY_GENERATED_DATA_KEY + generated_flag_count += 1 + if KeyringTraceFlag.WRAPPING_KEY_ENCRYPTED_DATA_KEY in keyring_trace.flags: + encrypted_flag_count += 1 + + assert generated_flag_count == 1 + + assert len(test.encrypted_data_keys) == original_number_of_encrypted_data_keys + 1 + + assert encrypted_flag_count == 1 + + +# @patch("aws_encryption_sdk.internal.crypto.wrapping_keys.WrappingKey.decrypt") +# def test_on_decrypt_when_data_key_given(mock_decrypt): +# mock_decrypt.return_value = _DATA_KEY +# test_raw_rsa_keyring = 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()), +# ) +# test = test_raw_rsa_keyring.on_decrypt( +# decryption_materials=_DECRYPTION_MATERIALS_WITH_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\x7f.}\x87\x16,\x11n#\xc8p" +# b"\xdb\xbf\x94\x86*Q\x06\xd2\xf5\xdah\x08\xa4p\x81\xf7\xf4G\ +# x07FzE\xde", +# ) +# ] +# ) +# assert not mock_decrypt.called +# +# +# def test_keyring_trace_on_decrypt_when_data_key_given(): +# test_raw_rsa_keyring = 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()), +# ) +# test = test_raw_rsa_keyring.on_decrypt( +# decryption_materials=_DECRYPTION_MATERIALS_WITH_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\x7f.}\x87\x16,\x11n#\xc8p" +# b"\xdb\xbf\x94\x86*Q\x06\xd2\xf5\xdah\x08\xa4p\x81\xf7\xf4G\ +# x07FzE\xde", +# ) +# ] +# ) +# for keyring_trace in test.keyring_trace: +# if keyring_trace.wrapping_key.key_info == _KEY_ID: +# # Check keyring trace does not contain KeyringTraceFlag.WRAPPING_KEY_DECRYPTED_DATA_KEY +# assert KeyringTraceFlag.WRAPPING_KEY_DECRYPTED_DATA_KEY not in keyring_trace.flags +# +# +# @patch("aws_encryption_sdk.internal.crypto.wrapping_keys.WrappingKey.decrypt") +# def test_on_decrypt_when_data_key_and_edk_not_provided(mock_decrypt): +# mock_decrypt.return_value = _DATA_KEY +# test_raw_rsa_keyring = 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()), +# ) +# +# test = test_raw_rsa_keyring.on_decrypt(decryption_materials=_DECRYPTION_MATERIALS_WITHOUT_DATA_KEY, +# encrypted_data_keys=[]) +# assert not mock_decrypt.called +# +# for keyring_trace in test.keyring_trace: +# if keyring_trace.wrapping_key.key_info == _KEY_ID: +# assert KeyringTraceFlag.WRAPPING_KEY_DECRYPTED_DATA_KEY not in keyring_trace.flags +# +# assert test.data_encryption_key is None +# +# +# @patch("aws_encryption_sdk.internal.crypto.wrapping_keys.WrappingKey.decrypt") +# def test_on_decrypt_when_data_key_not_provided_and_edk_not_in_keyring(mock_decrypt): +# mock_decrypt.return_value = _DATA_KEY +# test_raw_rsa_keyring = 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()), +# ) +# +# test = test_raw_rsa_keyring.on_decrypt(decryption_materials=_DECRYPTION_MATERIALS_WITHOUT_DATA_KEY, +# encrypted_data_keys=[ +# EncryptedDataKey( +# key_provider=MasterKeyInfo( +# provider_id=_PROVIDER_ID, +# key_info=b"5430b043-5843-4629-869c-64794af77ada"), +# 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", +# ) +# ] +# ) +# assert not mock_decrypt.called +# +# for keyring_trace in test.keyring_trace: +# if keyring_trace.wrapping_key.key_info == _KEY_ID: +# assert KeyringTraceFlag.WRAPPING_KEY_DECRYPTED_DATA_KEY not in keyring_trace.flags +# +# assert test.data_encryption_key is None +# +# +# @patch("aws_encryption_sdk.internal.crypto.wrapping_keys.WrappingKey.decrypt") +# def test_on_decrypt_when_data_key_not_provided_and_edk_provided(mock_decrypt): +# mock_decrypt.return_value = _DATA_KEY +# test_raw_rsa_keyring = 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()), +# ) +# +# test = test_raw_rsa_keyring.on_decrypt(decryption_materials=_DECRYPTION_MATERIALS_WITHOUT_DATA_KEY, +# encrypted_data_keys=[_ENCRYPTED_DATA_KEY_RSA] +# ) +# assert mock_decrypt.called_once_with(encrypted_wrapped_data_key=_ENCRYPTED_DATA_KEY_RSA, +# encryption_context=_ENCRYPTION_CONTEXT +# ) +# +# +# def test_keyring_trace_when_data_key_not_provided_and_edk_provided(): +# test_raw_rsa_keyring = 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()), +# ) +# +# test = test_raw_rsa_keyring.on_decrypt(decryption_materials=_DECRYPTION_MATERIALS_WITHOUT_DATA_KEY, +# encrypted_data_keys=[_ENCRYPTED_DATA_KEY_RSA] +# ) +# decrypted_flag_count = 0 +# +# for keyring_trace in test.keyring_trace: +# if KeyringTraceFlag.WRAPPING_KEY_DECRYPTED_DATA_KEY in keyring_trace.flags: +# decrypted_flag_count += 1 +# +# assert decrypted_flag_count == 1 +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# # @patch("aws_encryption_sdk.keyring.raw_keyring.generate_data_key") +# # def test_data_encryption_key_provided(self, mock_generate_data_key): +# # mock_generate_data_key.return_value = _DATA_KEY +# # test_raw_rsa_keyring = RawRSAKeyring( +# # key_namespace=_PROVIDER_ID, +# # key_name=_KEY_ID, +# # wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, +# # private_wrapping_key=_WRAPPING_KEY, +# # ) +# # +# # test = test_raw_rsa_keyring.on_encrypt(encryption_materials=_ENCRYPTION_MATERIALS_WITH_DATA_KEY) +# # # Check if keyring is generated +# # assert not mock_generate_data_key.called +# # +# # # Check if data encryption key is encrypted +# # assert test.encrypted_data_keys is not None +# # +# # def test_data_encryption_key_generated(self): +# # test_raw_rsa_keyring = RawRSAKeyring( +# # key_namespace=_PROVIDER_ID, +# # key_name=_KEY_ID, +# # wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, +# # private_wrapping_key=_WRAPPING_KEY, +# # ) +# # test = test_raw_rsa_keyring.on_encrypt(encryption_materials=_ENCRYPTION_MATERIALS_WITHOUT_DATA_KEY) +# # +# # # Check if key is generated +# # if not test.data_encryption_key: +# # # Check if error thrown if data key is not generated +# # assert pytest.raises(GenerateKeyError, "Unable to generate data encryption key.") +# # else: +# # # Check if data key is generated +# # assert test.data_encryption_key and test.data_encryption_key is not None +# # assert test.encrypted_data_keys and test.encrypted_data_keys is not None +# # +# # @patch("aws_encryption_sdk.keyring.raw_keyring.generate_data_key") +# # def test_encrypted_data_key_provided(self, mock_generate_data_key): +# # mock_generate_data_key.return_value = _DATA_KEY +# # test_raw_rsa_keyring = RawRSAKeyring( +# # key_namespace=_PROVIDER_ID, +# # key_name=_KEY_ID, +# # wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, +# # private_wrapping_key=_WRAPPING_KEY, +# # ) +# # test = test_raw_rsa_keyring.on_encrypt(encryption_materials=_ENCRYPTION_MATERIALS_WITH_ENCRYPTED_DATA_KEY) +# # +# # # Check if generate_data_key is called +# # assert not mock_generate_data_key.called +# # # +# # # Check if encrypt is called +# # assert len(test.encrypted_data_keys) == len(_ENCRYPTION_MATERIALS_WITH_ENCRYPTED_DATA_KEY.encrypted_data_keys) +# # +# # # @patch("aws_encryption_sdk.key_providers.raw.os.urandom") +# # # def test_data_key_not_generated(self, mock_os_urandom): +# # # mock_os_urandom.return_value = None +# # # test_raw_aes_keyring = RawAESKeyring( +# # # key_namespace=_PROVIDER_ID, +# # # key_name=_KEY_ID, +# # # wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, +# # # wrapping_key=_WRAPPING_KEY, +# # # ) +# # # test = test_raw_aes_keyring.on_encrypt(encryption_materials=_ENCRYPTION_MATERIALS_WITHOUT_DATA_KEY) +# # # assert pytest.raises(GenerateKeyError, "Unable to generate data encryption key.") +# # +# # @patch("aws_encryption_sdk.keyring.raw_keyring.generate_data_key") +# # def test_data_key_not_generated(self, mock_generate_data_key): +# # mock_generate_data_key.return_value = None +# # test_raw_rsa_keyring = RawRSAKeyring( +# # key_namespace=_PROVIDER_ID, +# # key_name=_KEY_ID, +# # wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, +# # private_wrapping_key=_WRAPPING_KEY, +# # ) +# # test = test_raw_rsa_keyring.on_encrypt(encryption_materials=_ENCRYPTION_MATERIALS_WITHOUT_DATA_KEY) +# # assert pytest.raises(GenerateKeyError) +# # +# # @patch("aws_encryption_sdk.internal.crypto.wrapping_keys.WrappingKey.decrypt") +# # def test_decrypt_when_data_key_provided(self, mock_decrypt): +# # mock_decrypt.return_value = _DATA_KEY +# # test_raw_rsa_keyring = RawRSAKeyring( +# # key_namespace=_PROVIDER_ID, +# # key_name=_KEY_ID, +# # wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, +# # private_wrapping_key=_WRAPPING_KEY, +# # ) +# # test = test_raw_rsa_keyring.on_decrypt( +# # decryption_materials=_DECRYPTION_MATERIALS_WITH_DATA_KEY, encrypted_data_keys=[self.mock_encrypted_data_key] +# # ) +# # assert not mock_decrypt.called +# # +# # # @patch("aws_encryption_sdk.internal.crypto.wrapping_keys.WrappingKey.decrypt") +# # # def test_decrypt_when_data_key_not_provided(self, mock_decrypt): +# # # mock_decrypt.return_value = _DATA_KEY +# # # test_raw_aes_keyring = RawAESKeyring( +# # # key_namespace=_PROVIDER_ID, +# # # key_name=_KEY_ID, +# # # wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, +# # # wrapping_key=_WRAPPING_KEY, +# # # ) +# # # +# # # test = test_raw_aes_keyring.on_decrypt(decryption_materials=_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\x7f.}\x87\x16,\x11n#\xc8p" +# # # b"\xdb\xbf\x94\x86*Q\x06\xd2\xf5\xdah\x08\xa4p\x81\xf7\xf4G\ +# # # x07FzE\xde", +# # # ) +# # # ] +# # # ) +# # # assert mock_decrypt.called diff --git a/test/unit/test_utils.py b/test/unit/test_utils.py index d448a4da7..e0b5271c9 100644 --- a/test/unit/test_utils.py +++ b/test/unit/test_utils.py @@ -21,21 +21,197 @@ 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.keyring.base import Keyring +from aws_encryption_sdk.identifiers import Algorithm, KeyringTraceFlag +from aws_encryption_sdk.keyring.base import EncryptedDataKey, Keyring from aws_encryption_sdk.materials_managers import DecryptionMaterials, EncryptionMaterials -from aws_encryption_sdk.structures import DataKey, EncryptedDataKey, MasterKeyInfo, RawDataKey +from aws_encryption_sdk.structures import KeyringTrace, MasterKeyInfo, RawDataKey, DataKey from .test_values import VALUES from .unit_test_utils import assert_prepped_stream_identity 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 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" +) +_ENCRYPTED_DATA_KEY_AES = EncryptedDataKey( + key_provider=MasterKeyInfo( + provider_id='Random Raw Keys', + key_info=b'5325b043-5843-4629-869c-64794af77ada\x00\x00\x00\x80' + b'\x00\x00\x00\x0c\xc7\xd5d\xc9\xc5\xf21\x8d\x8b\xf9H' + b'\xbb'), + encrypted_data_key=b'\xf3+\x15n\xe6`\xbe\xfe\xf0\x9e1\xe5\x9b' + b'\xaf\xfe\xdaT\xbb\x17\x14\xfd} o\xdd\xf1' + b'\xbc\xe1C\xa5J\xd8\xc7\x15\xc2\x90t=\xb9' + b'\xfd;\x94lTu/6\xfe' + +) + +_ENCRYPTED_DATA_KEY_RSA = EncryptedDataKey( + key_provider=MasterKeyInfo( + provider_id='Random Raw Keys', + key_info=_KEY_ID), + encrypted_data_key=b'\xf3+\x15n\xe6`\xbe\xfe\xf0\x9e1\xe5\x9b' + b'\xaf\xfe\xdaT\xbb\x17\x14\xfd} o\xdd\xf1' + b'\xbc\xe1C\xa5J\xd8\xc7\x15\xc2\x90t=\xb9' + b'\xfd;\x94lTu/6\xfe' + +) + +# _ENCRYPTED_DATA_KEYS_RSA = [ +# EncryptedDataKey( +# key_provider=MasterKeyInfo( +# provider_id='Random Raw Keys', +# key_info=b'5325b043-5843-4629-869c-64794af77ada'), +# encrypted_data_key=b'd7\xc7 R\x0e\x91\x104\xadK\xcb}j\xa1e2\x86\xe1W\xac\xf2\xab\xfc\xe3@\x15\x18' +# b'\xc7\xef\x10a\xf4n1`\x11\x17\x85\x0c]X\x98\xac\xc8J\x9c\xc6\xbd}Y\xbaL\xb6' +# b'\xb1\xf1\xf1\n\xba\x1c\x03\xfbM\xebs\\&hW\x1b\xc8d\x1c\x81\xd2\xe0\xec\xdf' +# b'\xfe\xe1j\xf4\xcaHO\xe5`\x8c\xc74\x11Cc\xf9\xb1\xe9S\xa9*\xdbK+2\x12\xd2\xb0' +# b'\xc2\xdb2\xf1\xc2\xc65&\x96R\xdc\xfd\xf9\xafaE\x8c\xbc\x9f$E-R\xe6\xcd^\xf2w' +# b'\x87#\x02l\xf3|;\x90\x9ez\xbfA.\xe5\x1cB\xda+[\xf1.|\xf5s\xb9\nI\xc8\xab\xf4' +# b'\xee\x9f\x81\n*\xcd\xee\x975m\x85\xde-\xd59=\x87C\xfc\xe0\x8d\xaa\xc4\xdf\xb1#' +# b'\x95nm\x9dc}\x05\x0e"\x0c6^\xfd\xda\xc8q\x9b\x02\x1b\x12\xb4\xd0&\x85\xb1\xd1' +# b'\x97\x1f&sQ\x10]\x04\xb9o\x80\xb1\x81a\x86cI\xbd\xaaz\xf0\xfb\x1dB#zN\xa8\xba' +# b'\xc0]PsT\x08\xa4\x19\x16\xc4\xd9'), +# EncryptedDataKey( +# key_provider=MasterKeyInfo( +# provider_id='Random Raw Keys', +# key_info=b'5325b043-5843-4629-869c-64794af77ada'), +# encrypted_data_key=b'\xbbno\xb3C\xd2s\xd9\xa8\x92\xcb\xd2x\n#\x0e:j\x11\xf7\xf8\xb5+\xcf\x98\xea\xa2' +# b'\xdd\x8d\xf0\x0f\xca\xef\xdb\xb8\x03\xd9\xaf\x99\xca\xf1\x1c\xb2\xd6\x92\x9ch1m' +# b'\xa9!\x84\x90\xbe7RI\xdc.p\xe2\xdc\x0e\x8f\x1cl\xc8\x91\xf7HHR\x01\x9d\xdf\xbd' +# b'\x19\xbbt\xf7\x00\x13H\x024#\x18K\xf2qd\xef\x9a\x86\xac\x82\xe5rik\x9c\x8aI\xaf' +# b'\xf6f\xf6l\xe9\\\x08\xc0\x8fq\x17\xbf\x06\x0b\xa5\xe0\xf5\x97\xf4\xc8e\n6\x83' +# b'\x08J\xfb4)\x1a.\x1f6\xda\xb2\xc6n\xa9\xd2Fa\x19\x86\xa9qh\x8e\x97\x0e2\xba\xfd' +# b'\xe4:/\x91~H\x0b^\x91C\xc0\xc9\x0c`C\xebt\xd8\xec\xecZ\xf10\x80\xaa\xa1/\x18\xc0' +# b'\x923\xdc\x9e\xec<\xb3\x9f\xb7\x8b\xec\xc3\x8d\nb\x82\x84\xd0\x9b\xa3\x9f4\x84\x8c' +# b'\xa3v*v9d\xdb\xa6=\xc2\xfa\x88s\x8a\xa4\t)6\xe8\x08\x1dOj;\xd0\x1c0\xaf\x1e\x10\xaa' +# b'\x7f\x90\xff\x92\xac\xceIMs\xf6\xb0\xff+\xfdvf') +# +# , ] + +_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=b"5430b043-5843-4629-869c-64794af77ada"), + 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=b"5430b043-5843-4629-869c-64794af77ada"), + 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_AES = 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=[ + _ENCRYPTED_DATA_KEY_AES + ], + 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_WITH_ENCRYPTED_DATA_KEY_RSA = 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='Random Raw Keys', +# key_info=b'5325b043-5843-4629-869c-64794af77ada'), +# encrypted_data_key=b'd7\xc7 R\x0e\x91\x104\xadK\xcb}j\xa1e2\x86\xe1W\xac\xf2\xab\xfc\xe3@\x15\x18' +# b'\xc7\xef\x10a\xf4n1`\x11\x17\x85\x0c]X\x98\xac\xc8J\x9c\xc6\xbd}Y\xbaL\xb6' +# b'\xb1\xf1\xf1\n\xba\x1c\x03\xfbM\xebs\\&hW\x1b\xc8d\x1c\x81\xd2\xe0\xec\xdf' +# b'\xfe\xe1j\xf4\xcaHO\xe5`\x8c\xc74\x11Cc\xf9\xb1\xe9S\xa9*\xdbK+2\x12\xd2\xb0' +# b'\xc2\xdb2\xf1\xc2\xc65&\x96R\xdc\xfd\xf9\xafaE\x8c\xbc\x9f$E-R\xe6\xcd^\xf2w' +# b'\x87#\x02l\xf3|;\x90\x9ez\xbfA.\xe5\x1cB\xda+[\xf1.|\xf5s\xb9\nI\xc8\xab\xf4' +# b'\xee\x9f\x81\n*\xcd\xee\x975m\x85\xde-\xd59=\x87C\xfc\xe0\x8d\xaa\xc4\xdf\xb1#' +# b'\x95nm\x9dc}\x05\x0e"\x0c6^\xfd\xda\xc8q\x9b\x02\x1b\x12\xb4\xd0&\x85\xb1\xd1' +# b'\x97\x1f&sQ\x10]\x04\xb9o\x80\xb1\x81a\x86cI\xbd\xaaz\xf0\xfb\x1dB#zN\xa8\xba' +# b'\xc0]PsT\x08\xa4\x19\x16\xc4\xd9'), +# EncryptedDataKey( +# key_provider=MasterKeyInfo( +# provider_id='Random Raw Keys', +# key_info=b'5325b043-5843-4629-869c-64794af77ada'), +# encrypted_data_key=b'\xbbno\xb3C\xd2s\xd9\xa8\x92\xcb\xd2x\n#\x0e:j\x11\xf7\xf8\xb5+\xcf\x98\xea\xa2' +# b'\xdd\x8d\xf0\x0f\xca\xef\xdb\xb8\x03\xd9\xaf\x99\xca\xf1\x1c\xb2\xd6\x92\x9ch1m' +# b'\xa9!\x84\x90\xbe7RI\xdc.p\xe2\xdc\x0e\x8f\x1cl\xc8\x91\xf7HHR\x01\x9d\xdf\xbd' +# b'\x19\xbbt\xf7\x00\x13H\x024#\x18K\xf2qd\xef\x9a\x86\xac\x82\xe5rik\x9c\x8aI\xaf' +# b'\xf6f\xf6l\xe9\\\x08\xc0\x8fq\x17\xbf\x06\x0b\xa5\xe0\xf5\x97\xf4\xc8e\n6\x83' +# b'\x08J\xfb4)\x1a.\x1f6\xda\xb2\xc6n\xa9\xd2Fa\x19\x86\xa9qh\x8e\x97\x0e2\xba\xfd' +# b'\xe4:/\x91~H\x0b^\x91C\xc0\xc9\x0c`C\xebt\xd8\xec\xecZ\xf10\x80\xaa\xa1/\x18\xc0' +# b'\x923\xdc\x9e\xec<\xb3\x9f\xb7\x8b\xec\xc3\x8d\nb\x82\x84\xd0\x9b\xa3\x9f4\x84\x8c' +# b'\xa3v*v9d\xdb\xa6=\xc2\xfa\x88s\x8a\xa4\t)6\xe8\x08\x1dOj;\xd0\x1c0\xaf\x1e\x10\xaa' +# b'\x7f\x90\xff\x92\xac\xceIMs\xf6\xb0\xff+\xfdvf') +# +# , ], +# 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=b"5430b043-5843-4629-869c-64794af77ada"), + 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=b"5430b043-5843-4629-869c-64794af77ada"), + flags={KeyringTraceFlag.WRAPPING_KEY_DECRYPTED_DATA_KEY}, + ) + ], +) + +_DECRYPTION_MATERIALS_WITHOUT_DATA_KEY = DecryptionMaterials( + algorithm=Algorithm.AES_256_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384, + verification_key=b"ex_verification_key", + encryption_context=_ENCRYPTION_CONTEXT, +) + _RAW_RSA_PRIVATE_KEY_PEM_ENCODED = ( b"-----BEGIN RSA PRIVATE KEY-----\n" From 866755d65d7226bfeb3f1066b5f4928b2c5d3c85 Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Fri, 26 Jul 2019 14:34:46 -0700 Subject: [PATCH 104/119] All unit tests working --- test/functional/test_f_keyring_raw_aes.py | 20 +- test/functional/test_f_keyring_raw_rsa.py | 215 ++++++--- test/unit/test_keyring_raw_aes.py | 94 ++-- test/unit/test_keyring_raw_rsa.py | 555 ++++++++-------------- test/unit/test_utils.py | 138 +----- 5 files changed, 429 insertions(+), 593 deletions(-) diff --git a/test/functional/test_f_keyring_raw_aes.py b/test/functional/test_f_keyring_raw_aes.py index 699b594b6..0006fb408 100644 --- a/test/functional/test_f_keyring_raw_aes.py +++ b/test/functional/test_f_keyring_raw_aes.py @@ -18,6 +18,7 @@ from aws_encryption_sdk.keyring.raw_keyring import RawAESKeyring from aws_encryption_sdk.materials_managers import DecryptionMaterials, EncryptionMaterials from aws_encryption_sdk.structures import EncryptedDataKey, KeyringTrace, MasterKeyInfo, RawDataKey +from aws_encryption_sdk.key_providers.raw import RawMasterKeyProvider pytestmark = [pytest.mark.functional, pytest.mark.local] @@ -92,7 +93,7 @@ def test_raw_aes_encryption_decryption(encryption_materials_samples, wrapping_al _wrapping_algorithm = wrapping_algorithm_samples # Creating an instance of a raw AES keyring - sample_raw_aes_keyring = RawAESKeyring( + test_raw_aes_keyring = RawAESKeyring( key_namespace=key_namespace, key_name=key_name, wrapping_key=_WRAPPING_KEY, @@ -100,7 +101,7 @@ def test_raw_aes_encryption_decryption(encryption_materials_samples, wrapping_al ) # Call on_encrypt function for the keyring - encryption_materials = sample_raw_aes_keyring.on_encrypt(encryption_materials=encryption_materials_samples) + encryption_materials = test_raw_aes_keyring.on_encrypt(encryption_materials=encryption_materials_samples) print("PLAINTEXT DATA KEY") print(encryption_materials.data_encryption_key) @@ -113,9 +114,22 @@ def test_raw_aes_encryption_decryption(encryption_materials_samples, wrapping_al ) # Call on_decrypt function for the keyring - decryption_materials = sample_raw_aes_keyring.on_decrypt( + decryption_materials = test_raw_aes_keyring.on_decrypt( decryption_materials=decryption_materials, encrypted_data_keys=encryption_materials.encrypted_data_keys ) # Check if the data keys match assert encryption_materials.data_encryption_key.data_key == decryption_materials.data_encryption_key.data_key + + +def test_compatibility_with_raw_mkp(): + # Creating an instance of a raw AES keyring + test_raw_aes_keyring = RawAESKeyring( + key_namespace=key_namespace, + key_name=key_name, + wrapping_key=_WRAPPING_KEY, + wrapping_algorithm=WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING, + ) + test_raw_master_key_provider = RawMasterKeyProvider( + + ) \ No newline at end of file diff --git a/test/functional/test_f_keyring_raw_rsa.py b/test/functional/test_f_keyring_raw_rsa.py index 64e04dc88..eed07f6c2 100644 --- a/test/functional/test_f_keyring_raw_rsa.py +++ b/test/functional/test_f_keyring_raw_rsa.py @@ -15,6 +15,7 @@ import pytest from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives.asymmetric import rsa +from cryptography.hazmat.primitives import serialization from aws_encryption_sdk.identifiers import Algorithm, KeyringTraceFlag, WrappingAlgorithm from aws_encryption_sdk.keyring.raw_keyring import RawRSAKeyring @@ -28,37 +29,72 @@ _KEY_ID = b"5325b043-5843-4629-869c-64794af77ada" _SIGNING_KEY = b"aws-crypto-public-key" _WRAPPING_ALGORITHM = WrappingAlgorithm.RSA_OAEP_SHA256_MGF1 +# +# _PUBLIC_KEY = ( +# b"-----BEGIN PUBLIC KEY-----\n" +# b"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCOCigedc4PMp2sopCpJSqRNQla\n" +# b"KHuk2WBuNVfU3Z5oSwleZs63t/7PrKWWaVPsPfVxzAW2GK/h74KlIaN/T93W0o8Q\n" +# b"hsm6cMnRobaGYLro0hmy1VyiNrLE7JAOXhExdYJuL9fhK7VnYYxEDWa7K8xbdnCp\n" +# b"myFdLqOWTeSou6eF6wIDAQAB\n" +# b"-----END PUBLIC KEY-----\n" +# ) +_PUBLIC_EXPONENT = 65537 +_KEY_SIZE = 2048 +_BACKEND = default_backend() + +_RAW_RSA_PRIVATE_KEY_PEM_ENCODED_WITHOUT_PASSWORD = rsa.generate_private_key(public_exponent=_PUBLIC_EXPONENT, + key_size=_KEY_SIZE, + backend=_BACKEND).private_bytes( + encoding=serialization.Encoding.PEM, + format=serialization.PrivateFormat.TraditionalOpenSSL, + encryption_algorithm=serialization.NoEncryption() +) + +_RAW_RSA_PRIVATE_KEY_PEM_ENCODED_WITH_PASSWORD = rsa.generate_private_key(public_exponent=_PUBLIC_EXPONENT, + key_size=_KEY_SIZE, + backend=_BACKEND).private_bytes( + encoding=serialization.Encoding.PEM, + format=serialization.PrivateFormat.PKCS8, + encryption_algorithm=serialization.BestAvailableEncryption(b'mypassword') +) + +_RAW_RSA_PUBLIC_KEY_PEM_ENCODED = rsa.generate_private_key(public_exponent=_PUBLIC_EXPONENT, + key_size=_KEY_SIZE, + backend=_BACKEND).public_key().public_bytes( + encoding=serialization.Encoding.PEM, + format=serialization.PublicFormat.SubjectPublicKeyInfo, +) -_PRIVATE_KEY = ( - 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" +_RAW_RSA_PRIVATE_KEY_DER_ENCODED_WITHOUT_PASSWORD = rsa.generate_private_key(public_exponent=_PUBLIC_EXPONENT, + key_size=_KEY_SIZE, + backend=_BACKEND).private_bytes( + encoding=serialization.Encoding.DER, + format=serialization.PrivateFormat.TraditionalOpenSSL, + encryption_algorithm=serialization.NoEncryption() ) +_RAW_RSA_PRIVATE_KEY_DER_ENCODED_WITH_PASSWORD = rsa.generate_private_key(public_exponent=_PUBLIC_EXPONENT, + key_size=_KEY_SIZE, + backend=_BACKEND).private_bytes( + encoding=serialization.Encoding.DER, + format=serialization.PrivateFormat.PKCS8, + encryption_algorithm=serialization.BestAvailableEncryption(b'mypassword') +) + +_RAW_RSA_PUBLIC_KEY_DER_ENCODED = rsa.generate_private_key(public_exponent=_PUBLIC_EXPONENT, + key_size=_KEY_SIZE, + backend=_BACKEND).public_key().public_bytes( + encoding=serialization.Encoding.DER, + format=serialization.PublicFormat.SubjectPublicKeyInfo, +) + +# _WRAPPING_ALGORITHMS = [ +# WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, +# WrappingAlgorithm.RSA_OAEP_SHA1_MGF1, +# WrappingAlgorithm.RSA_OAEP_SHA384_MGF1, +# WrappingAlgorithm.RSA_OAEP_SHA512_MGF1, +# WrappingAlgorithm.RSA_PKCS1 +# ] _ENCRYPTION_MATERIALS = [ EncryptionMaterials( @@ -109,61 +145,99 @@ ] _RAW_RSA_KEYRINGS = [ + RawRSAKeyring( key_namespace=_PROVIDER_ID, key_name=_KEY_ID, wrapping_algorithm=_WRAPPING_ALGORITHM, - 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=_PUBLIC_EXPONENT, + key_size=_KEY_SIZE, + backend=_BACKEND), + ), + RawRSAKeyring( + key_namespace=_PROVIDER_ID, + key_name=_KEY_ID, + wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA1_MGF1, + private_wrapping_key=rsa.generate_private_key(public_exponent=_PUBLIC_EXPONENT, + key_size=_KEY_SIZE, backend=_BACKEND), + ), + RawRSAKeyring( + key_namespace=_PROVIDER_ID, + key_name=_KEY_ID, + wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA384_MGF1, + private_wrapping_key=rsa.generate_private_key(public_exponent=_PUBLIC_EXPONENT, + key_size=_KEY_SIZE, backend=_BACKEND), + ), + RawRSAKeyring( + key_namespace=_PROVIDER_ID, + key_name=_KEY_ID, + wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA512_MGF1, + private_wrapping_key=rsa.generate_private_key(public_exponent=_PUBLIC_EXPONENT, + key_size=_KEY_SIZE, backend=_BACKEND), + ), + RawRSAKeyring( + key_namespace=_PROVIDER_ID, + key_name=_KEY_ID, + wrapping_algorithm=WrappingAlgorithm.RSA_PKCS1, + private_wrapping_key=rsa.generate_private_key(public_exponent=_PUBLIC_EXPONENT, + key_size=_KEY_SIZE, backend=_BACKEND), + ), + + + + RawRSAKeyring.fromPEMEncoding( + key_namespace=_PROVIDER_ID, + key_name=_KEY_ID, + private_encoded_key=_RAW_RSA_PRIVATE_KEY_PEM_ENCODED_WITHOUT_PASSWORD, + wrapping_algorithm=_WRAPPING_ALGORITHM, ), RawRSAKeyring.fromPEMEncoding( key_namespace=_PROVIDER_ID, key_name=_KEY_ID, - private_encoded_key=_PRIVATE_KEY, - password=None, + private_encoded_key=_RAW_RSA_PRIVATE_KEY_PEM_ENCODED_WITH_PASSWORD, + password=b'mypassword', + wrapping_algorithm=_WRAPPING_ALGORITHM, + ), + RawRSAKeyring.fromPEMEncoding( + key_namespace=_PROVIDER_ID, + key_name=_KEY_ID, + public_encoded_key=_RAW_RSA_PUBLIC_KEY_PEM_ENCODED, + wrapping_algorithm=_WRAPPING_ALGORITHM, + ), + + + + RawRSAKeyring.fromDEREncoding( + key_namespace=_PROVIDER_ID, + key_name=_KEY_ID, + private_encoded_key=_RAW_RSA_PRIVATE_KEY_DER_ENCODED_WITHOUT_PASSWORD, + wrapping_algorithm=_WRAPPING_ALGORITHM, + ), + RawRSAKeyring.fromDEREncoding( + key_namespace=_PROVIDER_ID, + key_name=_KEY_ID, + private_encoded_key=_RAW_RSA_PRIVATE_KEY_DER_ENCODED_WITH_PASSWORD, + password=b'mypassword', + wrapping_algorithm=_WRAPPING_ALGORITHM, + ), + RawRSAKeyring.fromDEREncoding( + key_namespace=_PROVIDER_ID, + key_name=_KEY_ID, + public_encoded_key=_RAW_RSA_PUBLIC_KEY_DER_ENCODED, + password=b'mypassword', wrapping_algorithm=_WRAPPING_ALGORITHM, ), - # RawRSAKeyring.fromDEREncoding( - # key_namespace=_PROVIDER_ID, - # key_name=_KEY_ID, - # encoded_key=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", - # password=None, - # wrapping_algorithm=_WRAPPING_ALGORITHM, - # ) ] @pytest.mark.parametrize("encryption_materials_samples", _ENCRYPTION_MATERIALS) -@pytest.mark.parametrize("fake_raw_rsa_keyring", _RAW_RSA_KEYRINGS) -def test_raw_rsa_encryption_decryption(encryption_materials_samples, fake_raw_rsa_keyring): +@pytest.mark.parametrize("test_raw_rsa_keyring", _RAW_RSA_KEYRINGS) +def test_raw_rsa_encryption_decryption(encryption_materials_samples, test_raw_rsa_keyring): # Call on_encrypt function for the keyring - encryption_materials = fake_raw_rsa_keyring.on_encrypt(encryption_materials=encryption_materials_samples) + encryption_materials = test_raw_rsa_keyring.on_encrypt(encryption_materials=encryption_materials_samples) + + assert encryption_materials.encrypted_data_keys is not None # Generate decryption materials decryption_materials = DecryptionMaterials( @@ -171,9 +245,10 @@ def test_raw_rsa_encryption_decryption(encryption_materials_samples, fake_raw_rs ) # Call on_decrypt function for the keyring - decryption_materials = fake_raw_rsa_keyring.on_decrypt( + decryption_materials = test_raw_rsa_keyring.on_decrypt( decryption_materials=decryption_materials, encrypted_data_keys=encryption_materials.encrypted_data_keys ) - # Check if the data keys match - assert encryption_materials.data_encryption_key.data_key == decryption_materials.data_encryption_key.data_key + if test_raw_rsa_keyring._private_wrapping_key is not None: + # Check if the data keys match + assert encryption_materials.data_encryption_key.data_key == decryption_materials.data_encryption_key.data_key diff --git a/test/unit/test_keyring_raw_aes.py b/test/unit/test_keyring_raw_aes.py index 8f6e32605..b0eea4508 100644 --- a/test/unit/test_keyring_raw_aes.py +++ b/test/unit/test_keyring_raw_aes.py @@ -13,16 +13,23 @@ """Unit tests for Raw AES keyring.""" import pytest -from mock import MagicMock, patch, sentinel, Mock +import os from aws_encryption_sdk.identifiers import KeyringTraceFlag, WrappingAlgorithm, Algorithm from aws_encryption_sdk.keyring.base import EncryptedDataKey, Keyring from aws_encryption_sdk.keyring.raw_keyring import RawAESKeyring, generate_data_key, GenerateKeyError from aws_encryption_sdk.structures import MasterKeyInfo from aws_encryption_sdk.materials_managers import EncryptionMaterials -from .test_utils import _ENCRYPTION_MATERIALS_WITHOUT_DATA_KEY, _ENCRYPTION_MATERIALS_WITH_DATA_KEY, _PROVIDER_ID, \ - _WRAPPING_KEY, _DATA_KEY, _KEY_ID, _DECRYPTION_MATERIALS_WITH_DATA_KEY, _DECRYPTION_MATERIALS_WITHOUT_DATA_KEY, \ - _ENCRYPTION_CONTEXT, _ENCRYPTED_DATA_KEY_AES, _SIGNING_KEY + +from .test_utils import _ENCRYPTION_MATERIALS_WITH_DATA_KEY, _PROVIDER_ID, _WRAPPING_KEY, _DATA_KEY, _KEY_ID, \ + _DECRYPTION_MATERIALS_WITH_DATA_KEY, _ENCRYPTION_CONTEXT, _ENCRYPTED_DATA_KEY_AES, _SIGNING_KEY, \ + _DECRYPTION_MATERIALS_WITHOUT_DATA_KEY, _ENCRYPTION_MATERIALS_WITHOUT_DATA_KEY + +import aws_encryption_sdk.keyring.raw_keyring +import aws_encryption_sdk.key_providers.raw +from aws_encryption_sdk.internal.crypto.wrapping_keys import WrappingKey +from pytest_mock import mocker # noqa pylint: disable=unused-import + try: # Python 3.5.0 and 3.5.1 have incompatible typing modules from typing import Iterable # noqa pylint: disable=unused-import @@ -33,6 +40,24 @@ pytestmark = [pytest.mark.unit, pytest.mark.local] +@pytest.fixture +def patch_generate_data_key(mocker): + mocker.patch.object(aws_encryption_sdk.keyring.raw_keyring, "generate_data_key") + return aws_encryption_sdk.keyring.raw_keyring.generate_data_key + + +@pytest.fixture +def patch_decrypt_data_key(mocker): + mocker.patch.object(WrappingKey, "decrypt") + return WrappingKey.decrypt + + +@pytest.fixture +def patch_os_urandom(mocker): + mocker.patch.object(os, "urandom") + return os.urandom + + def test_parent(): assert issubclass(RawAESKeyring, Keyring) @@ -70,9 +95,7 @@ def test_invalid_values_as_parameter(): assert exc_info.errisinstance(TypeError) -@patch("aws_encryption_sdk.keyring.raw_keyring.generate_data_key") -def test_on_encrypt_when_data_encryption_key_given(mock_generate_data_key): - mock_generate_data_key.return_value = _DATA_KEY +def test_on_encrypt_when_data_encryption_key_given(patch_generate_data_key): test_raw_aes_keyring = RawAESKeyring( key_namespace=_PROVIDER_ID, key_name=_KEY_ID, @@ -82,7 +105,7 @@ def test_on_encrypt_when_data_encryption_key_given(mock_generate_data_key): test = test_raw_aes_keyring.on_encrypt(encryption_materials=_ENCRYPTION_MATERIALS_WITH_DATA_KEY) # Check if keyring is generated - assert not mock_generate_data_key.called + assert not patch_generate_data_key.called def test_keyring_trace_on_encrypt_when_data_encryption_key_given(): @@ -102,6 +125,7 @@ def test_keyring_trace_on_encrypt_when_data_encryption_key_given(): def test_on_encrypt_when_data_encryption_key_not_given(): + test_raw_aes_keyring = RawAESKeyring( key_namespace=_PROVIDER_ID, key_name=_KEY_ID, @@ -134,9 +158,7 @@ def test_on_encrypt_when_data_encryption_key_not_given(): assert encrypted_flag_count == 1 -@patch("aws_encryption_sdk.internal.crypto.wrapping_keys.WrappingKey.decrypt") -def test_on_decrypt_when_data_key_given(mock_decrypt): - mock_decrypt.return_value = _DATA_KEY +def test_on_decrypt_when_data_key_given(patch_decrypt_data_key): test_raw_aes_keyring = RawAESKeyring( key_namespace=_PROVIDER_ID, key_name=_KEY_ID, @@ -156,7 +178,7 @@ def test_on_decrypt_when_data_key_given(mock_decrypt): ) ] ) - assert not mock_decrypt.called + assert not patch_decrypt_data_key.called def test_keyring_trace_on_decrypt_when_data_key_given(): @@ -185,9 +207,7 @@ def test_keyring_trace_on_decrypt_when_data_key_given(): assert KeyringTraceFlag.WRAPPING_KEY_DECRYPTED_DATA_KEY not in keyring_trace.flags -@patch("aws_encryption_sdk.internal.crypto.wrapping_keys.WrappingKey.decrypt") -def test_on_decrypt_when_data_key_and_edk_not_provided(mock_decrypt): - mock_decrypt.return_value = _DATA_KEY +def test_on_decrypt_when_data_key_and_edk_not_provided(patch_decrypt_data_key): test_raw_aes_keyring = RawAESKeyring( key_namespace=_PROVIDER_ID, key_name=_KEY_ID, @@ -197,7 +217,7 @@ def test_on_decrypt_when_data_key_and_edk_not_provided(mock_decrypt): test = test_raw_aes_keyring.on_decrypt(decryption_materials=_DECRYPTION_MATERIALS_WITHOUT_DATA_KEY, encrypted_data_keys=[]) - assert not mock_decrypt.called + assert not patch_decrypt_data_key.called for keyring_trace in test.keyring_trace: if keyring_trace.wrapping_key.key_info == _KEY_ID: @@ -206,9 +226,7 @@ def test_on_decrypt_when_data_key_and_edk_not_provided(mock_decrypt): assert test.data_encryption_key is None -@patch("aws_encryption_sdk.internal.crypto.wrapping_keys.WrappingKey.decrypt") -def test_on_decrypt_when_data_key_not_provided_and_edk_not_in_keyring(mock_decrypt): - mock_decrypt.return_value = _DATA_KEY +def test_on_decrypt_when_data_key_not_provided_and_edk_not_in_keyring(patch_decrypt_data_key): test_raw_aes_keyring = RawAESKeyring( key_namespace=_PROVIDER_ID, key_name=_KEY_ID, @@ -230,7 +248,7 @@ def test_on_decrypt_when_data_key_not_provided_and_edk_not_in_keyring(mock_decry ) ] ) - assert not mock_decrypt.called + assert not patch_decrypt_data_key.called for keyring_trace in test.keyring_trace: if keyring_trace.wrapping_key.key_info == _KEY_ID: @@ -239,9 +257,8 @@ def test_on_decrypt_when_data_key_not_provided_and_edk_not_in_keyring(mock_decry assert test.data_encryption_key is None -@patch("aws_encryption_sdk.internal.crypto.wrapping_keys.WrappingKey.decrypt") -def test_on_decrypt_when_data_key_not_provided_and_edk_provided(mock_decrypt): - mock_decrypt.return_value = _DATA_KEY +def test_on_decrypt_when_data_key_not_provided_and_edk_provided(patch_decrypt_data_key): + patch_decrypt_data_key.return_value = _DATA_KEY test_raw_aes_keyring = RawAESKeyring( key_namespace=_PROVIDER_ID, key_name=_KEY_ID, @@ -252,9 +269,9 @@ def test_on_decrypt_when_data_key_not_provided_and_edk_provided(mock_decrypt): test = test_raw_aes_keyring.on_decrypt(decryption_materials=_DECRYPTION_MATERIALS_WITHOUT_DATA_KEY, encrypted_data_keys=[_ENCRYPTED_DATA_KEY_AES] ) - assert mock_decrypt.called_once_with(encrypted_wrapped_data_key=_ENCRYPTED_DATA_KEY_AES, - encryption_context=_ENCRYPTION_CONTEXT - ) + assert patch_decrypt_data_key.called_once_with(encrypted_wrapped_data_key=_ENCRYPTED_DATA_KEY_AES, + encryption_context=_ENCRYPTION_CONTEXT + ) def test_keyring_trace_when_data_key_not_provided_and_edk_provided(): @@ -277,23 +294,22 @@ def test_keyring_trace_when_data_key_not_provided_and_edk_provided(): assert decrypted_flag_count == 1 -# @patch("aws_encryption_sdk.key_providers.raw.os.urandom") -# def test_error_when_data_key_not_generated(mock_os_urandom): -# mock_os_urandom.side_effect = Exception() -# test_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, -# ) -# with pytest.raises(GenerateKeyError) as exc_info: -# test_raw_aes_keyring.on_encrypt(encryption_materials=_ENCRYPTION_MATERIALS_WITHOUT_DATA_KEY) -# assert exc_info.match("Unable to generate data encryption key.") +def test_error_when_data_key_not_generated(patch_os_urandom): + patch_os_urandom.side_effect = NotImplementedError + with pytest.raises(GenerateKeyError) as exc_info: + generate_data_key(encryption_materials=EncryptionMaterials( + algorithm=Algorithm.AES_256_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384, + encryption_context=_ENCRYPTION_CONTEXT, + signing_key=_SIGNING_KEY, + ), + key_provider=MasterKeyInfo(provider_id=_PROVIDER_ID, + key_info=_KEY_ID)) + assert exc_info.match("Unable to generate data encryption key.") def test_generate_data_key_error_when_data_key_exists(): with pytest.raises(TypeError) as exc_info: - generate_data_key(encryption_materials=_ENCRYPTION_MATERIALS_WITHOUT_DATA_KEY, + generate_data_key(encryption_materials=_ENCRYPTION_MATERIALS_WITH_DATA_KEY, key_provider=MasterKeyInfo( provider_id=_PROVIDER_ID, key_info=_KEY_ID diff --git a/test/unit/test_keyring_raw_rsa.py b/test/unit/test_keyring_raw_rsa.py index 50c2f43f1..523f86126 100644 --- a/test/unit/test_keyring_raw_rsa.py +++ b/test/unit/test_keyring_raw_rsa.py @@ -13,18 +13,21 @@ """Unit tests for Raw AES keyring.""" import pytest -from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives.asymmetric import rsa -from mock import MagicMock, patch, sentinel from aws_encryption_sdk.identifiers import Algorithm, KeyringTraceFlag, WrappingAlgorithm from aws_encryption_sdk.keyring.base import EncryptedDataKey, Keyring from aws_encryption_sdk.keyring.raw_keyring import RawRSAKeyring from aws_encryption_sdk.materials_managers import DecryptionMaterials, EncryptionMaterials -from aws_encryption_sdk.structures import KeyringTrace, MasterKeyInfo, RawDataKey -from .test_utils import _KEY_ID, _ENCRYPTION_CONTEXT, _SIGNING_KEY, _DATA_KEY, _PROVIDER_ID, _ENCRYPTED_DATA_KEY_RSA - # _ENCRYPTION_MATERIALS_WITHOUT_DATA_KEY, _ENCRYPTION_MATERIALS_WITH_DATA_KEY, _DECRYPTION_MATERIALS_WITHOUT_DATA_KEY,\ - # _DECRYPTION_MATERIALS_WITH_DATA_KEY, _ENCRYPTED_DATA_KEY_RSA +from aws_encryption_sdk.structures import MasterKeyInfo +from .test_utils import _KEY_ID, _ENCRYPTION_CONTEXT, _SIGNING_KEY, _DATA_KEY, _PROVIDER_ID, _ENCRYPTED_DATA_KEY_RSA, \ + _DECRYPTION_MATERIALS_WITH_DATA_KEY, _ENCRYPTION_MATERIALS_WITH_DATA_KEY, _PUBLIC_EXPONENT, _KEY_SIZE, _BACKEND + +import aws_encryption_sdk.keyring.raw_keyring +import aws_encryption_sdk.key_providers.raw +from aws_encryption_sdk.internal.crypto.wrapping_keys import WrappingKey +from pytest_mock import mocker # noqa pylint: disable=unused-import + try: # Python 3.5.0 and 3.5.1 have incompatible typing modules from typing import Iterable # noqa pylint: disable=unused-import @@ -34,77 +37,37 @@ pytestmark = [pytest.mark.unit, pytest.mark.local] -_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=b"5430b043-5843-4629-869c-64794af77ada"), - 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=b"5430b043-5843-4629-869c-64794af77ada"), - 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( +_DECRYPTION_MATERIALS_WITHOUT_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(', - ), - encrypted_data_keys=[_ENCRYPTED_DATA_KEY_RSA], + verification_key=b"ex_verification_key", 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=b"5430b043-5843-4629-869c-64794af77ada"), -# # 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=b"5430b043-5843-4629-869c-64794af77ada"), -# # flags={KeyringTraceFlag.WRAPPING_KEY_DECRYPTED_DATA_KEY}, -# # ) -# # ], -# # ) -# # -# # _DECRYPTION_MATERIALS_WITHOUT_DATA_KEY = DecryptionMaterials( -# # algorithm=Algorithm.AES_256_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384, -# # verification_key=b"ex_verification_key", -# # encryption_context=_ENCRYPTION_CONTEXT, -# # ) -# -# # def apply_fixtures(self): -# # self.mock_encrypted_data_key = EncryptedDataKey( -# # key_provider=MasterKeyInfo(provider_id=_PROVIDER_ID, key_info=_KEY_ID), -# # encrypted_data_key=VALUES["encrypted_data_key"], -# # ) -# # self.mock_encryption_materials = MagicMock() -# # self.mock_encryption_materials.__class__ = EncryptionMaterials -# -# +@pytest.fixture +def patch_generate_data_key(mocker): + mocker.patch.object(aws_encryption_sdk.keyring.raw_keyring, "generate_data_key") + return aws_encryption_sdk.keyring.raw_keyring.generate_data_key + + +@pytest.fixture +def patch_decrypt_data_key(mocker): + mocker.patch.object(WrappingKey, "decrypt") + return WrappingKey.decrypt + + +@pytest.fixture +def patch_os_urandom(mocker): + mocker.patch.object(aws_encryption_sdk.key_providers.raw.os, "urandom") + return aws_encryption_sdk.key_providers.raw.os.urandom + + def test_parent(): assert issubclass(RawRSAKeyring, Keyring) @@ -114,7 +77,9 @@ def test_valid_parameters(): 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=_PUBLIC_EXPONENT, + key_size=_KEY_SIZE, + backend=_BACKEND) ) assert test.key_namespace == _PROVIDER_ID assert test.key_name == _KEY_ID @@ -127,8 +92,9 @@ def test_missing_required_parameters(): RawRSAKeyring( key_namespace=_PROVIDER_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=_PUBLIC_EXPONENT, + key_size=_KEY_SIZE, + backend=_BACKEND) ) assert exc_info.errisinstance(TypeError) @@ -154,19 +120,19 @@ def test_public_and_private_key_not_provided(): assert exc_info.match("At least one of public key or private key must be provided.") -@patch("aws_encryption_sdk.keyring.raw_keyring.generate_data_key") -def test_on_encrypt_when_data_encryption_key_given(mock_generate_data_key): - mock_generate_data_key.return_value = _DATA_KEY +def test_on_encrypt_when_data_encryption_key_given(patch_generate_data_key): test_raw_rsa_keyring = 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=_PUBLIC_EXPONENT, + key_size=_KEY_SIZE, + backend=_BACKEND) ) test = test_raw_rsa_keyring.on_encrypt(encryption_materials=_ENCRYPTION_MATERIALS_WITH_DATA_KEY) # Check if keyring is generated - assert not mock_generate_data_key.called + assert not patch_generate_data_key.called def test_keyring_trace_on_encrypt_when_data_encryption_key_given(): @@ -174,7 +140,9 @@ def test_keyring_trace_on_encrypt_when_data_encryption_key_given(): 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=_PUBLIC_EXPONENT, + key_size=_KEY_SIZE, + backend=_BACKEND), ) test = test_raw_rsa_keyring.on_encrypt(encryption_materials=_ENCRYPTION_MATERIALS_WITH_DATA_KEY) @@ -190,7 +158,9 @@ def test_on_encrypt_when_data_encryption_key_not_given(): 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=_PUBLIC_EXPONENT, + key_size=_KEY_SIZE, + backend=_BACKEND), ) original_number_of_encrypted_data_keys = len(_ENCRYPTION_MATERIALS_WITHOUT_DATA_KEY.encrypted_data_keys) @@ -218,287 +188,152 @@ def test_on_encrypt_when_data_encryption_key_not_given(): assert encrypted_flag_count == 1 -# @patch("aws_encryption_sdk.internal.crypto.wrapping_keys.WrappingKey.decrypt") -# def test_on_decrypt_when_data_key_given(mock_decrypt): -# mock_decrypt.return_value = _DATA_KEY -# test_raw_rsa_keyring = 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()), -# ) -# test = test_raw_rsa_keyring.on_decrypt( -# decryption_materials=_DECRYPTION_MATERIALS_WITH_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\x7f.}\x87\x16,\x11n#\xc8p" -# b"\xdb\xbf\x94\x86*Q\x06\xd2\xf5\xdah\x08\xa4p\x81\xf7\xf4G\ -# x07FzE\xde", -# ) -# ] -# ) -# assert not mock_decrypt.called -# -# -# def test_keyring_trace_on_decrypt_when_data_key_given(): -# test_raw_rsa_keyring = 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()), -# ) -# test = test_raw_rsa_keyring.on_decrypt( -# decryption_materials=_DECRYPTION_MATERIALS_WITH_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\x7f.}\x87\x16,\x11n#\xc8p" -# b"\xdb\xbf\x94\x86*Q\x06\xd2\xf5\xdah\x08\xa4p\x81\xf7\xf4G\ -# x07FzE\xde", -# ) -# ] -# ) -# for keyring_trace in test.keyring_trace: -# if keyring_trace.wrapping_key.key_info == _KEY_ID: -# # Check keyring trace does not contain KeyringTraceFlag.WRAPPING_KEY_DECRYPTED_DATA_KEY -# assert KeyringTraceFlag.WRAPPING_KEY_DECRYPTED_DATA_KEY not in keyring_trace.flags -# -# -# @patch("aws_encryption_sdk.internal.crypto.wrapping_keys.WrappingKey.decrypt") -# def test_on_decrypt_when_data_key_and_edk_not_provided(mock_decrypt): -# mock_decrypt.return_value = _DATA_KEY -# test_raw_rsa_keyring = 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()), -# ) -# -# test = test_raw_rsa_keyring.on_decrypt(decryption_materials=_DECRYPTION_MATERIALS_WITHOUT_DATA_KEY, -# encrypted_data_keys=[]) -# assert not mock_decrypt.called -# -# for keyring_trace in test.keyring_trace: -# if keyring_trace.wrapping_key.key_info == _KEY_ID: -# assert KeyringTraceFlag.WRAPPING_KEY_DECRYPTED_DATA_KEY not in keyring_trace.flags -# -# assert test.data_encryption_key is None -# -# -# @patch("aws_encryption_sdk.internal.crypto.wrapping_keys.WrappingKey.decrypt") -# def test_on_decrypt_when_data_key_not_provided_and_edk_not_in_keyring(mock_decrypt): -# mock_decrypt.return_value = _DATA_KEY -# test_raw_rsa_keyring = 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()), -# ) -# -# test = test_raw_rsa_keyring.on_decrypt(decryption_materials=_DECRYPTION_MATERIALS_WITHOUT_DATA_KEY, -# encrypted_data_keys=[ -# EncryptedDataKey( -# key_provider=MasterKeyInfo( -# provider_id=_PROVIDER_ID, -# key_info=b"5430b043-5843-4629-869c-64794af77ada"), -# 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", -# ) -# ] -# ) -# assert not mock_decrypt.called -# -# for keyring_trace in test.keyring_trace: -# if keyring_trace.wrapping_key.key_info == _KEY_ID: -# assert KeyringTraceFlag.WRAPPING_KEY_DECRYPTED_DATA_KEY not in keyring_trace.flags -# -# assert test.data_encryption_key is None -# -# -# @patch("aws_encryption_sdk.internal.crypto.wrapping_keys.WrappingKey.decrypt") -# def test_on_decrypt_when_data_key_not_provided_and_edk_provided(mock_decrypt): -# mock_decrypt.return_value = _DATA_KEY -# test_raw_rsa_keyring = 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()), -# ) -# -# test = test_raw_rsa_keyring.on_decrypt(decryption_materials=_DECRYPTION_MATERIALS_WITHOUT_DATA_KEY, -# encrypted_data_keys=[_ENCRYPTED_DATA_KEY_RSA] -# ) -# assert mock_decrypt.called_once_with(encrypted_wrapped_data_key=_ENCRYPTED_DATA_KEY_RSA, -# encryption_context=_ENCRYPTION_CONTEXT -# ) -# -# -# def test_keyring_trace_when_data_key_not_provided_and_edk_provided(): -# test_raw_rsa_keyring = 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()), -# ) -# -# test = test_raw_rsa_keyring.on_decrypt(decryption_materials=_DECRYPTION_MATERIALS_WITHOUT_DATA_KEY, -# encrypted_data_keys=[_ENCRYPTED_DATA_KEY_RSA] -# ) -# decrypted_flag_count = 0 -# -# for keyring_trace in test.keyring_trace: -# if KeyringTraceFlag.WRAPPING_KEY_DECRYPTED_DATA_KEY in keyring_trace.flags: -# decrypted_flag_count += 1 -# -# assert decrypted_flag_count == 1 -# -# -# -# -# -# -# -# -# -# -# -# -# -# -# -# -# -# -# -# -# -# -# -# -# -# -# -# -# -# # @patch("aws_encryption_sdk.keyring.raw_keyring.generate_data_key") -# # def test_data_encryption_key_provided(self, mock_generate_data_key): -# # mock_generate_data_key.return_value = _DATA_KEY -# # test_raw_rsa_keyring = RawRSAKeyring( -# # key_namespace=_PROVIDER_ID, -# # key_name=_KEY_ID, -# # wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, -# # private_wrapping_key=_WRAPPING_KEY, -# # ) -# # -# # test = test_raw_rsa_keyring.on_encrypt(encryption_materials=_ENCRYPTION_MATERIALS_WITH_DATA_KEY) -# # # Check if keyring is generated -# # assert not mock_generate_data_key.called -# # -# # # Check if data encryption key is encrypted -# # assert test.encrypted_data_keys is not None -# # -# # def test_data_encryption_key_generated(self): -# # test_raw_rsa_keyring = RawRSAKeyring( -# # key_namespace=_PROVIDER_ID, -# # key_name=_KEY_ID, -# # wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, -# # private_wrapping_key=_WRAPPING_KEY, -# # ) -# # test = test_raw_rsa_keyring.on_encrypt(encryption_materials=_ENCRYPTION_MATERIALS_WITHOUT_DATA_KEY) -# # -# # # Check if key is generated -# # if not test.data_encryption_key: -# # # Check if error thrown if data key is not generated -# # assert pytest.raises(GenerateKeyError, "Unable to generate data encryption key.") -# # else: -# # # Check if data key is generated -# # assert test.data_encryption_key and test.data_encryption_key is not None -# # assert test.encrypted_data_keys and test.encrypted_data_keys is not None -# # -# # @patch("aws_encryption_sdk.keyring.raw_keyring.generate_data_key") -# # def test_encrypted_data_key_provided(self, mock_generate_data_key): -# # mock_generate_data_key.return_value = _DATA_KEY -# # test_raw_rsa_keyring = RawRSAKeyring( -# # key_namespace=_PROVIDER_ID, -# # key_name=_KEY_ID, -# # wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, -# # private_wrapping_key=_WRAPPING_KEY, -# # ) -# # test = test_raw_rsa_keyring.on_encrypt(encryption_materials=_ENCRYPTION_MATERIALS_WITH_ENCRYPTED_DATA_KEY) -# # -# # # Check if generate_data_key is called -# # assert not mock_generate_data_key.called -# # # -# # # Check if encrypt is called -# # assert len(test.encrypted_data_keys) == len(_ENCRYPTION_MATERIALS_WITH_ENCRYPTED_DATA_KEY.encrypted_data_keys) -# # -# # # @patch("aws_encryption_sdk.key_providers.raw.os.urandom") -# # # def test_data_key_not_generated(self, mock_os_urandom): -# # # mock_os_urandom.return_value = None -# # # test_raw_aes_keyring = RawAESKeyring( -# # # key_namespace=_PROVIDER_ID, -# # # key_name=_KEY_ID, -# # # wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, -# # # wrapping_key=_WRAPPING_KEY, -# # # ) -# # # test = test_raw_aes_keyring.on_encrypt(encryption_materials=_ENCRYPTION_MATERIALS_WITHOUT_DATA_KEY) -# # # assert pytest.raises(GenerateKeyError, "Unable to generate data encryption key.") -# # -# # @patch("aws_encryption_sdk.keyring.raw_keyring.generate_data_key") -# # def test_data_key_not_generated(self, mock_generate_data_key): -# # mock_generate_data_key.return_value = None -# # test_raw_rsa_keyring = RawRSAKeyring( -# # key_namespace=_PROVIDER_ID, -# # key_name=_KEY_ID, -# # wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, -# # private_wrapping_key=_WRAPPING_KEY, -# # ) -# # test = test_raw_rsa_keyring.on_encrypt(encryption_materials=_ENCRYPTION_MATERIALS_WITHOUT_DATA_KEY) -# # assert pytest.raises(GenerateKeyError) -# # -# # @patch("aws_encryption_sdk.internal.crypto.wrapping_keys.WrappingKey.decrypt") -# # def test_decrypt_when_data_key_provided(self, mock_decrypt): -# # mock_decrypt.return_value = _DATA_KEY -# # test_raw_rsa_keyring = RawRSAKeyring( -# # key_namespace=_PROVIDER_ID, -# # key_name=_KEY_ID, -# # wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, -# # private_wrapping_key=_WRAPPING_KEY, -# # ) -# # test = test_raw_rsa_keyring.on_decrypt( -# # decryption_materials=_DECRYPTION_MATERIALS_WITH_DATA_KEY, encrypted_data_keys=[self.mock_encrypted_data_key] -# # ) -# # assert not mock_decrypt.called -# # -# # # @patch("aws_encryption_sdk.internal.crypto.wrapping_keys.WrappingKey.decrypt") -# # # def test_decrypt_when_data_key_not_provided(self, mock_decrypt): -# # # mock_decrypt.return_value = _DATA_KEY -# # # test_raw_aes_keyring = RawAESKeyring( -# # # key_namespace=_PROVIDER_ID, -# # # key_name=_KEY_ID, -# # # wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, -# # # wrapping_key=_WRAPPING_KEY, -# # # ) -# # # -# # # test = test_raw_aes_keyring.on_decrypt(decryption_materials=_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\x7f.}\x87\x16,\x11n#\xc8p" -# # # b"\xdb\xbf\x94\x86*Q\x06\xd2\xf5\xdah\x08\xa4p\x81\xf7\xf4G\ -# # # x07FzE\xde", -# # # ) -# # # ] -# # # ) -# # # assert mock_decrypt.called +def test_on_decrypt_when_data_key_given(patch_decrypt_data_key): + test_raw_rsa_keyring = 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=_PUBLIC_EXPONENT, + key_size=_KEY_SIZE, + backend=_BACKEND), + ) + test = test_raw_rsa_keyring.on_decrypt( + decryption_materials=_DECRYPTION_MATERIALS_WITH_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\x7f.}\x87\x16,\x11n#\xc8p" + b"\xdb\xbf\x94\x86*Q\x06\xd2\xf5\xdah\x08\xa4p\x81\xf7\xf4G\ + x07FzE\xde", + ) + ] + ) + assert not patch_decrypt_data_key.called + + +def test_keyring_trace_on_decrypt_when_data_key_given(): + test_raw_rsa_keyring = 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=_PUBLIC_EXPONENT, + key_size=_KEY_SIZE, + backend=_BACKEND), + ) + test = test_raw_rsa_keyring.on_decrypt( + decryption_materials=_DECRYPTION_MATERIALS_WITH_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\x7f.}\x87\x16,\x11n#\xc8p" + b"\xdb\xbf\x94\x86*Q\x06\xd2\xf5\xdah\x08\xa4p\x81\xf7\xf4G\ + x07FzE\xde", + ) + ] + ) + for keyring_trace in test.keyring_trace: + if keyring_trace.wrapping_key.key_info == _KEY_ID: + # Check keyring trace does not contain KeyringTraceFlag.WRAPPING_KEY_DECRYPTED_DATA_KEY + assert KeyringTraceFlag.WRAPPING_KEY_DECRYPTED_DATA_KEY not in keyring_trace.flags + + +def test_on_decrypt_when_data_key_and_edk_not_provided(patch_decrypt_data_key): + test_raw_rsa_keyring = 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=_PUBLIC_EXPONENT, + key_size=_KEY_SIZE, + backend=_BACKEND), + ) + + test = test_raw_rsa_keyring.on_decrypt(decryption_materials=_DECRYPTION_MATERIALS_WITHOUT_DATA_KEY, + encrypted_data_keys=[]) + assert not patch_decrypt_data_key.called + + for keyring_trace in test.keyring_trace: + assert KeyringTraceFlag.WRAPPING_KEY_DECRYPTED_DATA_KEY not in keyring_trace.flags + + assert test.data_encryption_key is None + + +def test_on_decrypt_when_data_key_not_provided_and_edk_not_in_keyring(patch_decrypt_data_key): + test_raw_rsa_keyring = 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=_PUBLIC_EXPONENT, + key_size=_KEY_SIZE, + backend=_BACKEND), + ) + + test = test_raw_rsa_keyring.on_decrypt(decryption_materials=_DECRYPTION_MATERIALS_WITHOUT_DATA_KEY, + encrypted_data_keys=[ + EncryptedDataKey( + key_provider=MasterKeyInfo( + provider_id=_PROVIDER_ID, + key_info=b"5430b043-5843-4629-869c-64794af77ada"), + 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", + ) + ] + ) + assert not patch_decrypt_data_key.called + + for keyring_trace in test.keyring_trace: + if keyring_trace.wrapping_key.key_info == _KEY_ID: + assert KeyringTraceFlag.WRAPPING_KEY_DECRYPTED_DATA_KEY not in keyring_trace.flags + + assert test.data_encryption_key is None + + +def test_on_decrypt_when_data_key_not_provided_and_edk_provided(patch_decrypt_data_key): + patch_decrypt_data_key.return_value = _DATA_KEY + test_raw_rsa_keyring = 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=_PUBLIC_EXPONENT, + key_size=_KEY_SIZE, + backend=_BACKEND), + ) + + test = test_raw_rsa_keyring.on_decrypt(decryption_materials=_DECRYPTION_MATERIALS_WITHOUT_DATA_KEY, + encrypted_data_keys=[_ENCRYPTED_DATA_KEY_RSA] + ) + assert patch_decrypt_data_key.called_once_with(encrypted_wrapped_data_key=_ENCRYPTED_DATA_KEY_RSA, + encryption_context=_ENCRYPTION_CONTEXT + ) + + +def test_keyring_trace_when_data_key_not_provided_and_edk_provided(): + test_raw_rsa_keyring = 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=_PUBLIC_EXPONENT, + key_size=_KEY_SIZE, + backend=_BACKEND), + ) + + test = test_raw_rsa_keyring.on_decrypt(decryption_materials=_DECRYPTION_MATERIALS_WITHOUT_DATA_KEY, + encrypted_data_keys=test_raw_rsa_keyring.on_encrypt( + encryption_materials=_ENCRYPTION_MATERIALS_WITHOUT_DATA_KEY). + encrypted_data_keys + ) + decrypted_flag_count = 0 + + for keyring_trace in test.keyring_trace: + if KeyringTraceFlag.WRAPPING_KEY_DECRYPTED_DATA_KEY in keyring_trace.flags: + decrypted_flag_count += 1 + + assert decrypted_flag_count == 1 diff --git a/test/unit/test_utils.py b/test/unit/test_utils.py index e0b5271c9..f2ccf87a9 100644 --- a/test/unit/test_utils.py +++ b/test/unit/test_utils.py @@ -17,6 +17,7 @@ import pytest from mock import MagicMock, patch, sentinel +from cryptography.hazmat.backends import default_backend import aws_encryption_sdk.identifiers import aws_encryption_sdk.internal.utils from aws_encryption_sdk.exceptions import InvalidDataKeyError, SerializationError, UnknownIdentityError @@ -45,6 +46,11 @@ _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" ) + +_PUBLIC_EXPONENT = 65537 +_KEY_SIZE = 2048 +_BACKEND = default_backend() + _ENCRYPTED_DATA_KEY_AES = EncryptedDataKey( key_provider=MasterKeyInfo( provider_id='Random Raw Keys', @@ -69,37 +75,6 @@ ) -# _ENCRYPTED_DATA_KEYS_RSA = [ -# EncryptedDataKey( -# key_provider=MasterKeyInfo( -# provider_id='Random Raw Keys', -# key_info=b'5325b043-5843-4629-869c-64794af77ada'), -# encrypted_data_key=b'd7\xc7 R\x0e\x91\x104\xadK\xcb}j\xa1e2\x86\xe1W\xac\xf2\xab\xfc\xe3@\x15\x18' -# b'\xc7\xef\x10a\xf4n1`\x11\x17\x85\x0c]X\x98\xac\xc8J\x9c\xc6\xbd}Y\xbaL\xb6' -# b'\xb1\xf1\xf1\n\xba\x1c\x03\xfbM\xebs\\&hW\x1b\xc8d\x1c\x81\xd2\xe0\xec\xdf' -# b'\xfe\xe1j\xf4\xcaHO\xe5`\x8c\xc74\x11Cc\xf9\xb1\xe9S\xa9*\xdbK+2\x12\xd2\xb0' -# b'\xc2\xdb2\xf1\xc2\xc65&\x96R\xdc\xfd\xf9\xafaE\x8c\xbc\x9f$E-R\xe6\xcd^\xf2w' -# b'\x87#\x02l\xf3|;\x90\x9ez\xbfA.\xe5\x1cB\xda+[\xf1.|\xf5s\xb9\nI\xc8\xab\xf4' -# b'\xee\x9f\x81\n*\xcd\xee\x975m\x85\xde-\xd59=\x87C\xfc\xe0\x8d\xaa\xc4\xdf\xb1#' -# b'\x95nm\x9dc}\x05\x0e"\x0c6^\xfd\xda\xc8q\x9b\x02\x1b\x12\xb4\xd0&\x85\xb1\xd1' -# b'\x97\x1f&sQ\x10]\x04\xb9o\x80\xb1\x81a\x86cI\xbd\xaaz\xf0\xfb\x1dB#zN\xa8\xba' -# b'\xc0]PsT\x08\xa4\x19\x16\xc4\xd9'), -# EncryptedDataKey( -# key_provider=MasterKeyInfo( -# provider_id='Random Raw Keys', -# key_info=b'5325b043-5843-4629-869c-64794af77ada'), -# encrypted_data_key=b'\xbbno\xb3C\xd2s\xd9\xa8\x92\xcb\xd2x\n#\x0e:j\x11\xf7\xf8\xb5+\xcf\x98\xea\xa2' -# b'\xdd\x8d\xf0\x0f\xca\xef\xdb\xb8\x03\xd9\xaf\x99\xca\xf1\x1c\xb2\xd6\x92\x9ch1m' -# b'\xa9!\x84\x90\xbe7RI\xdc.p\xe2\xdc\x0e\x8f\x1cl\xc8\x91\xf7HHR\x01\x9d\xdf\xbd' -# b'\x19\xbbt\xf7\x00\x13H\x024#\x18K\xf2qd\xef\x9a\x86\xac\x82\xe5rik\x9c\x8aI\xaf' -# b'\xf6f\xf6l\xe9\\\x08\xc0\x8fq\x17\xbf\x06\x0b\xa5\xe0\xf5\x97\xf4\xc8e\n6\x83' -# b'\x08J\xfb4)\x1a.\x1f6\xda\xb2\xc6n\xa9\xd2Fa\x19\x86\xa9qh\x8e\x97\x0e2\xba\xfd' -# b'\xe4:/\x91~H\x0b^\x91C\xc0\xc9\x0c`C\xebt\xd8\xec\xecZ\xf10\x80\xaa\xa1/\x18\xc0' -# b'\x923\xdc\x9e\xec<\xb3\x9f\xb7\x8b\xec\xc3\x8d\nb\x82\x84\xd0\x9b\xa3\x9f4\x84\x8c' -# b'\xa3v*v9d\xdb\xa6=\xc2\xfa\x88s\x8a\xa4\t)6\xe8\x08\x1dOj;\xd0\x1c0\xaf\x1e\x10\xaa' -# b'\x7f\x90\xff\x92\xac\xceIMs\xf6\xb0\xff+\xfdvf') -# -# , ] _ENCRYPTION_MATERIALS_WITH_DATA_KEY = EncryptionMaterials( algorithm=Algorithm.AES_256_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384, @@ -117,12 +92,6 @@ ], ) -_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_AES = EncryptionMaterials( algorithm=Algorithm.AES_256_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384, data_encryption_key=RawDataKey( @@ -142,53 +111,17 @@ ], ) -# _ENCRYPTION_MATERIALS_WITH_ENCRYPTED_DATA_KEY_RSA = 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='Random Raw Keys', -# key_info=b'5325b043-5843-4629-869c-64794af77ada'), -# encrypted_data_key=b'd7\xc7 R\x0e\x91\x104\xadK\xcb}j\xa1e2\x86\xe1W\xac\xf2\xab\xfc\xe3@\x15\x18' -# b'\xc7\xef\x10a\xf4n1`\x11\x17\x85\x0c]X\x98\xac\xc8J\x9c\xc6\xbd}Y\xbaL\xb6' -# b'\xb1\xf1\xf1\n\xba\x1c\x03\xfbM\xebs\\&hW\x1b\xc8d\x1c\x81\xd2\xe0\xec\xdf' -# b'\xfe\xe1j\xf4\xcaHO\xe5`\x8c\xc74\x11Cc\xf9\xb1\xe9S\xa9*\xdbK+2\x12\xd2\xb0' -# b'\xc2\xdb2\xf1\xc2\xc65&\x96R\xdc\xfd\xf9\xafaE\x8c\xbc\x9f$E-R\xe6\xcd^\xf2w' -# b'\x87#\x02l\xf3|;\x90\x9ez\xbfA.\xe5\x1cB\xda+[\xf1.|\xf5s\xb9\nI\xc8\xab\xf4' -# b'\xee\x9f\x81\n*\xcd\xee\x975m\x85\xde-\xd59=\x87C\xfc\xe0\x8d\xaa\xc4\xdf\xb1#' -# b'\x95nm\x9dc}\x05\x0e"\x0c6^\xfd\xda\xc8q\x9b\x02\x1b\x12\xb4\xd0&\x85\xb1\xd1' -# b'\x97\x1f&sQ\x10]\x04\xb9o\x80\xb1\x81a\x86cI\xbd\xaaz\xf0\xfb\x1dB#zN\xa8\xba' -# b'\xc0]PsT\x08\xa4\x19\x16\xc4\xd9'), -# EncryptedDataKey( -# key_provider=MasterKeyInfo( -# provider_id='Random Raw Keys', -# key_info=b'5325b043-5843-4629-869c-64794af77ada'), -# encrypted_data_key=b'\xbbno\xb3C\xd2s\xd9\xa8\x92\xcb\xd2x\n#\x0e:j\x11\xf7\xf8\xb5+\xcf\x98\xea\xa2' -# b'\xdd\x8d\xf0\x0f\xca\xef\xdb\xb8\x03\xd9\xaf\x99\xca\xf1\x1c\xb2\xd6\x92\x9ch1m' -# b'\xa9!\x84\x90\xbe7RI\xdc.p\xe2\xdc\x0e\x8f\x1cl\xc8\x91\xf7HHR\x01\x9d\xdf\xbd' -# b'\x19\xbbt\xf7\x00\x13H\x024#\x18K\xf2qd\xef\x9a\x86\xac\x82\xe5rik\x9c\x8aI\xaf' -# b'\xf6f\xf6l\xe9\\\x08\xc0\x8fq\x17\xbf\x06\x0b\xa5\xe0\xf5\x97\xf4\xc8e\n6\x83' -# b'\x08J\xfb4)\x1a.\x1f6\xda\xb2\xc6n\xa9\xd2Fa\x19\x86\xa9qh\x8e\x97\x0e2\xba\xfd' -# b'\xe4:/\x91~H\x0b^\x91C\xc0\xc9\x0c`C\xebt\xd8\xec\xecZ\xf10\x80\xaa\xa1/\x18\xc0' -# b'\x923\xdc\x9e\xec<\xb3\x9f\xb7\x8b\xec\xc3\x8d\nb\x82\x84\xd0\x9b\xa3\x9f4\x84\x8c' -# b'\xa3v*v9d\xdb\xa6=\xc2\xfa\x88s\x8a\xa4\t)6\xe8\x08\x1dOj;\xd0\x1c0\xaf\x1e\x10\xaa' -# b'\x7f\x90\xff\x92\xac\xceIMs\xf6\xb0\xff+\xfdvf') -# -# , ], -# 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, +) + +_DECRYPTION_MATERIALS_WITHOUT_DATA_KEY = DecryptionMaterials( + algorithm=Algorithm.AES_256_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384, + verification_key=b"ex_verification_key", + encryption_context=_ENCRYPTION_CONTEXT, +) _DECRYPTION_MATERIALS_WITH_DATA_KEY = DecryptionMaterials( algorithm=Algorithm.AES_256_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384, @@ -206,43 +139,6 @@ ], ) -_DECRYPTION_MATERIALS_WITHOUT_DATA_KEY = DecryptionMaterials( - algorithm=Algorithm.AES_256_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384, - verification_key=b"ex_verification_key", - encryption_context=_ENCRYPTION_CONTEXT, -) - - -_RAW_RSA_PRIVATE_KEY_PEM_ENCODED = ( - 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" -) - def test_prep_stream_data_passthrough(): test = aws_encryption_sdk.internal.utils.prep_stream_data(io.BytesIO(b"some data")) From dae98c35d0ed02039dd63396a660b327e06c8f93 Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Sat, 27 Jul 2019 01:10:21 -0700 Subject: [PATCH 105/119] All unit tests done. Functional tests - key_info_prefix_vectors for AES and compatibility with MKP for RSA remaining --- test/functional/test_f_keyring_raw_aes.py | 50 ++++-- test/functional/test_f_keyring_raw_rsa.py | 109 +++++------- test/unit/test_keyring_raw_aes.py | 179 +++++++++---------- test/unit/test_keyring_raw_rsa.py | 202 ++++++++++------------ test/unit/test_utils.py | 173 +++++++++--------- 5 files changed, 352 insertions(+), 361 deletions(-) diff --git a/test/functional/test_f_keyring_raw_aes.py b/test/functional/test_f_keyring_raw_aes.py index 0006fb408..e65520c6d 100644 --- a/test/functional/test_f_keyring_raw_aes.py +++ b/test/functional/test_f_keyring_raw_aes.py @@ -15,10 +15,10 @@ import pytest from aws_encryption_sdk.identifiers import Algorithm, KeyringTraceFlag, WrappingAlgorithm +from aws_encryption_sdk.key_providers.raw import RawMasterKey from aws_encryption_sdk.keyring.raw_keyring import RawAESKeyring from aws_encryption_sdk.materials_managers import DecryptionMaterials, EncryptionMaterials from aws_encryption_sdk.structures import EncryptedDataKey, KeyringTrace, MasterKeyInfo, RawDataKey -from aws_encryption_sdk.key_providers.raw import RawMasterKeyProvider pytestmark = [pytest.mark.functional, pytest.mark.local] @@ -31,7 +31,7 @@ _WRAPPING_ALGORITHM = [ WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING, WrappingAlgorithm.AES_128_GCM_IV12_TAG16_NO_PADDING, - WrappingAlgorithm.AES_192_GCM_IV12_TAG16_NO_PADDING + WrappingAlgorithm.AES_192_GCM_IV12_TAG16_NO_PADDING, ] _ENCRYPTION_MATERIALS = [ @@ -81,6 +81,13 @@ ], ), ] +# +# _KEY_INFO_VECTORS = [ +# (b"5325b043-5843-4629-869c-64794af77ada", b"5325b043-5843-4629-869c-64794af77ada\x00\x00\x00\x80\x00\x00\x00\x0c", +# WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING), +# (b"30456b043-0323-4452-332a", b"30456b043-0323-4452-332a\x00\x00\x00\x80\x00\x00\x00\x0c", +# WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING) +# ] @pytest.mark.parametrize("encryption_materials_samples", _ENCRYPTION_MATERIALS) @@ -121,15 +128,36 @@ def test_raw_aes_encryption_decryption(encryption_materials_samples, wrapping_al # Check if the data keys match assert encryption_materials.data_encryption_key.data_key == decryption_materials.data_encryption_key.data_key + test_raw_master_key = RawMasterKey( + key_id=test_raw_aes_keyring.key_name, + provider_id=test_raw_aes_keyring.key_namespace, + wrapping_key=test_raw_aes_keyring._wrapping_key_structure, + ) + encryption_materials = test_raw_aes_keyring.on_encrypt(encryption_materials=encryption_materials_samples) -def test_compatibility_with_raw_mkp(): - # Creating an instance of a raw AES keyring - test_raw_aes_keyring = RawAESKeyring( - key_namespace=key_namespace, - key_name=key_name, - wrapping_key=_WRAPPING_KEY, - wrapping_algorithm=WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING, + assert ( + encryption_materials.data_encryption_key.data_key + == test_raw_master_key.decrypt_data_key_from_list( + encrypted_data_keys=encryption_materials._encrypted_data_keys, + algorithm=encryption_materials.algorithm, + encryption_context=encryption_materials.encryption_context, + ).data_key ) - test_raw_master_key_provider = RawMasterKeyProvider( - ) \ No newline at end of file + if encryption_materials_samples.data_encryption_key is not None: + raw_master_key_encrypted_data_key = test_raw_master_key.encrypt_data_key( + data_key=encryption_materials_samples.data_encryption_key, + algorithm=encryption_materials_samples.algorithm, + encryption_context=encryption_materials_samples.encryption_context, + ) + assert ( + encryption_materials_samples.data_encryption_key.data_key + == test_raw_aes_keyring.on_decrypt( + decryption_materials=DecryptionMaterials( + algorithm=encryption_materials_samples.algorithm, + encryption_context=encryption_materials_samples.encryption_context, + verification_key=b"ex_verification_key", + ), + encrypted_data_keys=[raw_master_key_encrypted_data_key], + ).data_encryption_key.data_key + ) diff --git a/test/functional/test_f_keyring_raw_rsa.py b/test/functional/test_f_keyring_raw_rsa.py index eed07f6c2..24800bf17 100644 --- a/test/functional/test_f_keyring_raw_rsa.py +++ b/test/functional/test_f_keyring_raw_rsa.py @@ -14,8 +14,8 @@ import pytest from cryptography.hazmat.backends import default_backend -from cryptography.hazmat.primitives.asymmetric import rsa from cryptography.hazmat.primitives import serialization +from cryptography.hazmat.primitives.asymmetric import rsa from aws_encryption_sdk.identifiers import Algorithm, KeyringTraceFlag, WrappingAlgorithm from aws_encryption_sdk.keyring.raw_keyring import RawRSAKeyring @@ -29,73 +29,55 @@ _KEY_ID = b"5325b043-5843-4629-869c-64794af77ada" _SIGNING_KEY = b"aws-crypto-public-key" _WRAPPING_ALGORITHM = WrappingAlgorithm.RSA_OAEP_SHA256_MGF1 -# -# _PUBLIC_KEY = ( -# b"-----BEGIN PUBLIC KEY-----\n" -# b"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCOCigedc4PMp2sopCpJSqRNQla\n" -# b"KHuk2WBuNVfU3Z5oSwleZs63t/7PrKWWaVPsPfVxzAW2GK/h74KlIaN/T93W0o8Q\n" -# b"hsm6cMnRobaGYLro0hmy1VyiNrLE7JAOXhExdYJuL9fhK7VnYYxEDWa7K8xbdnCp\n" -# b"myFdLqOWTeSou6eF6wIDAQAB\n" -# b"-----END PUBLIC KEY-----\n" -# ) + _PUBLIC_EXPONENT = 65537 _KEY_SIZE = 2048 _BACKEND = default_backend() -_RAW_RSA_PRIVATE_KEY_PEM_ENCODED_WITHOUT_PASSWORD = rsa.generate_private_key(public_exponent=_PUBLIC_EXPONENT, - key_size=_KEY_SIZE, - backend=_BACKEND).private_bytes( +_RAW_RSA_PRIVATE_KEY_PEM_ENCODED_WITHOUT_PASSWORD = rsa.generate_private_key( + public_exponent=_PUBLIC_EXPONENT, key_size=_KEY_SIZE, backend=_BACKEND +).private_bytes( encoding=serialization.Encoding.PEM, format=serialization.PrivateFormat.TraditionalOpenSSL, - encryption_algorithm=serialization.NoEncryption() + encryption_algorithm=serialization.NoEncryption(), ) -_RAW_RSA_PRIVATE_KEY_PEM_ENCODED_WITH_PASSWORD = rsa.generate_private_key(public_exponent=_PUBLIC_EXPONENT, - key_size=_KEY_SIZE, - backend=_BACKEND).private_bytes( +_RAW_RSA_PRIVATE_KEY_PEM_ENCODED_WITH_PASSWORD = rsa.generate_private_key( + public_exponent=_PUBLIC_EXPONENT, key_size=_KEY_SIZE, backend=_BACKEND +).private_bytes( encoding=serialization.Encoding.PEM, format=serialization.PrivateFormat.PKCS8, - encryption_algorithm=serialization.BestAvailableEncryption(b'mypassword') + encryption_algorithm=serialization.BestAvailableEncryption(b"mypassword"), ) -_RAW_RSA_PUBLIC_KEY_PEM_ENCODED = rsa.generate_private_key(public_exponent=_PUBLIC_EXPONENT, - key_size=_KEY_SIZE, - backend=_BACKEND).public_key().public_bytes( - encoding=serialization.Encoding.PEM, - format=serialization.PublicFormat.SubjectPublicKeyInfo, +_RAW_RSA_PUBLIC_KEY_PEM_ENCODED = ( + rsa.generate_private_key(public_exponent=_PUBLIC_EXPONENT, key_size=_KEY_SIZE, backend=_BACKEND) + .public_key() + .public_bytes(encoding=serialization.Encoding.PEM, format=serialization.PublicFormat.SubjectPublicKeyInfo) ) -_RAW_RSA_PRIVATE_KEY_DER_ENCODED_WITHOUT_PASSWORD = rsa.generate_private_key(public_exponent=_PUBLIC_EXPONENT, - key_size=_KEY_SIZE, - backend=_BACKEND).private_bytes( +_RAW_RSA_PRIVATE_KEY_DER_ENCODED_WITHOUT_PASSWORD = rsa.generate_private_key( + public_exponent=_PUBLIC_EXPONENT, key_size=_KEY_SIZE, backend=_BACKEND +).private_bytes( encoding=serialization.Encoding.DER, format=serialization.PrivateFormat.TraditionalOpenSSL, - encryption_algorithm=serialization.NoEncryption() + encryption_algorithm=serialization.NoEncryption(), ) -_RAW_RSA_PRIVATE_KEY_DER_ENCODED_WITH_PASSWORD = rsa.generate_private_key(public_exponent=_PUBLIC_EXPONENT, - key_size=_KEY_SIZE, - backend=_BACKEND).private_bytes( +_RAW_RSA_PRIVATE_KEY_DER_ENCODED_WITH_PASSWORD = rsa.generate_private_key( + public_exponent=_PUBLIC_EXPONENT, key_size=_KEY_SIZE, backend=_BACKEND +).private_bytes( encoding=serialization.Encoding.DER, format=serialization.PrivateFormat.PKCS8, - encryption_algorithm=serialization.BestAvailableEncryption(b'mypassword') + encryption_algorithm=serialization.BestAvailableEncryption(b"mypassword"), ) -_RAW_RSA_PUBLIC_KEY_DER_ENCODED = rsa.generate_private_key(public_exponent=_PUBLIC_EXPONENT, - key_size=_KEY_SIZE, - backend=_BACKEND).public_key().public_bytes( - encoding=serialization.Encoding.DER, - format=serialization.PublicFormat.SubjectPublicKeyInfo, +_RAW_RSA_PUBLIC_KEY_DER_ENCODED = ( + rsa.generate_private_key(public_exponent=_PUBLIC_EXPONENT, key_size=_KEY_SIZE, backend=_BACKEND) + .public_key() + .public_bytes(encoding=serialization.Encoding.DER, format=serialization.PublicFormat.SubjectPublicKeyInfo) ) -# _WRAPPING_ALGORITHMS = [ -# WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, -# WrappingAlgorithm.RSA_OAEP_SHA1_MGF1, -# WrappingAlgorithm.RSA_OAEP_SHA384_MGF1, -# WrappingAlgorithm.RSA_OAEP_SHA512_MGF1, -# WrappingAlgorithm.RSA_PKCS1 -# ] - _ENCRYPTION_MATERIALS = [ EncryptionMaterials( algorithm=Algorithm.AES_256_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384, @@ -145,46 +127,46 @@ ] _RAW_RSA_KEYRINGS = [ - RawRSAKeyring( key_namespace=_PROVIDER_ID, key_name=_KEY_ID, wrapping_algorithm=_WRAPPING_ALGORITHM, - private_wrapping_key=rsa.generate_private_key(public_exponent=_PUBLIC_EXPONENT, - key_size=_KEY_SIZE, - backend=_BACKEND), + private_wrapping_key=rsa.generate_private_key( + public_exponent=_PUBLIC_EXPONENT, key_size=_KEY_SIZE, backend=_BACKEND + ), ), RawRSAKeyring( key_namespace=_PROVIDER_ID, key_name=_KEY_ID, wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA1_MGF1, - private_wrapping_key=rsa.generate_private_key(public_exponent=_PUBLIC_EXPONENT, - key_size=_KEY_SIZE, backend=_BACKEND), + private_wrapping_key=rsa.generate_private_key( + public_exponent=_PUBLIC_EXPONENT, key_size=_KEY_SIZE, backend=_BACKEND + ), ), RawRSAKeyring( key_namespace=_PROVIDER_ID, key_name=_KEY_ID, wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA384_MGF1, - private_wrapping_key=rsa.generate_private_key(public_exponent=_PUBLIC_EXPONENT, - key_size=_KEY_SIZE, backend=_BACKEND), + private_wrapping_key=rsa.generate_private_key( + public_exponent=_PUBLIC_EXPONENT, key_size=_KEY_SIZE, backend=_BACKEND + ), ), RawRSAKeyring( key_namespace=_PROVIDER_ID, key_name=_KEY_ID, wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA512_MGF1, - private_wrapping_key=rsa.generate_private_key(public_exponent=_PUBLIC_EXPONENT, - key_size=_KEY_SIZE, backend=_BACKEND), + private_wrapping_key=rsa.generate_private_key( + public_exponent=_PUBLIC_EXPONENT, key_size=_KEY_SIZE, backend=_BACKEND + ), ), RawRSAKeyring( key_namespace=_PROVIDER_ID, key_name=_KEY_ID, wrapping_algorithm=WrappingAlgorithm.RSA_PKCS1, - private_wrapping_key=rsa.generate_private_key(public_exponent=_PUBLIC_EXPONENT, - key_size=_KEY_SIZE, backend=_BACKEND), + private_wrapping_key=rsa.generate_private_key( + public_exponent=_PUBLIC_EXPONENT, key_size=_KEY_SIZE, backend=_BACKEND + ), ), - - - RawRSAKeyring.fromPEMEncoding( key_namespace=_PROVIDER_ID, key_name=_KEY_ID, @@ -195,7 +177,7 @@ key_namespace=_PROVIDER_ID, key_name=_KEY_ID, private_encoded_key=_RAW_RSA_PRIVATE_KEY_PEM_ENCODED_WITH_PASSWORD, - password=b'mypassword', + password=b"mypassword", wrapping_algorithm=_WRAPPING_ALGORITHM, ), RawRSAKeyring.fromPEMEncoding( @@ -204,9 +186,6 @@ public_encoded_key=_RAW_RSA_PUBLIC_KEY_PEM_ENCODED, wrapping_algorithm=_WRAPPING_ALGORITHM, ), - - - RawRSAKeyring.fromDEREncoding( key_namespace=_PROVIDER_ID, key_name=_KEY_ID, @@ -217,14 +196,14 @@ key_namespace=_PROVIDER_ID, key_name=_KEY_ID, private_encoded_key=_RAW_RSA_PRIVATE_KEY_DER_ENCODED_WITH_PASSWORD, - password=b'mypassword', + password=b"mypassword", wrapping_algorithm=_WRAPPING_ALGORITHM, ), RawRSAKeyring.fromDEREncoding( key_namespace=_PROVIDER_ID, key_name=_KEY_ID, public_encoded_key=_RAW_RSA_PUBLIC_KEY_DER_ENCODED, - password=b'mypassword', + password=b"mypassword", wrapping_algorithm=_WRAPPING_ALGORITHM, ), ] diff --git a/test/unit/test_keyring_raw_aes.py b/test/unit/test_keyring_raw_aes.py index b0eea4508..390330f58 100644 --- a/test/unit/test_keyring_raw_aes.py +++ b/test/unit/test_keyring_raw_aes.py @@ -12,24 +12,33 @@ # language governing permissions and limitations under the License. """Unit tests for Raw AES keyring.""" -import pytest import os -from aws_encryption_sdk.identifiers import KeyringTraceFlag, WrappingAlgorithm, Algorithm -from aws_encryption_sdk.keyring.base import EncryptedDataKey, Keyring -from aws_encryption_sdk.keyring.raw_keyring import RawAESKeyring, generate_data_key, GenerateKeyError -from aws_encryption_sdk.structures import MasterKeyInfo -from aws_encryption_sdk.materials_managers import EncryptionMaterials - -from .test_utils import _ENCRYPTION_MATERIALS_WITH_DATA_KEY, _PROVIDER_ID, _WRAPPING_KEY, _DATA_KEY, _KEY_ID, \ - _DECRYPTION_MATERIALS_WITH_DATA_KEY, _ENCRYPTION_CONTEXT, _ENCRYPTED_DATA_KEY_AES, _SIGNING_KEY, \ - _DECRYPTION_MATERIALS_WITHOUT_DATA_KEY, _ENCRYPTION_MATERIALS_WITHOUT_DATA_KEY +import pytest +from pytest_mock import mocker # noqa pylint: disable=unused-import -import aws_encryption_sdk.keyring.raw_keyring import aws_encryption_sdk.key_providers.raw +import aws_encryption_sdk.keyring.raw_keyring +from aws_encryption_sdk.identifiers import Algorithm, KeyringTraceFlag, WrappingAlgorithm from aws_encryption_sdk.internal.crypto.wrapping_keys import WrappingKey -from pytest_mock import mocker # noqa pylint: disable=unused-import +from aws_encryption_sdk.keyring.base import EncryptedDataKey, Keyring +from aws_encryption_sdk.keyring.raw_keyring import GenerateKeyError, RawAESKeyring, generate_data_key +from aws_encryption_sdk.materials_managers import EncryptionMaterials +from aws_encryption_sdk.structures import MasterKeyInfo +from .test_utils import ( + _DATA_KEY, + _ENCRYPTED_DATA_KEY_AES, + _ENCRYPTION_CONTEXT, + _KEY_ID, + _PROVIDER_ID, + _SIGNING_KEY, + _WRAPPING_KEY, + get_decryption_materials_with_data_encryption_key, + get_decryption_materials_without_data_encryption_key, + get_encryption_materials_with_data_encryption_key, + get_encryption_materials_without_data_encryption_key, +) try: # Python 3.5.0 and 3.5.1 have incompatible typing modules from typing import Iterable # noqa pylint: disable=unused-import @@ -78,8 +87,7 @@ def test_valid_parameters(): def test_missing_required_parameters(): with pytest.raises(Exception) as exc_info: RawAESKeyring( - key_namespace=_PROVIDER_ID, - wrapping_algorithm=WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING, + key_namespace=_PROVIDER_ID, wrapping_algorithm=WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING ) assert exc_info.errisinstance(TypeError) @@ -103,7 +111,7 @@ def test_on_encrypt_when_data_encryption_key_given(patch_generate_data_key): wrapping_key=_WRAPPING_KEY, ) - test = test_raw_aes_keyring.on_encrypt(encryption_materials=_ENCRYPTION_MATERIALS_WITH_DATA_KEY) + test = test_raw_aes_keyring.on_encrypt(encryption_materials=get_encryption_materials_with_data_encryption_key()) # Check if keyring is generated assert not patch_generate_data_key.called @@ -116,7 +124,7 @@ def test_keyring_trace_on_encrypt_when_data_encryption_key_given(): wrapping_key=_WRAPPING_KEY, ) - test = test_raw_aes_keyring.on_encrypt(encryption_materials=_ENCRYPTION_MATERIALS_WITH_DATA_KEY) + test = test_raw_aes_keyring.on_encrypt(encryption_materials=get_encryption_materials_with_data_encryption_key()) for keyring_trace in test.keyring_trace: if keyring_trace.wrapping_key.key_info == _KEY_ID: @@ -133,9 +141,11 @@ def test_on_encrypt_when_data_encryption_key_not_given(): wrapping_key=_WRAPPING_KEY, ) - original_number_of_encrypted_data_keys = len(_ENCRYPTION_MATERIALS_WITHOUT_DATA_KEY.encrypted_data_keys) + original_number_of_encrypted_data_keys = len( + get_encryption_materials_without_data_encryption_key().encrypted_data_keys + ) - test = test_raw_aes_keyring.on_encrypt(encryption_materials=_ENCRYPTION_MATERIALS_WITHOUT_DATA_KEY) + test = test_raw_aes_keyring.on_encrypt(encryption_materials=get_encryption_materials_without_data_encryption_key()) # Check if data key is generated assert test.data_encryption_key and test.data_encryption_key is not None @@ -144,8 +154,10 @@ def test_on_encrypt_when_data_encryption_key_not_given(): encrypted_flag_count = 0 for keyring_trace in test.keyring_trace: - if keyring_trace.wrapping_key.key_info == _KEY_ID and KeyringTraceFlag.WRAPPING_KEY_GENERATED_DATA_KEY \ - in keyring_trace.flags: + if ( + keyring_trace.wrapping_key.key_info == _KEY_ID + and KeyringTraceFlag.WRAPPING_KEY_GENERATED_DATA_KEY in keyring_trace.flags + ): # Check keyring trace contains KeyringTraceFlag.WRAPPING_KEY_GENERATED_DATA_KEY generated_flag_count += 1 if KeyringTraceFlag.WRAPPING_KEY_ENCRYPTED_DATA_KEY in keyring_trace.flags: @@ -166,17 +178,16 @@ def test_on_decrypt_when_data_key_given(patch_decrypt_data_key): wrapping_key=_WRAPPING_KEY, ) test = test_raw_aes_keyring.on_decrypt( - decryption_materials=_DECRYPTION_MATERIALS_WITH_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\x7f.}\x87\x16,\x11n#\xc8p" - b"\xdb\xbf\x94\x86*Q\x06\xd2\xf5\xdah\x08\xa4p\x81\xf7\xf4G\ - x07FzE\xde", - ) - ] + decryption_materials=get_decryption_materials_with_data_encryption_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\x7f.}\x87\x16,\x11n#\xc8p" + b"\xdb\xbf\x94\x86*Q\x06\xd2\xf5\xdah\x08\xa4p\x81\xf7\xf4G\ + x07FzE\xde", + ) + ], ) assert not patch_decrypt_data_key.called @@ -189,17 +200,16 @@ def test_keyring_trace_on_decrypt_when_data_key_given(): wrapping_key=_WRAPPING_KEY, ) test = test_raw_aes_keyring.on_decrypt( - decryption_materials=_DECRYPTION_MATERIALS_WITH_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\x7f.}\x87\x16,\x11n#\xc8p" - b"\xdb\xbf\x94\x86*Q\x06\xd2\xf5\xdah\x08\xa4p\x81\xf7\xf4G\ - x07FzE\xde", - ) - ] + decryption_materials=get_decryption_materials_with_data_encryption_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\x7f.}\x87\x16,\x11n#\xc8p" + b"\xdb\xbf\x94\x86*Q\x06\xd2\xf5\xdah\x08\xa4p\x81\xf7\xf4G\ + x07FzE\xde", + ) + ], ) for keyring_trace in test.keyring_trace: if keyring_trace.wrapping_key.key_info == _KEY_ID: @@ -215,8 +225,9 @@ def test_on_decrypt_when_data_key_and_edk_not_provided(patch_decrypt_data_key): wrapping_key=_WRAPPING_KEY, ) - test = test_raw_aes_keyring.on_decrypt(decryption_materials=_DECRYPTION_MATERIALS_WITHOUT_DATA_KEY, - encrypted_data_keys=[]) + test = test_raw_aes_keyring.on_decrypt( + decryption_materials=get_decryption_materials_without_data_encryption_key(), encrypted_data_keys=[] + ) assert not patch_decrypt_data_key.called for keyring_trace in test.keyring_trace: @@ -234,20 +245,19 @@ def test_on_decrypt_when_data_key_not_provided_and_edk_not_in_keyring(patch_decr wrapping_key=_WRAPPING_KEY, ) - test = test_raw_aes_keyring.on_decrypt(decryption_materials=_DECRYPTION_MATERIALS_WITHOUT_DATA_KEY, - encrypted_data_keys=[ - EncryptedDataKey( - key_provider=MasterKeyInfo( - provider_id=_PROVIDER_ID, - key_info=b"5430b043-5843-4629-869c-64794af77ada"), - encrypted_data_key=b"\xde^\x97\x7f\x84\xe9\x9e\x98\xd0\xe2\xf8\ + test = test_raw_aes_keyring.on_decrypt( + decryption_materials=get_decryption_materials_without_data_encryption_key(), + encrypted_data_keys=[ + EncryptedDataKey( + key_provider=MasterKeyInfo(provider_id=_PROVIDER_ID, key_info=b"5430b043-5843-4629-869c-64794af77ada"), + 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\ + b"\xdb\xbf\x94\x86*Q\x06\xd2\xf5\xdah\x08\xa4p\ x81\xf7\xf4G\ x07FzE\xde", - ) - ] - ) + ) + ], + ) assert not patch_decrypt_data_key.called for keyring_trace in test.keyring_trace: @@ -266,12 +276,13 @@ def test_on_decrypt_when_data_key_not_provided_and_edk_provided(patch_decrypt_da wrapping_key=_WRAPPING_KEY, ) - test = test_raw_aes_keyring.on_decrypt(decryption_materials=_DECRYPTION_MATERIALS_WITHOUT_DATA_KEY, - encrypted_data_keys=[_ENCRYPTED_DATA_KEY_AES] - ) - assert patch_decrypt_data_key.called_once_with(encrypted_wrapped_data_key=_ENCRYPTED_DATA_KEY_AES, - encryption_context=_ENCRYPTION_CONTEXT - ) + test = test_raw_aes_keyring.on_decrypt( + decryption_materials=get_decryption_materials_without_data_encryption_key(), + encrypted_data_keys=[_ENCRYPTED_DATA_KEY_AES], + ) + assert patch_decrypt_data_key.called_once_with( + encrypted_wrapped_data_key=_ENCRYPTED_DATA_KEY_AES, encryption_context=_ENCRYPTION_CONTEXT + ) def test_keyring_trace_when_data_key_not_provided_and_edk_provided(): @@ -282,9 +293,10 @@ def test_keyring_trace_when_data_key_not_provided_and_edk_provided(): wrapping_key=_WRAPPING_KEY, ) - test = test_raw_aes_keyring.on_decrypt(decryption_materials=_DECRYPTION_MATERIALS_WITHOUT_DATA_KEY, - encrypted_data_keys=[_ENCRYPTED_DATA_KEY_AES] - ) + test = test_raw_aes_keyring.on_decrypt( + decryption_materials=get_decryption_materials_without_data_encryption_key(), + encrypted_data_keys=[_ENCRYPTED_DATA_KEY_AES], + ) decrypted_flag_count = 0 for keyring_trace in test.keyring_trace: @@ -297,39 +309,32 @@ def test_keyring_trace_when_data_key_not_provided_and_edk_provided(): def test_error_when_data_key_not_generated(patch_os_urandom): patch_os_urandom.side_effect = NotImplementedError with pytest.raises(GenerateKeyError) as exc_info: - generate_data_key(encryption_materials=EncryptionMaterials( - algorithm=Algorithm.AES_256_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384, - encryption_context=_ENCRYPTION_CONTEXT, - signing_key=_SIGNING_KEY, - ), - key_provider=MasterKeyInfo(provider_id=_PROVIDER_ID, - key_info=_KEY_ID)) + generate_data_key( + encryption_materials=get_encryption_materials_without_data_encryption_key(), + key_provider=MasterKeyInfo(provider_id=_PROVIDER_ID, key_info=_KEY_ID), + ) assert exc_info.match("Unable to generate data encryption key.") def test_generate_data_key_error_when_data_key_exists(): with pytest.raises(TypeError) as exc_info: - generate_data_key(encryption_materials=_ENCRYPTION_MATERIALS_WITH_DATA_KEY, - key_provider=MasterKeyInfo( - provider_id=_PROVIDER_ID, - key_info=_KEY_ID - ) - ) + generate_data_key( + encryption_materials=get_encryption_materials_with_data_encryption_key(), + key_provider=MasterKeyInfo(provider_id=_PROVIDER_ID, key_info=_KEY_ID), + ) assert exc_info.match("Data encryption key already exists.") def test_generate_data_key_keyring_trace(): 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, - ) - plaintext = generate_data_key(encryption_materials=encryption_materials_without_data_key, - key_provider=MasterKeyInfo( - provider_id=_PROVIDER_ID, - key_info=_KEY_ID - ) - ) + algorithm=Algorithm.AES_256_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384, + encryption_context=_ENCRYPTION_CONTEXT, + signing_key=_SIGNING_KEY, + ) + plaintext = generate_data_key( + encryption_materials=encryption_materials_without_data_key, + key_provider=MasterKeyInfo(provider_id=_PROVIDER_ID, key_info=_KEY_ID), + ) generate_flag_count = 0 for keyring_trace in encryption_materials_without_data_key.keyring_trace: diff --git a/test/unit/test_keyring_raw_rsa.py b/test/unit/test_keyring_raw_rsa.py index 523f86126..08c8aa611 100644 --- a/test/unit/test_keyring_raw_rsa.py +++ b/test/unit/test_keyring_raw_rsa.py @@ -14,20 +14,29 @@ import pytest from cryptography.hazmat.primitives.asymmetric import rsa +from pytest_mock import mocker # noqa pylint: disable=unused-import -from aws_encryption_sdk.identifiers import Algorithm, KeyringTraceFlag, WrappingAlgorithm -from aws_encryption_sdk.keyring.base import EncryptedDataKey, Keyring -from aws_encryption_sdk.keyring.raw_keyring import RawRSAKeyring -from aws_encryption_sdk.materials_managers import DecryptionMaterials, EncryptionMaterials -from aws_encryption_sdk.structures import MasterKeyInfo -from .test_utils import _KEY_ID, _ENCRYPTION_CONTEXT, _SIGNING_KEY, _DATA_KEY, _PROVIDER_ID, _ENCRYPTED_DATA_KEY_RSA, \ - _DECRYPTION_MATERIALS_WITH_DATA_KEY, _ENCRYPTION_MATERIALS_WITH_DATA_KEY, _PUBLIC_EXPONENT, _KEY_SIZE, _BACKEND - -import aws_encryption_sdk.keyring.raw_keyring import aws_encryption_sdk.key_providers.raw +import aws_encryption_sdk.keyring.raw_keyring +from aws_encryption_sdk.identifiers import KeyringTraceFlag, WrappingAlgorithm from aws_encryption_sdk.internal.crypto.wrapping_keys import WrappingKey -from pytest_mock import mocker # noqa pylint: disable=unused-import +from aws_encryption_sdk.keyring.base import EncryptedDataKey, Keyring +from aws_encryption_sdk.keyring.raw_keyring import RawRSAKeyring +from .test_utils import ( + _BACKEND, + _DATA_KEY, + _ENCRYPTED_DATA_KEY_RSA, + _ENCRYPTION_CONTEXT, + _KEY_ID, + _KEY_SIZE, + _PROVIDER_ID, + _PUBLIC_EXPONENT, + get_decryption_materials_with_data_encryption_key, + get_decryption_materials_without_data_encryption_key, + get_encryption_materials_with_data_encryption_key, + get_encryption_materials_without_data_encryption_key, +) try: # Python 3.5.0 and 3.5.1 have incompatible typing modules from typing import Iterable # noqa pylint: disable=unused-import @@ -37,18 +46,6 @@ pytestmark = [pytest.mark.unit, pytest.mark.local] -_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, -) - -_DECRYPTION_MATERIALS_WITHOUT_DATA_KEY = DecryptionMaterials( - algorithm=Algorithm.AES_256_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384, - verification_key=b"ex_verification_key", - encryption_context=_ENCRYPTION_CONTEXT, -) - @pytest.fixture def patch_generate_data_key(mocker): @@ -77,9 +74,9 @@ def test_valid_parameters(): key_namespace=_PROVIDER_ID, key_name=_KEY_ID, wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, - private_wrapping_key=rsa.generate_private_key(public_exponent=_PUBLIC_EXPONENT, - key_size=_KEY_SIZE, - backend=_BACKEND) + private_wrapping_key=rsa.generate_private_key( + public_exponent=_PUBLIC_EXPONENT, key_size=_KEY_SIZE, backend=_BACKEND + ), ) assert test.key_namespace == _PROVIDER_ID assert test.key_name == _KEY_ID @@ -92,9 +89,9 @@ def test_missing_required_parameters(): RawRSAKeyring( key_namespace=_PROVIDER_ID, wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, - private_wrapping_key=rsa.generate_private_key(public_exponent=_PUBLIC_EXPONENT, - key_size=_KEY_SIZE, - backend=_BACKEND) + private_wrapping_key=rsa.generate_private_key( + public_exponent=_PUBLIC_EXPONENT, key_size=_KEY_SIZE, backend=_BACKEND + ), ) assert exc_info.errisinstance(TypeError) @@ -113,9 +110,7 @@ def test_invalid_values_as_parameter(): def test_public_and_private_key_not_provided(): with pytest.raises(TypeError) as exc_info: RawRSAKeyring( - key_namespace=_PROVIDER_ID, - key_name=_KEY_ID, - wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, + key_namespace=_PROVIDER_ID, key_name=_KEY_ID, wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1 ) assert exc_info.match("At least one of public key or private key must be provided.") @@ -125,12 +120,12 @@ def test_on_encrypt_when_data_encryption_key_given(patch_generate_data_key): key_namespace=_PROVIDER_ID, key_name=_KEY_ID, wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, - private_wrapping_key=rsa.generate_private_key(public_exponent=_PUBLIC_EXPONENT, - key_size=_KEY_SIZE, - backend=_BACKEND) + private_wrapping_key=rsa.generate_private_key( + public_exponent=_PUBLIC_EXPONENT, key_size=_KEY_SIZE, backend=_BACKEND + ), ) - test = test_raw_rsa_keyring.on_encrypt(encryption_materials=_ENCRYPTION_MATERIALS_WITH_DATA_KEY) + test = test_raw_rsa_keyring.on_encrypt(encryption_materials=get_encryption_materials_with_data_encryption_key()) # Check if keyring is generated assert not patch_generate_data_key.called @@ -140,12 +135,12 @@ def test_keyring_trace_on_encrypt_when_data_encryption_key_given(): key_namespace=_PROVIDER_ID, key_name=_KEY_ID, wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, - private_wrapping_key=rsa.generate_private_key(public_exponent=_PUBLIC_EXPONENT, - key_size=_KEY_SIZE, - backend=_BACKEND), + private_wrapping_key=rsa.generate_private_key( + public_exponent=_PUBLIC_EXPONENT, key_size=_KEY_SIZE, backend=_BACKEND + ), ) - test = test_raw_rsa_keyring.on_encrypt(encryption_materials=_ENCRYPTION_MATERIALS_WITH_DATA_KEY) + test = test_raw_rsa_keyring.on_encrypt(encryption_materials=get_encryption_materials_with_data_encryption_key()) for keyring_trace in test.keyring_trace: if keyring_trace.wrapping_key.key_info == _KEY_ID: @@ -158,14 +153,16 @@ def test_on_encrypt_when_data_encryption_key_not_given(): key_namespace=_PROVIDER_ID, key_name=_KEY_ID, wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, - private_wrapping_key=rsa.generate_private_key(public_exponent=_PUBLIC_EXPONENT, - key_size=_KEY_SIZE, - backend=_BACKEND), + private_wrapping_key=rsa.generate_private_key( + public_exponent=_PUBLIC_EXPONENT, key_size=_KEY_SIZE, backend=_BACKEND + ), ) - original_number_of_encrypted_data_keys = len(_ENCRYPTION_MATERIALS_WITHOUT_DATA_KEY.encrypted_data_keys) + original_number_of_encrypted_data_keys = len( + get_encryption_materials_without_data_encryption_key().encrypted_data_keys + ) - test = test_raw_rsa_keyring.on_encrypt(encryption_materials=_ENCRYPTION_MATERIALS_WITHOUT_DATA_KEY) + test = test_raw_rsa_keyring.on_encrypt(encryption_materials=get_encryption_materials_without_data_encryption_key()) # Check if data key is generated assert test.data_encryption_key and test.data_encryption_key is not None @@ -174,8 +171,10 @@ def test_on_encrypt_when_data_encryption_key_not_given(): encrypted_flag_count = 0 for keyring_trace in test.keyring_trace: - if keyring_trace.wrapping_key.key_info == _KEY_ID and KeyringTraceFlag.WRAPPING_KEY_GENERATED_DATA_KEY \ - in keyring_trace.flags: + if ( + keyring_trace.wrapping_key.key_info == _KEY_ID + and KeyringTraceFlag.WRAPPING_KEY_GENERATED_DATA_KEY in keyring_trace.flags + ): # Check keyring trace contains KeyringTraceFlag.WRAPPING_KEY_GENERATED_DATA_KEY generated_flag_count += 1 if KeyringTraceFlag.WRAPPING_KEY_ENCRYPTED_DATA_KEY in keyring_trace.flags: @@ -193,23 +192,13 @@ def test_on_decrypt_when_data_key_given(patch_decrypt_data_key): key_namespace=_PROVIDER_ID, key_name=_KEY_ID, wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, - private_wrapping_key=rsa.generate_private_key(public_exponent=_PUBLIC_EXPONENT, - key_size=_KEY_SIZE, - backend=_BACKEND), + private_wrapping_key=rsa.generate_private_key( + public_exponent=_PUBLIC_EXPONENT, key_size=_KEY_SIZE, backend=_BACKEND + ), ) test = test_raw_rsa_keyring.on_decrypt( - decryption_materials=_DECRYPTION_MATERIALS_WITH_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\x7f.}\x87\x16,\x11n#\xc8p" - b"\xdb\xbf\x94\x86*Q\x06\xd2\xf5\xdah\x08\xa4p\x81\xf7\xf4G\ - x07FzE\xde", - ) - ] + decryption_materials=get_decryption_materials_with_data_encryption_key(), + encrypted_data_keys=[_ENCRYPTED_DATA_KEY_RSA], ) assert not patch_decrypt_data_key.called @@ -219,23 +208,13 @@ def test_keyring_trace_on_decrypt_when_data_key_given(): key_namespace=_PROVIDER_ID, key_name=_KEY_ID, wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, - private_wrapping_key=rsa.generate_private_key(public_exponent=_PUBLIC_EXPONENT, - key_size=_KEY_SIZE, - backend=_BACKEND), + private_wrapping_key=rsa.generate_private_key( + public_exponent=_PUBLIC_EXPONENT, key_size=_KEY_SIZE, backend=_BACKEND + ), ) test = test_raw_rsa_keyring.on_decrypt( - decryption_materials=_DECRYPTION_MATERIALS_WITH_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\x7f.}\x87\x16,\x11n#\xc8p" - b"\xdb\xbf\x94\x86*Q\x06\xd2\xf5\xdah\x08\xa4p\x81\xf7\xf4G\ - x07FzE\xde", - ) - ] + decryption_materials=get_decryption_materials_with_data_encryption_key(), + encrypted_data_keys=[_ENCRYPTED_DATA_KEY_RSA], ) for keyring_trace in test.keyring_trace: if keyring_trace.wrapping_key.key_info == _KEY_ID: @@ -248,13 +227,14 @@ def test_on_decrypt_when_data_key_and_edk_not_provided(patch_decrypt_data_key): key_namespace=_PROVIDER_ID, key_name=_KEY_ID, wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, - private_wrapping_key=rsa.generate_private_key(public_exponent=_PUBLIC_EXPONENT, - key_size=_KEY_SIZE, - backend=_BACKEND), + private_wrapping_key=rsa.generate_private_key( + public_exponent=_PUBLIC_EXPONENT, key_size=_KEY_SIZE, backend=_BACKEND + ), ) - test = test_raw_rsa_keyring.on_decrypt(decryption_materials=_DECRYPTION_MATERIALS_WITHOUT_DATA_KEY, - encrypted_data_keys=[]) + test = test_raw_rsa_keyring.on_decrypt( + decryption_materials=get_decryption_materials_without_data_encryption_key(), encrypted_data_keys=[] + ) assert not patch_decrypt_data_key.called for keyring_trace in test.keyring_trace: @@ -268,25 +248,15 @@ def test_on_decrypt_when_data_key_not_provided_and_edk_not_in_keyring(patch_decr key_namespace=_PROVIDER_ID, key_name=_KEY_ID, wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, - private_wrapping_key=rsa.generate_private_key(public_exponent=_PUBLIC_EXPONENT, - key_size=_KEY_SIZE, - backend=_BACKEND), + private_wrapping_key=rsa.generate_private_key( + public_exponent=_PUBLIC_EXPONENT, key_size=_KEY_SIZE, backend=_BACKEND + ), ) - test = test_raw_rsa_keyring.on_decrypt(decryption_materials=_DECRYPTION_MATERIALS_WITHOUT_DATA_KEY, - encrypted_data_keys=[ - EncryptedDataKey( - key_provider=MasterKeyInfo( - provider_id=_PROVIDER_ID, - key_info=b"5430b043-5843-4629-869c-64794af77ada"), - 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", - ) - ] - ) + test = test_raw_rsa_keyring.on_decrypt( + decryption_materials=get_decryption_materials_without_data_encryption_key(), + encrypted_data_keys=[_ENCRYPTED_DATA_KEY_RSA], + ) assert not patch_decrypt_data_key.called for keyring_trace in test.keyring_trace: @@ -302,17 +272,18 @@ def test_on_decrypt_when_data_key_not_provided_and_edk_provided(patch_decrypt_da key_namespace=_PROVIDER_ID, key_name=_KEY_ID, wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, - private_wrapping_key=rsa.generate_private_key(public_exponent=_PUBLIC_EXPONENT, - key_size=_KEY_SIZE, - backend=_BACKEND), + private_wrapping_key=rsa.generate_private_key( + public_exponent=_PUBLIC_EXPONENT, key_size=_KEY_SIZE, backend=_BACKEND + ), ) - test = test_raw_rsa_keyring.on_decrypt(decryption_materials=_DECRYPTION_MATERIALS_WITHOUT_DATA_KEY, - encrypted_data_keys=[_ENCRYPTED_DATA_KEY_RSA] - ) - assert patch_decrypt_data_key.called_once_with(encrypted_wrapped_data_key=_ENCRYPTED_DATA_KEY_RSA, - encryption_context=_ENCRYPTION_CONTEXT - ) + test = test_raw_rsa_keyring.on_decrypt( + decryption_materials=get_decryption_materials_without_data_encryption_key(), + encrypted_data_keys=[_ENCRYPTED_DATA_KEY_RSA], + ) + assert patch_decrypt_data_key.called_once_with( + encrypted_wrapped_data_key=_ENCRYPTED_DATA_KEY_RSA, encryption_context=_ENCRYPTION_CONTEXT + ) def test_keyring_trace_when_data_key_not_provided_and_edk_provided(): @@ -320,16 +291,17 @@ def test_keyring_trace_when_data_key_not_provided_and_edk_provided(): key_namespace=_PROVIDER_ID, key_name=_KEY_ID, wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, - private_wrapping_key=rsa.generate_private_key(public_exponent=_PUBLIC_EXPONENT, - key_size=_KEY_SIZE, - backend=_BACKEND), + private_wrapping_key=rsa.generate_private_key( + public_exponent=_PUBLIC_EXPONENT, key_size=_KEY_SIZE, backend=_BACKEND + ), ) - test = test_raw_rsa_keyring.on_decrypt(decryption_materials=_DECRYPTION_MATERIALS_WITHOUT_DATA_KEY, - encrypted_data_keys=test_raw_rsa_keyring.on_encrypt( - encryption_materials=_ENCRYPTION_MATERIALS_WITHOUT_DATA_KEY). - encrypted_data_keys - ) + test = test_raw_rsa_keyring.on_decrypt( + decryption_materials=get_decryption_materials_without_data_encryption_key(), + encrypted_data_keys=test_raw_rsa_keyring.on_encrypt( + encryption_materials=get_encryption_materials_without_data_encryption_key() + ).encrypted_data_keys, + ) decrypted_flag_count = 0 for keyring_trace in test.keyring_trace: diff --git a/test/unit/test_utils.py b/test/unit/test_utils.py index f2ccf87a9..76079f56e 100644 --- a/test/unit/test_utils.py +++ b/test/unit/test_utils.py @@ -15,17 +15,17 @@ import io import pytest +from cryptography.hazmat.backends import default_backend from mock import MagicMock, patch, sentinel -from cryptography.hazmat.backends import default_backend 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.identifiers import Algorithm, KeyringTraceFlag +from aws_encryption_sdk.internal.defaults import MAX_FRAME_SIZE, MESSAGE_ID_LENGTH from aws_encryption_sdk.keyring.base import EncryptedDataKey, Keyring from aws_encryption_sdk.materials_managers import DecryptionMaterials, EncryptionMaterials -from aws_encryption_sdk.structures import KeyringTrace, MasterKeyInfo, RawDataKey, DataKey +from aws_encryption_sdk.structures import DataKey, KeyringTrace, MasterKeyInfo, RawDataKey from .test_values import VALUES from .unit_test_utils import assert_prepped_stream_identity @@ -52,92 +52,99 @@ _BACKEND = default_backend() _ENCRYPTED_DATA_KEY_AES = EncryptedDataKey( - key_provider=MasterKeyInfo( - provider_id='Random Raw Keys', - key_info=b'5325b043-5843-4629-869c-64794af77ada\x00\x00\x00\x80' - b'\x00\x00\x00\x0c\xc7\xd5d\xc9\xc5\xf21\x8d\x8b\xf9H' - b'\xbb'), - encrypted_data_key=b'\xf3+\x15n\xe6`\xbe\xfe\xf0\x9e1\xe5\x9b' - b'\xaf\xfe\xdaT\xbb\x17\x14\xfd} o\xdd\xf1' - b'\xbc\xe1C\xa5J\xd8\xc7\x15\xc2\x90t=\xb9' - b'\xfd;\x94lTu/6\xfe' - -) - -_ENCRYPTED_DATA_KEY_RSA = EncryptedDataKey( - key_provider=MasterKeyInfo( - provider_id='Random Raw Keys', - key_info=_KEY_ID), - encrypted_data_key=b'\xf3+\x15n\xe6`\xbe\xfe\xf0\x9e1\xe5\x9b' - b'\xaf\xfe\xdaT\xbb\x17\x14\xfd} o\xdd\xf1' - b'\xbc\xe1C\xa5J\xd8\xc7\x15\xc2\x90t=\xb9' - b'\xfd;\x94lTu/6\xfe' - -) - - -_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=b"5430b043-5843-4629-869c-64794af77ada"), - data_key=b'*!\xa1"^-(\xf3\x105\x05i@B\xc2\xa2\xb7\xdd\xd5\xd5\xa9\xddm\xfae\xa8\\$\xf9d\x1e(', + key_provider=MasterKeyInfo( + provider_id="Random Raw Keys", + key_info=b"5325b043-5843-4629-869c-64794af77ada\x00\x00\x00\x80" + b"\x00\x00\x00\x0c\xc7\xd5d\xc9\xc5\xf21\x8d\x8b\xf9H" + b"\xbb", ), - encryption_context=_ENCRYPTION_CONTEXT, - signing_key=_SIGNING_KEY, - keyring_trace=[ - KeyringTrace( - wrapping_key=MasterKeyInfo(provider_id=_PROVIDER_ID, key_info=b"5430b043-5843-4629-869c-64794af77ada"), - flags={KeyringTraceFlag.WRAPPING_KEY_GENERATED_DATA_KEY}, - ) - ], + encrypted_data_key=b"\xf3+\x15n\xe6`\xbe\xfe\xf0\x9e1\xe5\x9b" + b"\xaf\xfe\xdaT\xbb\x17\x14\xfd} o\xdd\xf1" + b"\xbc\xe1C\xa5J\xd8\xc7\x15\xc2\x90t=\xb9" + b"\xfd;\x94lTu/6\xfe", ) -_ENCRYPTION_MATERIALS_WITH_ENCRYPTED_DATA_KEY_AES = 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=[ - _ENCRYPTED_DATA_KEY_AES - ], - 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, +_ENCRYPTED_DATA_KEY_RSA = EncryptedDataKey( + key_provider=MasterKeyInfo(provider_id="Random Raw Keys", key_info=_KEY_ID), + encrypted_data_key=b"\xf3+\x15n\xe6`\xbe\xfe\xf0\x9e1\xe5\x9b" + b"\xaf\xfe\xdaT\xbb\x17\x14\xfd} o\xdd\xf1" + b"\xbc\xe1C\xa5J\xd8\xc7\x15\xc2\x90t=\xb9" + b"\xfd;\x94lTu/6\xfe", ) -_DECRYPTION_MATERIALS_WITHOUT_DATA_KEY = DecryptionMaterials( - algorithm=Algorithm.AES_256_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384, - verification_key=b"ex_verification_key", - encryption_context=_ENCRYPTION_CONTEXT, -) -_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=b"5430b043-5843-4629-869c-64794af77ada"), - 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=b"5430b043-5843-4629-869c-64794af77ada"), - flags={KeyringTraceFlag.WRAPPING_KEY_DECRYPTED_DATA_KEY}, - ) - ], -) +def get_encryption_materials_with_data_encryption_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=b"5430b043-5843-4629-869c-64794af77ada"), + 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=b"5430b043-5843-4629-869c-64794af77ada"), + flags={KeyringTraceFlag.WRAPPING_KEY_GENERATED_DATA_KEY}, + ) + ], + ) + + +def get_encryption_materials_with_encrypted_data_key_aes(): + 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=[_ENCRYPTED_DATA_KEY_AES], + 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_without_data_encryption_key(): + return EncryptionMaterials( + algorithm=Algorithm.AES_256_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384, + encryption_context=_ENCRYPTION_CONTEXT, + signing_key=_SIGNING_KEY, + ) + + +def get_decryption_materials_without_data_encryption_key(): + return DecryptionMaterials( + algorithm=Algorithm.AES_256_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384, + verification_key=b"ex_verification_key", + encryption_context=_ENCRYPTION_CONTEXT, + ) + + +def get_decryption_materials_with_data_encryption_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=b"5430b043-5843-4629-869c-64794af77ada"), + 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=b"5430b043-5843-4629-869c-64794af77ada"), + flags={KeyringTraceFlag.WRAPPING_KEY_DECRYPTED_DATA_KEY}, + ) + ], + ) def test_prep_stream_data_passthrough(): From 00a7dad2abba90b9e046aeb1ec7dd7a7fb565f7c Mon Sep 17 00:00:00 2001 From: MeghaShetty Date: Sat, 27 Jul 2019 14:37:32 -0700 Subject: [PATCH 106/119] Delete sample_aes.py --- examples/src/sample_aes.py | 81 -------------------------------------- 1 file changed, 81 deletions(-) delete mode 100644 examples/src/sample_aes.py diff --git a/examples/src/sample_aes.py b/examples/src/sample_aes.py deleted file mode 100644 index 23d91e1a1..000000000 --- a/examples/src/sample_aes.py +++ /dev/null @@ -1,81 +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 Algorithm, WrappingAlgorithm -from aws_encryption_sdk.keyring.raw_keyring import RawAESKeyring -from aws_encryption_sdk.materials_managers import DecryptionMaterials, EncryptionMaterials - -pytestmark = [pytest.mark.functional, pytest.mark.local] - -_ENCRYPTION_CONTEXT = {"key_a": "value_a", "key_b": "value_b", "key_c": "value_c"} -_PROVIDER_ID = "Random Raw Keys" -_KEY_ID = b"5325b043-5843-4629-869c-64794af77ada" -_WRAPPING_KEY = b"12345678901234567890123456789012" -_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, -) - - -def sample_aes_encryption_decryption(): - - # Initializing attributes - key_namespace = _PROVIDER_ID - key_name = _KEY_ID - _wrapping_algorithm = WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING - - # Creating an instance of a raw AES keyring - sample_raw_aes_keyring = RawAESKeyring( - key_namespace=key_namespace, - key_name=key_name, - wrapping_key=_WRAPPING_KEY, - wrapping_algorithm=_wrapping_algorithm, - ) - - # Call on_encrypt function for the keyring - encryption_materials = sample_raw_aes_keyring.on_encrypt(encryption_materials=_ENCRYPTION_MATERIALS) - - print("PLAINTEXT DATA KEY") - print(encryption_materials.data_encryption_key.data_key) - - print("ENCRYPTED DATA KEY") - print(encryption_materials.encrypted_data_keys[0].encrypted_data_key) - - # 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, - ) - - # Call on_decrypt function for the keyring - decryption_materials = sample_raw_aes_keyring.on_decrypt( - decryption_materials=decryption_materials, encrypted_data_keys=encryption_materials.encrypted_data_keys - ) - - print(decryption_materials.keyring_trace) - - print("DECRYPTED DATA KEY") - print(decryption_materials.data_encryption_key.data_key) - - # Check if the data keys match - assert encryption_materials.data_encryption_key == decryption_materials.data_encryption_key - - -sample_aes_encryption_decryption() From 29f69e0449e6dc4a8ae5a6eb71f7cb98360c5ad2 Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Sat, 27 Jul 2019 15:06:12 -0700 Subject: [PATCH 107/119] Corrected tox and pylint errors --- src/aws_encryption_sdk/keyring/raw_keyring.py | 6 +++--- test/functional/test_f_keyring_raw_rsa.py | 12 ++++++------ test/unit/test_keyring_raw_aes.py | 8 ++++---- test/unit/test_keyring_raw_rsa.py | 8 ++++---- 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/aws_encryption_sdk/keyring/raw_keyring.py b/src/aws_encryption_sdk/keyring/raw_keyring.py index da4d93707..27da9d257 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 @@ -259,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 @@ -299,7 +299,7 @@ def fromPEMEncoding( ) @classmethod - def fromDEREncoding( + def from_der_encoding( cls, key_namespace, # type: str key_name, # type: bytes diff --git a/test/functional/test_f_keyring_raw_rsa.py b/test/functional/test_f_keyring_raw_rsa.py index 24800bf17..bd0c1573d 100644 --- a/test/functional/test_f_keyring_raw_rsa.py +++ b/test/functional/test_f_keyring_raw_rsa.py @@ -167,39 +167,39 @@ public_exponent=_PUBLIC_EXPONENT, key_size=_KEY_SIZE, backend=_BACKEND ), ), - RawRSAKeyring.fromPEMEncoding( + RawRSAKeyring.from_pem_encoding( key_namespace=_PROVIDER_ID, key_name=_KEY_ID, private_encoded_key=_RAW_RSA_PRIVATE_KEY_PEM_ENCODED_WITHOUT_PASSWORD, wrapping_algorithm=_WRAPPING_ALGORITHM, ), - RawRSAKeyring.fromPEMEncoding( + RawRSAKeyring.from_pem_encoding( key_namespace=_PROVIDER_ID, key_name=_KEY_ID, private_encoded_key=_RAW_RSA_PRIVATE_KEY_PEM_ENCODED_WITH_PASSWORD, password=b"mypassword", wrapping_algorithm=_WRAPPING_ALGORITHM, ), - RawRSAKeyring.fromPEMEncoding( + RawRSAKeyring.from_pem_encoding( key_namespace=_PROVIDER_ID, key_name=_KEY_ID, public_encoded_key=_RAW_RSA_PUBLIC_KEY_PEM_ENCODED, wrapping_algorithm=_WRAPPING_ALGORITHM, ), - RawRSAKeyring.fromDEREncoding( + RawRSAKeyring.from_der_encoding( key_namespace=_PROVIDER_ID, key_name=_KEY_ID, private_encoded_key=_RAW_RSA_PRIVATE_KEY_DER_ENCODED_WITHOUT_PASSWORD, wrapping_algorithm=_WRAPPING_ALGORITHM, ), - RawRSAKeyring.fromDEREncoding( + RawRSAKeyring.from_der_encoding( key_namespace=_PROVIDER_ID, key_name=_KEY_ID, private_encoded_key=_RAW_RSA_PRIVATE_KEY_DER_ENCODED_WITH_PASSWORD, password=b"mypassword", wrapping_algorithm=_WRAPPING_ALGORITHM, ), - RawRSAKeyring.fromDEREncoding( + RawRSAKeyring.from_der_encoding( key_namespace=_PROVIDER_ID, key_name=_KEY_ID, public_encoded_key=_RAW_RSA_PUBLIC_KEY_DER_ENCODED, diff --git a/test/unit/test_keyring_raw_aes.py b/test/unit/test_keyring_raw_aes.py index 390330f58..52adff70b 100644 --- a/test/unit/test_keyring_raw_aes.py +++ b/test/unit/test_keyring_raw_aes.py @@ -111,7 +111,7 @@ def test_on_encrypt_when_data_encryption_key_given(patch_generate_data_key): wrapping_key=_WRAPPING_KEY, ) - test = test_raw_aes_keyring.on_encrypt(encryption_materials=get_encryption_materials_with_data_encryption_key()) + test_raw_aes_keyring.on_encrypt(encryption_materials=get_encryption_materials_with_data_encryption_key()) # Check if keyring is generated assert not patch_generate_data_key.called @@ -177,7 +177,7 @@ def test_on_decrypt_when_data_key_given(patch_decrypt_data_key): wrapping_algorithm=WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING, wrapping_key=_WRAPPING_KEY, ) - test = test_raw_aes_keyring.on_decrypt( + test_raw_aes_keyring.on_decrypt( decryption_materials=get_decryption_materials_with_data_encryption_key(), encrypted_data_keys=[ EncryptedDataKey( @@ -276,7 +276,7 @@ def test_on_decrypt_when_data_key_not_provided_and_edk_provided(patch_decrypt_da wrapping_key=_WRAPPING_KEY, ) - test = test_raw_aes_keyring.on_decrypt( + test_raw_aes_keyring.on_decrypt( decryption_materials=get_decryption_materials_without_data_encryption_key(), encrypted_data_keys=[_ENCRYPTED_DATA_KEY_AES], ) @@ -331,7 +331,7 @@ def test_generate_data_key_keyring_trace(): encryption_context=_ENCRYPTION_CONTEXT, signing_key=_SIGNING_KEY, ) - plaintext = generate_data_key( + generate_data_key( encryption_materials=encryption_materials_without_data_key, key_provider=MasterKeyInfo(provider_id=_PROVIDER_ID, key_info=_KEY_ID), ) diff --git a/test/unit/test_keyring_raw_rsa.py b/test/unit/test_keyring_raw_rsa.py index 08c8aa611..cce891bf8 100644 --- a/test/unit/test_keyring_raw_rsa.py +++ b/test/unit/test_keyring_raw_rsa.py @@ -20,7 +20,7 @@ import aws_encryption_sdk.keyring.raw_keyring from aws_encryption_sdk.identifiers import KeyringTraceFlag, WrappingAlgorithm from aws_encryption_sdk.internal.crypto.wrapping_keys import WrappingKey -from aws_encryption_sdk.keyring.base import EncryptedDataKey, Keyring +from aws_encryption_sdk.keyring.base import Keyring from aws_encryption_sdk.keyring.raw_keyring import RawRSAKeyring from .test_utils import ( @@ -125,7 +125,7 @@ def test_on_encrypt_when_data_encryption_key_given(patch_generate_data_key): ), ) - test = test_raw_rsa_keyring.on_encrypt(encryption_materials=get_encryption_materials_with_data_encryption_key()) + test_raw_rsa_keyring.on_encrypt(encryption_materials=get_encryption_materials_with_data_encryption_key()) # Check if keyring is generated assert not patch_generate_data_key.called @@ -196,7 +196,7 @@ def test_on_decrypt_when_data_key_given(patch_decrypt_data_key): public_exponent=_PUBLIC_EXPONENT, key_size=_KEY_SIZE, backend=_BACKEND ), ) - test = test_raw_rsa_keyring.on_decrypt( + test_raw_rsa_keyring.on_decrypt( decryption_materials=get_decryption_materials_with_data_encryption_key(), encrypted_data_keys=[_ENCRYPTED_DATA_KEY_RSA], ) @@ -277,7 +277,7 @@ def test_on_decrypt_when_data_key_not_provided_and_edk_provided(patch_decrypt_da ), ) - test = test_raw_rsa_keyring.on_decrypt( + test_raw_rsa_keyring.on_decrypt( decryption_materials=get_decryption_materials_without_data_encryption_key(), encrypted_data_keys=[_ENCRYPTED_DATA_KEY_RSA], ) From 2e43c1e0630b26de666036b1b30bad75cfbf8fc5 Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Sat, 27 Jul 2019 15:27:32 -0700 Subject: [PATCH 108/119] Removed print statements used while debugging --- src/aws_encryption_sdk/keyring/raw_keyring.py | 2 -- test/functional/test_f_keyring_raw_aes.py | 3 --- 2 files changed, 5 deletions(-) diff --git a/src/aws_encryption_sdk/keyring/raw_keyring.py b/src/aws_encryption_sdk/keyring/raw_keyring.py index 27da9d257..d10fa15c2 100644 --- a/src/aws_encryption_sdk/keyring/raw_keyring.py +++ b/src/aws_encryption_sdk/keyring/raw_keyring.py @@ -419,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/functional/test_f_keyring_raw_aes.py b/test/functional/test_f_keyring_raw_aes.py index e65520c6d..cf4c11490 100644 --- a/test/functional/test_f_keyring_raw_aes.py +++ b/test/functional/test_f_keyring_raw_aes.py @@ -110,9 +110,6 @@ def test_raw_aes_encryption_decryption(encryption_materials_samples, wrapping_al # Call on_encrypt function for the keyring encryption_materials = test_raw_aes_keyring.on_encrypt(encryption_materials=encryption_materials_samples) - print("PLAINTEXT DATA KEY") - print(encryption_materials.data_encryption_key) - # Generate decryption materials decryption_materials = DecryptionMaterials( algorithm=Algorithm.AES_256_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384, From 8ce5cc692f2383f955600220cb138cc20becf0f6 Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Wed, 31 Jul 2019 17:53:47 -0700 Subject: [PATCH 109/119] Partial commit for changes to tests --- test/unit/test_keyring_raw_aes.py | 15 ++-- test/unit/test_keyring_raw_rsa.py | 7 +- test/unit/test_utils.py | 118 +----------------------------- test/unit/unit_test_utils.py | 115 ++++++++++++++++++++++++++++- 4 files changed, 121 insertions(+), 134 deletions(-) diff --git a/test/unit/test_keyring_raw_aes.py b/test/unit/test_keyring_raw_aes.py index 52adff70b..914e2f259 100644 --- a/test/unit/test_keyring_raw_aes.py +++ b/test/unit/test_keyring_raw_aes.py @@ -26,7 +26,7 @@ from aws_encryption_sdk.materials_managers import EncryptionMaterials from aws_encryption_sdk.structures import MasterKeyInfo -from .test_utils import ( +from .unit_test_utils import ( _DATA_KEY, _ENCRYPTED_DATA_KEY_AES, _ENCRYPTION_CONTEXT, @@ -40,11 +40,6 @@ get_encryption_materials_without_data_encryption_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] @@ -85,22 +80,22 @@ def test_valid_parameters(): def test_missing_required_parameters(): - with pytest.raises(Exception) as exc_info: + with pytest.raises(TypeError) as exc_info: RawAESKeyring( key_namespace=_PROVIDER_ID, wrapping_algorithm=WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING ) - assert exc_info.errisinstance(TypeError) + assert exc_info.match("__init__() missing.*") def test_invalid_values_as_parameter(): - with pytest.raises(Exception) as exc_info: + with pytest.raises(TypeError) as exc_info: RawAESKeyring( key_namespace=_PROVIDER_ID, key_name=_KEY_ID, wrapping_algorithm=WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING, wrapping_key=WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING, ) - assert exc_info.errisinstance(TypeError) + assert exc_info.match("'_wrapping_key' must be Date: Thu, 1 Aug 2019 13:14:22 -0700 Subject: [PATCH 110/119] Partial commit for tests for raw keyrings --- src/aws_encryption_sdk/keyring/raw_keyring.py | 126 ++++++++---------- test/functional/test_f_keyring_raw_aes.py | 93 ++++++++++--- test/unit/test_keyring_raw_aes.py | 108 ++++++--------- test/unit/test_keyring_raw_rsa.py | 27 ++-- test/unit/unit_test_utils.py | 13 ++ 5 files changed, 196 insertions(+), 171 deletions(-) diff --git a/src/aws_encryption_sdk/keyring/raw_keyring.py b/src/aws_encryption_sdk/keyring/raw_keyring.py index d10fa15c2..064838fd2 100644 --- a/src/aws_encryption_sdk/keyring/raw_keyring.py +++ b/src/aws_encryption_sdk/keyring/raw_keyring.py @@ -41,7 +41,7 @@ _LOGGER = logging.getLogger(__name__) -def generate_data_key( +def _generate_data_key( encryption_materials, # type: EncryptionMaterials key_provider, # type: MasterKeyInfo ): @@ -80,7 +80,7 @@ def generate_data_key( @attr.s class RawAESKeyring(Keyring): - """Public class for Raw AES Keyring. + """Generate an instance for Raw AES Keyring using provided parameters :param str key_namespace: String defining the keyring. :param bytes key_name: Key ID @@ -94,6 +94,21 @@ class RawAESKeyring(Keyring): _wrapping_key = attr.ib(repr=False, validator=instance_of(six.binary_type)) _wrapping_algorithm = attr.ib(repr=False, validator=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._wrapping_key_structure = WrappingKey( + wrapping_algorithm=self._wrapping_algorithm, + wrapping_key=self._wrapping_key, + wrapping_key_type=EncryptionKeyType.SYMMETRIC, + ) + + 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 + ) + @staticmethod def _get_key_info_prefix(key_namespace, key_name, wrapping_key): # type: (str, bytes, WrappingKey) -> six.binary_type @@ -111,21 +126,6 @@ def _get_key_info_prefix(key_namespace, key_name, wrapping_key): ) return key_info_prefix - 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._wrapping_key_structure = WrappingKey( - wrapping_algorithm=self._wrapping_algorithm, - wrapping_key=self._wrapping_key, - wrapping_key_type=EncryptionKeyType.SYMMETRIC, - ) - - 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 - ) - def on_encrypt(self, encryption_materials): # type: (EncryptionMaterials) -> EncryptionMaterials """Generate a data key if not present and encrypt it using any available wrapping key @@ -136,26 +136,18 @@ def on_encrypt(self, encryption_materials): :rtype: aws_encryption_sdk.materials_managers.EncryptionMaterials """ if encryption_materials.data_encryption_key is None: - plaintext_generated = generate_data_key( + _generate_data_key( encryption_materials=encryption_materials, key_provider=self._key_provider ) - # 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=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 try: + # Encrypt data key + encrypted_wrapped_key = self._wrapping_key_structure.encrypt( + plaintext_data_key=encryption_materials.data_encryption_key.data_key, + encryption_context=encryption_materials.encryption_context, + ) + + # EncryptedData to EncryptedDataKey encrypted_data_key = serialize_wrapped_key( key_provider=self._key_provider, wrapping_algorithm=self._wrapping_algorithm, @@ -228,7 +220,7 @@ def on_decrypt(self, decryption_materials, encrypted_data_keys): # Update decryption materials data_encryption_key = RawDataKey( - key_provider=MasterKeyInfo(provider_id=self._key_provider.provider_id, key_info=self.key_name), + key_provider=self._key_provider, data_key=plaintext_data_key, ) decryption_materials.add_data_encryption_key(data_encryption_key, keyring_trace) @@ -238,18 +230,22 @@ def on_decrypt(self, decryption_materials, encrypted_data_keys): @attr.s class RawRSAKeyring(Keyring): - """Public class for Raw RSA Keyring. + """Generate an instance for Raw RSA Keyring using public and private keys which are instances of RSAPublicKey + and RSAPrivateKey :param str key_namespace: String defining the keyring ID :param bytes key_name: Key ID - :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 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 + + .. note:: + At least one of public wrapping key or private wrapping key must be provided. """ key_namespace = attr.ib(validator=instance_of(six.string_types)) @@ -258,6 +254,17 @@ class RawRSAKeyring(Keyring): _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))) + 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) + + 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 and self._public_wrapping_key is None: + self._public_wrapping_key = self._private_wrapping_key.public_key() + @classmethod def from_pem_encoding( cls, @@ -269,7 +276,7 @@ def from_pem_encoding( password=None, # type: bytes ): # type: (...) -> RawRSAKeyring - """Generate a raw RSA keyring using a key with PEM Encoding + """Generate a Raw RSA keyring using PEM Encoded public and private keys :param str key_namespace: String defining the keyring ID :param bytes key_name: Key ID @@ -308,7 +315,7 @@ def from_der_encoding( private_encoded_key=None, # type: bytes password=None, # type: bytes ): - """Generate a raw RSA keyring using a key with DER Encoding + """Generate a raw RSA keyring using DER Encoded public and private keys :param str key_namespace: String defining the keyring ID :param bytes key_name: Key ID @@ -337,17 +344,6 @@ def from_der_encoding( public_wrapping_key=loaded_public_wrapping_key, ) - 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) - - 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. @@ -358,19 +354,15 @@ def on_encrypt(self, encryption_materials): :rtype: aws_encryption_sdk.materials_managers.EncryptionMaterials """ if encryption_materials.data_encryption_key is None: - plaintext_generated = generate_data_key( + _generate_data_key( encryption_materials=encryption_materials, key_provider=self._key_provider ) - # 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: + # Encrypt data key encrypted_wrapped_key = EncryptedData( iv=None, ciphertext=self._public_wrapping_key.encrypt( @@ -379,19 +371,19 @@ def on_encrypt(self, encryption_materials): ), 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, + ) 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( - 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 keyring_trace = KeyringTrace( wrapping_key=encrypted_data_key.key_provider, flags={KeyringTraceFlag.WRAPPING_KEY_ENCRYPTED_DATA_KEY} @@ -442,7 +434,7 @@ def on_decrypt(self, decryption_materials, encrypted_data_keys): # Update decryption materials data_encryption_key = RawDataKey( - key_provider=MasterKeyInfo(provider_id=self._key_provider.provider_id, key_info=self.key_name), + key_provider=self._key_provider, data_key=plaintext_data_key, ) decryption_materials.add_data_encryption_key(data_encryption_key, keyring_trace) diff --git a/test/functional/test_f_keyring_raw_aes.py b/test/functional/test_f_keyring_raw_aes.py index cf4c11490..448741439 100644 --- a/test/functional/test_f_keyring_raw_aes.py +++ b/test/functional/test_f_keyring_raw_aes.py @@ -14,7 +14,8 @@ import pytest -from aws_encryption_sdk.identifiers import Algorithm, KeyringTraceFlag, WrappingAlgorithm +from aws_encryption_sdk.identifiers import Algorithm, KeyringTraceFlag, WrappingAlgorithm, EncryptionType +from aws_encryption_sdk.internal.defaults import ALGORITHM from aws_encryption_sdk.key_providers.raw import RawMasterKey from aws_encryption_sdk.keyring.raw_keyring import RawAESKeyring from aws_encryption_sdk.materials_managers import DecryptionMaterials, EncryptionMaterials @@ -28,11 +29,7 @@ _WRAPPING_KEY = b"12345678901234567890123456789012" _SIGNING_KEY = b"aws-crypto-public-key" -_WRAPPING_ALGORITHM = [ - WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING, - WrappingAlgorithm.AES_128_GCM_IV12_TAG16_NO_PADDING, - WrappingAlgorithm.AES_192_GCM_IV12_TAG16_NO_PADDING, -] +_WRAPPING_ALGORITHM = [alg for alg in WrappingAlgorithm if alg.encryption_type is EncryptionType.SYMMETRIC] _ENCRYPTION_MATERIALS = [ EncryptionMaterials( @@ -125,13 +122,35 @@ def test_raw_aes_encryption_decryption(encryption_materials_samples, wrapping_al # Check if the data keys match assert encryption_materials.data_encryption_key.data_key == decryption_materials.data_encryption_key.data_key + +@pytest.mark.parametrize("encryption_materials_samples", _ENCRYPTION_MATERIALS) +@pytest.mark.parametrize("wrapping_algorithm_samples", _WRAPPING_ALGORITHM) +def test_raw_master_key_decrypts_what_raw_keyring_encrypts(encryption_materials_samples, wrapping_algorithm_samples): + + # Initializing attributes + key_namespace = _PROVIDER_ID + key_name = _KEY_ID + _wrapping_algorithm = wrapping_algorithm_samples + + # Creating an instance of a raw AES keyring + test_raw_aes_keyring = RawAESKeyring( + key_namespace=key_namespace, + key_name=key_name, + wrapping_key=_WRAPPING_KEY, + wrapping_algorithm=_wrapping_algorithm, + ) + + # Creating an instance of a raw master key test_raw_master_key = RawMasterKey( key_id=test_raw_aes_keyring.key_name, provider_id=test_raw_aes_keyring.key_namespace, wrapping_key=test_raw_aes_keyring._wrapping_key_structure, ) + + # Encrypt using raw AES keyring encryption_materials = test_raw_aes_keyring.on_encrypt(encryption_materials=encryption_materials_samples) + # Check if plaintext data key encrypted by raw keyring is decrypted by raw master key assert ( encryption_materials.data_encryption_key.data_key == test_raw_master_key.decrypt_data_key_from_list( @@ -141,20 +160,50 @@ def test_raw_aes_encryption_decryption(encryption_materials_samples, wrapping_al ).data_key ) - if encryption_materials_samples.data_encryption_key is not None: - raw_master_key_encrypted_data_key = test_raw_master_key.encrypt_data_key( - data_key=encryption_materials_samples.data_encryption_key, - algorithm=encryption_materials_samples.algorithm, - encryption_context=encryption_materials_samples.encryption_context, - ) - assert ( - encryption_materials_samples.data_encryption_key.data_key - == test_raw_aes_keyring.on_decrypt( - decryption_materials=DecryptionMaterials( - algorithm=encryption_materials_samples.algorithm, - encryption_context=encryption_materials_samples.encryption_context, - verification_key=b"ex_verification_key", - ), - encrypted_data_keys=[raw_master_key_encrypted_data_key], - ).data_encryption_key.data_key + +@pytest.mark.parametrize("encryption_materials_samples", _ENCRYPTION_MATERIALS) +@pytest.mark.parametrize("wrapping_algorithm_samples", _WRAPPING_ALGORITHM) +def test_raw_keyring_decrypts_what_raw_master_key_encrypts(encryption_materials_samples, wrapping_algorithm_samples): + + # Initializing attributes + key_namespace = _PROVIDER_ID + key_name = _KEY_ID + _wrapping_algorithm = wrapping_algorithm_samples + + # Creating an instance of a raw AES keyring + test_raw_aes_keyring = RawAESKeyring( + key_namespace=key_namespace, + key_name=key_name, + wrapping_key=_WRAPPING_KEY, + wrapping_algorithm=_wrapping_algorithm, + ) + + # Creating an instance of a raw master key + test_raw_master_key = RawMasterKey( + key_id=test_raw_aes_keyring.key_name, + provider_id=test_raw_aes_keyring.key_namespace, + wrapping_key=test_raw_aes_keyring._wrapping_key_structure, + ) + + if encryption_materials_samples.data_encryption_key is None: + encryption_materials_samples.data_encryption_key = test_raw_master_key.generate_data_key( + algorithm=ALGORITHM, + encryption_context=_ENCRYPTION_CONTEXT ) + + raw_master_key_encrypted_data_key = test_raw_master_key.encrypt_data_key( + data_key=encryption_materials_samples.data_encryption_key, + algorithm=encryption_materials_samples.algorithm, + encryption_context=encryption_materials_samples.encryption_context, + ) + assert ( + encryption_materials_samples.data_encryption_key.data_key + == test_raw_aes_keyring.on_decrypt( + decryption_materials=DecryptionMaterials( + algorithm=encryption_materials_samples.algorithm, + encryption_context=encryption_materials_samples.encryption_context, + verification_key=b"ex_verification_key", + ), + encrypted_data_keys=[raw_master_key_encrypted_data_key], + ).data_encryption_key.data_key + ) diff --git a/test/unit/test_keyring_raw_aes.py b/test/unit/test_keyring_raw_aes.py index 914e2f259..3addf5381 100644 --- a/test/unit/test_keyring_raw_aes.py +++ b/test/unit/test_keyring_raw_aes.py @@ -22,13 +22,14 @@ from aws_encryption_sdk.identifiers import Algorithm, KeyringTraceFlag, WrappingAlgorithm from aws_encryption_sdk.internal.crypto.wrapping_keys import WrappingKey from aws_encryption_sdk.keyring.base import EncryptedDataKey, Keyring -from aws_encryption_sdk.keyring.raw_keyring import GenerateKeyError, RawAESKeyring, generate_data_key +from aws_encryption_sdk.keyring.raw_keyring import GenerateKeyError, RawAESKeyring, _generate_data_key from aws_encryption_sdk.materials_managers import EncryptionMaterials from aws_encryption_sdk.structures import MasterKeyInfo from .unit_test_utils import ( _DATA_KEY, _ENCRYPTED_DATA_KEY_AES, + _ENCRYPTED_DATA_KEY_NOT_IN_KEYRING, _ENCRYPTION_CONTEXT, _KEY_ID, _PROVIDER_ID, @@ -46,12 +47,12 @@ @pytest.fixture def patch_generate_data_key(mocker): - mocker.patch.object(aws_encryption_sdk.keyring.raw_keyring, "generate_data_key") - return aws_encryption_sdk.keyring.raw_keyring.generate_data_key + mocker.patch.object(aws_encryption_sdk.keyring.raw_keyring, "_generate_data_key") + return aws_encryption_sdk.keyring.raw_keyring._generate_data_key @pytest.fixture -def patch_decrypt_data_key(mocker): +def patch_decrypt_on_wrapping_key(mocker): mocker.patch.object(WrappingKey, "decrypt") return WrappingKey.decrypt @@ -84,7 +85,7 @@ def test_missing_required_parameters(): RawAESKeyring( key_namespace=_PROVIDER_ID, wrapping_algorithm=WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING ) - assert exc_info.match("__init__() missing.*") + assert exc_info.errisinstance(TypeError) def test_invalid_values_as_parameter(): @@ -143,7 +144,7 @@ def test_on_encrypt_when_data_encryption_key_not_given(): test = test_raw_aes_keyring.on_encrypt(encryption_materials=get_encryption_materials_without_data_encryption_key()) # Check if data key is generated - assert test.data_encryption_key and test.data_encryption_key is not None + assert test.data_encryption_key is not None generated_flag_count = 0 encrypted_flag_count = 0 @@ -165,7 +166,13 @@ def test_on_encrypt_when_data_encryption_key_not_given(): assert encrypted_flag_count == 1 -def test_on_decrypt_when_data_key_given(patch_decrypt_data_key): +@pytest.mark.parametrize("decryption_materials, edk", + ( + (get_decryption_materials_with_data_encryption_key(), [_ENCRYPTED_DATA_KEY_AES]), + (get_decryption_materials_with_data_encryption_key(), []) + ) + ) +def test_on_decrypt_when_data_key_given(decryption_materials, edk, patch_decrypt_on_wrapping_key): test_raw_aes_keyring = RawAESKeyring( key_namespace=_PROVIDER_ID, key_name=_KEY_ID, @@ -173,18 +180,10 @@ def test_on_decrypt_when_data_key_given(patch_decrypt_data_key): wrapping_key=_WRAPPING_KEY, ) test_raw_aes_keyring.on_decrypt( - decryption_materials=get_decryption_materials_with_data_encryption_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\x7f.}\x87\x16,\x11n#\xc8p" - b"\xdb\xbf\x94\x86*Q\x06\xd2\xf5\xdah\x08\xa4p\x81\xf7\xf4G\ - x07FzE\xde", - ) - ], + decryption_materials=decryption_materials, + encrypted_data_keys=edk, ) - assert not patch_decrypt_data_key.called + assert not patch_decrypt_on_wrapping_key.called def test_keyring_trace_on_decrypt_when_data_key_given(): @@ -196,15 +195,7 @@ def test_keyring_trace_on_decrypt_when_data_key_given(): ) test = test_raw_aes_keyring.on_decrypt( decryption_materials=get_decryption_materials_with_data_encryption_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\x7f.}\x87\x16,\x11n#\xc8p" - b"\xdb\xbf\x94\x86*Q\x06\xd2\xf5\xdah\x08\xa4p\x81\xf7\xf4G\ - x07FzE\xde", - ) - ], + encrypted_data_keys=[_ENCRYPTED_DATA_KEY_AES], ) for keyring_trace in test.keyring_trace: if keyring_trace.wrapping_key.key_info == _KEY_ID: @@ -212,27 +203,15 @@ def test_keyring_trace_on_decrypt_when_data_key_given(): assert KeyringTraceFlag.WRAPPING_KEY_DECRYPTED_DATA_KEY not in keyring_trace.flags -def test_on_decrypt_when_data_key_and_edk_not_provided(patch_decrypt_data_key): - test_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, - ) - - test = test_raw_aes_keyring.on_decrypt( - decryption_materials=get_decryption_materials_without_data_encryption_key(), encrypted_data_keys=[] - ) - assert not patch_decrypt_data_key.called - - for keyring_trace in test.keyring_trace: - if keyring_trace.wrapping_key.key_info == _KEY_ID: - assert KeyringTraceFlag.WRAPPING_KEY_DECRYPTED_DATA_KEY not in keyring_trace.flags - - assert test.data_encryption_key is None - - -def test_on_decrypt_when_data_key_not_provided_and_edk_not_in_keyring(patch_decrypt_data_key): +@pytest.mark.parametrize("decryption_materials, edk", + ( + (get_decryption_materials_without_data_encryption_key(), []), + (get_encryption_materials_without_data_encryption_key(), + [_ENCRYPTED_DATA_KEY_NOT_IN_KEYRING]) + ) + ) +def test_on_decrypt_when_data_key_and_edk_not_provided(decryption_materials, edk, + patch_decrypt_on_wrapping_key): test_raw_aes_keyring = RawAESKeyring( key_namespace=_PROVIDER_ID, key_name=_KEY_ID, @@ -241,19 +220,9 @@ def test_on_decrypt_when_data_key_not_provided_and_edk_not_in_keyring(patch_decr ) test = test_raw_aes_keyring.on_decrypt( - decryption_materials=get_decryption_materials_without_data_encryption_key(), - encrypted_data_keys=[ - EncryptedDataKey( - key_provider=MasterKeyInfo(provider_id=_PROVIDER_ID, key_info=b"5430b043-5843-4629-869c-64794af77ada"), - 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", - ) - ], + decryption_materials=decryption_materials, encrypted_data_keys=edk ) - assert not patch_decrypt_data_key.called + assert not patch_decrypt_on_wrapping_key.called for keyring_trace in test.keyring_trace: if keyring_trace.wrapping_key.key_info == _KEY_ID: @@ -262,22 +231,19 @@ def test_on_decrypt_when_data_key_not_provided_and_edk_not_in_keyring(patch_decr assert test.data_encryption_key is None -def test_on_decrypt_when_data_key_not_provided_and_edk_provided(patch_decrypt_data_key): - patch_decrypt_data_key.return_value = _DATA_KEY +def test_on_decrypt_when_data_key_not_provided_and_edk_provided(patch_decrypt_on_wrapping_key): + patch_decrypt_on_wrapping_key.return_value = _DATA_KEY test_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, ) - test_raw_aes_keyring.on_decrypt( decryption_materials=get_decryption_materials_without_data_encryption_key(), encrypted_data_keys=[_ENCRYPTED_DATA_KEY_AES], ) - assert patch_decrypt_data_key.called_once_with( - encrypted_wrapped_data_key=_ENCRYPTED_DATA_KEY_AES, encryption_context=_ENCRYPTION_CONTEXT - ) + patch_decrypt_on_wrapping_key.assert_called_once() def test_keyring_trace_when_data_key_not_provided_and_edk_provided(): @@ -304,7 +270,7 @@ def test_keyring_trace_when_data_key_not_provided_and_edk_provided(): def test_error_when_data_key_not_generated(patch_os_urandom): patch_os_urandom.side_effect = NotImplementedError with pytest.raises(GenerateKeyError) as exc_info: - generate_data_key( + _generate_data_key( encryption_materials=get_encryption_materials_without_data_encryption_key(), key_provider=MasterKeyInfo(provider_id=_PROVIDER_ID, key_info=_KEY_ID), ) @@ -313,7 +279,7 @@ def test_error_when_data_key_not_generated(patch_os_urandom): def test_generate_data_key_error_when_data_key_exists(): with pytest.raises(TypeError) as exc_info: - generate_data_key( + _generate_data_key( encryption_materials=get_encryption_materials_with_data_encryption_key(), key_provider=MasterKeyInfo(provider_id=_PROVIDER_ID, key_info=_KEY_ID), ) @@ -326,12 +292,16 @@ def test_generate_data_key_keyring_trace(): encryption_context=_ENCRYPTION_CONTEXT, signing_key=_SIGNING_KEY, ) - generate_data_key( + _generate_data_key( encryption_materials=encryption_materials_without_data_key, key_provider=MasterKeyInfo(provider_id=_PROVIDER_ID, key_info=_KEY_ID), ) + assert encryption_materials_without_data_key.data_encryption_key.key_provider.provider_id == _PROVIDER_ID + assert encryption_materials_without_data_key.data_encryption_key.key_provider.key_info == _KEY_ID + generate_flag_count = 0 + for keyring_trace in encryption_materials_without_data_key.keyring_trace: if KeyringTraceFlag.WRAPPING_KEY_GENERATED_DATA_KEY in keyring_trace.flags: generate_flag_count += 1 diff --git a/test/unit/test_keyring_raw_rsa.py b/test/unit/test_keyring_raw_rsa.py index b3ae521bd..9032f7175 100644 --- a/test/unit/test_keyring_raw_rsa.py +++ b/test/unit/test_keyring_raw_rsa.py @@ -44,12 +44,12 @@ @pytest.fixture def patch_generate_data_key(mocker): - mocker.patch.object(aws_encryption_sdk.keyring.raw_keyring, "generate_data_key") - return aws_encryption_sdk.keyring.raw_keyring.generate_data_key + mocker.patch.object(aws_encryption_sdk.keyring.raw_keyring, "_generate_data_key") + return aws_encryption_sdk.keyring.raw_keyring._generate_data_key @pytest.fixture -def patch_decrypt_data_key(mocker): +def patch_decrypt_on_wrapping_key(mocker): mocker.patch.object(WrappingKey, "decrypt") return WrappingKey.decrypt @@ -160,7 +160,7 @@ def test_on_encrypt_when_data_encryption_key_not_given(): test = test_raw_rsa_keyring.on_encrypt(encryption_materials=get_encryption_materials_without_data_encryption_key()) # Check if data key is generated - assert test.data_encryption_key and test.data_encryption_key is not None + assert test.data_encryption_key is not None generated_flag_count = 0 encrypted_flag_count = 0 @@ -182,7 +182,7 @@ def test_on_encrypt_when_data_encryption_key_not_given(): assert encrypted_flag_count == 1 -def test_on_decrypt_when_data_key_given(patch_decrypt_data_key): +def test_on_decrypt_when_data_key_given(patch_decrypt_on_wrapping_key): test_raw_rsa_keyring = RawRSAKeyring( key_namespace=_PROVIDER_ID, key_name=_KEY_ID, @@ -195,7 +195,7 @@ def test_on_decrypt_when_data_key_given(patch_decrypt_data_key): decryption_materials=get_decryption_materials_with_data_encryption_key(), encrypted_data_keys=[_ENCRYPTED_DATA_KEY_RSA], ) - assert not patch_decrypt_data_key.called + assert not patch_decrypt_on_wrapping_key.called def test_keyring_trace_on_decrypt_when_data_key_given(): @@ -217,7 +217,7 @@ def test_keyring_trace_on_decrypt_when_data_key_given(): assert KeyringTraceFlag.WRAPPING_KEY_DECRYPTED_DATA_KEY not in keyring_trace.flags -def test_on_decrypt_when_data_key_and_edk_not_provided(patch_decrypt_data_key): +def test_on_decrypt_when_data_key_and_edk_not_provided(patch_decrypt_on_wrapping_key): test_raw_rsa_keyring = RawRSAKeyring( key_namespace=_PROVIDER_ID, key_name=_KEY_ID, @@ -230,7 +230,7 @@ def test_on_decrypt_when_data_key_and_edk_not_provided(patch_decrypt_data_key): test = test_raw_rsa_keyring.on_decrypt( decryption_materials=get_decryption_materials_without_data_encryption_key(), encrypted_data_keys=[] ) - assert not patch_decrypt_data_key.called + assert not patch_decrypt_on_wrapping_key.called for keyring_trace in test.keyring_trace: assert KeyringTraceFlag.WRAPPING_KEY_DECRYPTED_DATA_KEY not in keyring_trace.flags @@ -238,7 +238,7 @@ def test_on_decrypt_when_data_key_and_edk_not_provided(patch_decrypt_data_key): assert test.data_encryption_key is None -def test_on_decrypt_when_data_key_not_provided_and_edk_not_in_keyring(patch_decrypt_data_key): +def test_on_decrypt_when_data_key_not_provided_and_edk_not_in_keyring(patch_decrypt_on_wrapping_key): test_raw_rsa_keyring = RawRSAKeyring( key_namespace=_PROVIDER_ID, key_name=_KEY_ID, @@ -252,7 +252,7 @@ def test_on_decrypt_when_data_key_not_provided_and_edk_not_in_keyring(patch_decr decryption_materials=get_decryption_materials_without_data_encryption_key(), encrypted_data_keys=[_ENCRYPTED_DATA_KEY_RSA], ) - assert not patch_decrypt_data_key.called + assert not patch_decrypt_on_wrapping_key.called for keyring_trace in test.keyring_trace: if keyring_trace.wrapping_key.key_info == _KEY_ID: @@ -261,8 +261,8 @@ def test_on_decrypt_when_data_key_not_provided_and_edk_not_in_keyring(patch_decr assert test.data_encryption_key is None -def test_on_decrypt_when_data_key_not_provided_and_edk_provided(patch_decrypt_data_key): - patch_decrypt_data_key.return_value = _DATA_KEY +def test_on_decrypt_when_data_key_not_provided_and_edk_provided(patch_decrypt_on_wrapping_key): + patch_decrypt_on_wrapping_key.return_value = _DATA_KEY test_raw_rsa_keyring = RawRSAKeyring( key_namespace=_PROVIDER_ID, key_name=_KEY_ID, @@ -276,7 +276,7 @@ def test_on_decrypt_when_data_key_not_provided_and_edk_provided(patch_decrypt_da decryption_materials=get_decryption_materials_without_data_encryption_key(), encrypted_data_keys=[_ENCRYPTED_DATA_KEY_RSA], ) - assert patch_decrypt_data_key.called_once_with( + assert patch_decrypt_on_wrapping_key.called_once_with( encrypted_wrapped_data_key=_ENCRYPTED_DATA_KEY_RSA, encryption_context=_ENCRYPTION_CONTEXT ) @@ -304,3 +304,4 @@ def test_keyring_trace_when_data_key_not_provided_and_edk_provided(): decrypted_flag_count += 1 assert decrypted_flag_count == 1 + assert test.data_encryption_key is not None diff --git a/test/unit/unit_test_utils.py b/test/unit/unit_test_utils.py index fa53dbba9..6cd33a581 100644 --- a/test/unit/unit_test_utils.py +++ b/test/unit/unit_test_utils.py @@ -48,6 +48,19 @@ b"\xfd;\x94lTu/6\xfe", ) +_ENCRYPTED_DATA_KEY_NOT_IN_KEYRING = EncryptedDataKey( + key_provider=MasterKeyInfo( + provider_id="Random Raw Keys", + key_info=b"5430b043-5843-4629-869c-64794af77ada\x00\x00\x00\x80" + b"\x00\x00\x00\x0c\xc7\xd5d\xc9\xc5\xf21\x8d\x8b\xf9H" + b"\xbb", + ), + encrypted_data_key=b"\xf3+\x15n\xe6`\xbe\xfe\xf0\x9e1\xe5\x9b" + b"\xaf\xfe\xdaT\xbb\x17\x14\xfd} o\xdd\xf1" + b"\xbc\xe1C\xa5J\xd8\xc7\x15\xc2\x90t=\xb9" + b"\xfd;\x94lTu/6\xfe", +) + _ENCRYPTED_DATA_KEY_RSA = EncryptedDataKey( key_provider=MasterKeyInfo(provider_id="Random Raw Keys", key_info=_KEY_ID), encrypted_data_key=b"\xf3+\x15n\xe6`\xbe\xfe\xf0\x9e1\xe5\x9b" From d5d186e3ac612877157f9f180994fe3dc6badfeb Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Thu, 1 Aug 2019 18:37:16 -0700 Subject: [PATCH 111/119] All tests except compatibility of raw rsa with mkp and key info prefix in raw aes --- src/aws_encryption_sdk/keyring/raw_keyring.py | 18 +- test/functional/test_f_keyring_raw_aes.py | 138 +++++++-------- test/functional/test_f_keyring_raw_rsa.py | 131 ++++++-------- test/unit/test_keyring_raw_aes.py | 167 +++++++----------- test/unit/test_keyring_raw_rsa.py | 156 +++++----------- test/unit/unit_test_utils.py | 5 +- 6 files changed, 240 insertions(+), 375 deletions(-) diff --git a/src/aws_encryption_sdk/keyring/raw_keyring.py b/src/aws_encryption_sdk/keyring/raw_keyring.py index 064838fd2..71c798374 100644 --- a/src/aws_encryption_sdk/keyring/raw_keyring.py +++ b/src/aws_encryption_sdk/keyring/raw_keyring.py @@ -136,9 +136,7 @@ def on_encrypt(self, encryption_materials): :rtype: aws_encryption_sdk.materials_managers.EncryptionMaterials """ if encryption_materials.data_encryption_key is None: - _generate_data_key( - encryption_materials=encryption_materials, key_provider=self._key_provider - ) + _generate_data_key(encryption_materials=encryption_materials, key_provider=self._key_provider) try: # Encrypt data key @@ -219,10 +217,7 @@ def on_decrypt(self, decryption_materials, encrypted_data_keys): ) # Update decryption materials - data_encryption_key = RawDataKey( - key_provider=self._key_provider, - data_key=plaintext_data_key, - ) + data_encryption_key = RawDataKey(key_provider=self._key_provider, data_key=plaintext_data_key) decryption_materials.add_data_encryption_key(data_encryption_key, keyring_trace) return decryption_materials @@ -354,9 +349,7 @@ def on_encrypt(self, encryption_materials): :rtype: aws_encryption_sdk.materials_managers.EncryptionMaterials """ if encryption_materials.data_encryption_key is None: - _generate_data_key( - encryption_materials=encryption_materials, key_provider=self._key_provider - ) + _generate_data_key(encryption_materials=encryption_materials, key_provider=self._key_provider) if self._public_wrapping_key is None: return encryption_materials @@ -433,10 +426,7 @@ def on_decrypt(self, decryption_materials, encrypted_data_keys): ) # Update decryption materials - data_encryption_key = RawDataKey( - key_provider=self._key_provider, - data_key=plaintext_data_key, - ) + data_encryption_key = RawDataKey(key_provider=self._key_provider, 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_keyring_raw_aes.py b/test/functional/test_f_keyring_raw_aes.py index 448741439..372d3be41 100644 --- a/test/functional/test_f_keyring_raw_aes.py +++ b/test/functional/test_f_keyring_raw_aes.py @@ -14,8 +14,7 @@ import pytest -from aws_encryption_sdk.identifiers import Algorithm, KeyringTraceFlag, WrappingAlgorithm, EncryptionType -from aws_encryption_sdk.internal.defaults import ALGORITHM +from aws_encryption_sdk.identifiers import Algorithm, EncryptionType, KeyringTraceFlag, WrappingAlgorithm from aws_encryption_sdk.key_providers.raw import RawMasterKey from aws_encryption_sdk.keyring.raw_keyring import RawAESKeyring from aws_encryption_sdk.materials_managers import DecryptionMaterials, EncryptionMaterials @@ -31,53 +30,57 @@ _WRAPPING_ALGORITHM = [alg for alg in WrappingAlgorithm if alg.encryption_type is EncryptionType.SYMMETRIC] -_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(', + +def sample_encryption_materials(): + return [ + EncryptionMaterials( + algorithm=Algorithm.AES_256_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384, + encryption_context=_ENCRYPTION_CONTEXT, + signing_key=_SIGNING_KEY, ), - 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(', + 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}, + ) + ], ), - encrypted_data_keys=[ - EncryptedDataKey( + 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), - 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, - }, - ) - ], - ), -] + 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, + }, + ) + ], + ), + ] + + # # _KEY_INFO_VECTORS = [ # (b"5325b043-5843-4629-869c-64794af77ada", b"5325b043-5843-4629-869c-64794af77ada\x00\x00\x00\x80\x00\x00\x00\x0c", @@ -87,7 +90,7 @@ # ] -@pytest.mark.parametrize("encryption_materials_samples", _ENCRYPTION_MATERIALS) +@pytest.mark.parametrize("encryption_materials_samples", sample_encryption_materials()) @pytest.mark.parametrize("wrapping_algorithm_samples", _WRAPPING_ALGORITHM) def test_raw_aes_encryption_decryption(encryption_materials_samples, wrapping_algorithm_samples): @@ -123,7 +126,7 @@ def test_raw_aes_encryption_decryption(encryption_materials_samples, wrapping_al assert encryption_materials.data_encryption_key.data_key == decryption_materials.data_encryption_key.data_key -@pytest.mark.parametrize("encryption_materials_samples", _ENCRYPTION_MATERIALS) +@pytest.mark.parametrize("encryption_materials_samples", sample_encryption_materials()) @pytest.mark.parametrize("wrapping_algorithm_samples", _WRAPPING_ALGORITHM) def test_raw_master_key_decrypts_what_raw_keyring_encrypts(encryption_materials_samples, wrapping_algorithm_samples): @@ -161,7 +164,7 @@ def test_raw_master_key_decrypts_what_raw_keyring_encrypts(encryption_materials_ ) -@pytest.mark.parametrize("encryption_materials_samples", _ENCRYPTION_MATERIALS) +@pytest.mark.parametrize("encryption_materials_samples", sample_encryption_materials()) @pytest.mark.parametrize("wrapping_algorithm_samples", _WRAPPING_ALGORITHM) def test_raw_keyring_decrypts_what_raw_master_key_encrypts(encryption_materials_samples, wrapping_algorithm_samples): @@ -185,25 +188,20 @@ def test_raw_keyring_decrypts_what_raw_master_key_encrypts(encryption_materials_ wrapping_key=test_raw_aes_keyring._wrapping_key_structure, ) - if encryption_materials_samples.data_encryption_key is None: - encryption_materials_samples.data_encryption_key = test_raw_master_key.generate_data_key( - algorithm=ALGORITHM, - encryption_context=_ENCRYPTION_CONTEXT + if encryption_materials_samples.data_encryption_key is not None: + raw_master_key_encrypted_data_key = test_raw_master_key.encrypt_data_key( + data_key=encryption_materials_samples.data_encryption_key, + algorithm=encryption_materials_samples.algorithm, + encryption_context=encryption_materials_samples.encryption_context, + ) + assert ( + encryption_materials_samples.data_encryption_key.data_key + == test_raw_aes_keyring.on_decrypt( + decryption_materials=DecryptionMaterials( + algorithm=encryption_materials_samples.algorithm, + encryption_context=encryption_materials_samples.encryption_context, + verification_key=b"ex_verification_key", + ), + encrypted_data_keys=[raw_master_key_encrypted_data_key], + ).data_encryption_key.data_key ) - - raw_master_key_encrypted_data_key = test_raw_master_key.encrypt_data_key( - data_key=encryption_materials_samples.data_encryption_key, - algorithm=encryption_materials_samples.algorithm, - encryption_context=encryption_materials_samples.encryption_context, - ) - assert ( - encryption_materials_samples.data_encryption_key.data_key - == test_raw_aes_keyring.on_decrypt( - decryption_materials=DecryptionMaterials( - algorithm=encryption_materials_samples.algorithm, - encryption_context=encryption_materials_samples.encryption_context, - verification_key=b"ex_verification_key", - ), - encrypted_data_keys=[raw_master_key_encrypted_data_key], - ).data_encryption_key.data_key - ) diff --git a/test/functional/test_f_keyring_raw_rsa.py b/test/functional/test_f_keyring_raw_rsa.py index bd0c1573d..3a7700983 100644 --- a/test/functional/test_f_keyring_raw_rsa.py +++ b/test/functional/test_f_keyring_raw_rsa.py @@ -17,7 +17,7 @@ from cryptography.hazmat.primitives import serialization from cryptography.hazmat.primitives.asymmetric import rsa -from aws_encryption_sdk.identifiers import Algorithm, KeyringTraceFlag, WrappingAlgorithm +from aws_encryption_sdk.identifiers import Algorithm, EncryptionType, KeyringTraceFlag, WrappingAlgorithm from aws_encryption_sdk.keyring.raw_keyring import RawRSAKeyring from aws_encryption_sdk.materials_managers import DecryptionMaterials, EncryptionMaterials from aws_encryption_sdk.structures import EncryptedDataKey, KeyringTrace, MasterKeyInfo, RawDataKey @@ -34,6 +34,9 @@ _KEY_SIZE = 2048 _BACKEND = default_backend() +_PRIVATE_WRAPPING_KEY = rsa.generate_private_key(public_exponent=_PUBLIC_EXPONENT, key_size=_KEY_SIZE, backend=_BACKEND) + + _RAW_RSA_PRIVATE_KEY_PEM_ENCODED_WITHOUT_PASSWORD = rsa.generate_private_key( public_exponent=_PUBLIC_EXPONENT, key_size=_KEY_SIZE, backend=_BACKEND ).private_bytes( @@ -126,91 +129,63 @@ ), ] -_RAW_RSA_KEYRINGS = [ - RawRSAKeyring( - key_namespace=_PROVIDER_ID, - key_name=_KEY_ID, - wrapping_algorithm=_WRAPPING_ALGORITHM, - private_wrapping_key=rsa.generate_private_key( - public_exponent=_PUBLIC_EXPONENT, key_size=_KEY_SIZE, backend=_BACKEND + +def sample_raw_rsa_keyring_using_different_wrapping_algorithm(): + for alg in WrappingAlgorithm: + if alg.encryption_type is EncryptionType.ASYMMETRIC: + yield RawRSAKeyring( + key_namespace=_PROVIDER_ID, + key_name=_KEY_ID, + wrapping_algorithm=alg, + private_wrapping_key=_PRIVATE_WRAPPING_KEY, + ) + pem_and_der_encoded_raw_rsa_keyring = [ + RawRSAKeyring.from_pem_encoding( + key_namespace=_PROVIDER_ID, + key_name=_KEY_ID, + private_encoded_key=_RAW_RSA_PRIVATE_KEY_PEM_ENCODED_WITHOUT_PASSWORD, + wrapping_algorithm=_WRAPPING_ALGORITHM, ), - ), - RawRSAKeyring( - key_namespace=_PROVIDER_ID, - key_name=_KEY_ID, - wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA1_MGF1, - private_wrapping_key=rsa.generate_private_key( - public_exponent=_PUBLIC_EXPONENT, key_size=_KEY_SIZE, backend=_BACKEND + RawRSAKeyring.from_pem_encoding( + key_namespace=_PROVIDER_ID, + key_name=_KEY_ID, + private_encoded_key=_RAW_RSA_PRIVATE_KEY_PEM_ENCODED_WITH_PASSWORD, + password=b"mypassword", + wrapping_algorithm=_WRAPPING_ALGORITHM, ), - ), - RawRSAKeyring( - key_namespace=_PROVIDER_ID, - key_name=_KEY_ID, - wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA384_MGF1, - private_wrapping_key=rsa.generate_private_key( - public_exponent=_PUBLIC_EXPONENT, key_size=_KEY_SIZE, backend=_BACKEND + RawRSAKeyring.from_pem_encoding( + key_namespace=_PROVIDER_ID, + key_name=_KEY_ID, + public_encoded_key=_RAW_RSA_PUBLIC_KEY_PEM_ENCODED, + wrapping_algorithm=_WRAPPING_ALGORITHM, ), - ), - RawRSAKeyring( - key_namespace=_PROVIDER_ID, - key_name=_KEY_ID, - wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA512_MGF1, - private_wrapping_key=rsa.generate_private_key( - public_exponent=_PUBLIC_EXPONENT, key_size=_KEY_SIZE, backend=_BACKEND + RawRSAKeyring.from_der_encoding( + key_namespace=_PROVIDER_ID, + key_name=_KEY_ID, + private_encoded_key=_RAW_RSA_PRIVATE_KEY_DER_ENCODED_WITHOUT_PASSWORD, + wrapping_algorithm=_WRAPPING_ALGORITHM, ), - ), - RawRSAKeyring( - key_namespace=_PROVIDER_ID, - key_name=_KEY_ID, - wrapping_algorithm=WrappingAlgorithm.RSA_PKCS1, - private_wrapping_key=rsa.generate_private_key( - public_exponent=_PUBLIC_EXPONENT, key_size=_KEY_SIZE, backend=_BACKEND + RawRSAKeyring.from_der_encoding( + key_namespace=_PROVIDER_ID, + key_name=_KEY_ID, + private_encoded_key=_RAW_RSA_PRIVATE_KEY_DER_ENCODED_WITH_PASSWORD, + password=b"mypassword", + wrapping_algorithm=_WRAPPING_ALGORITHM, ), - ), - RawRSAKeyring.from_pem_encoding( - key_namespace=_PROVIDER_ID, - key_name=_KEY_ID, - private_encoded_key=_RAW_RSA_PRIVATE_KEY_PEM_ENCODED_WITHOUT_PASSWORD, - wrapping_algorithm=_WRAPPING_ALGORITHM, - ), - RawRSAKeyring.from_pem_encoding( - key_namespace=_PROVIDER_ID, - key_name=_KEY_ID, - private_encoded_key=_RAW_RSA_PRIVATE_KEY_PEM_ENCODED_WITH_PASSWORD, - password=b"mypassword", - wrapping_algorithm=_WRAPPING_ALGORITHM, - ), - RawRSAKeyring.from_pem_encoding( - key_namespace=_PROVIDER_ID, - key_name=_KEY_ID, - public_encoded_key=_RAW_RSA_PUBLIC_KEY_PEM_ENCODED, - wrapping_algorithm=_WRAPPING_ALGORITHM, - ), - RawRSAKeyring.from_der_encoding( - key_namespace=_PROVIDER_ID, - key_name=_KEY_ID, - private_encoded_key=_RAW_RSA_PRIVATE_KEY_DER_ENCODED_WITHOUT_PASSWORD, - wrapping_algorithm=_WRAPPING_ALGORITHM, - ), - RawRSAKeyring.from_der_encoding( - key_namespace=_PROVIDER_ID, - key_name=_KEY_ID, - private_encoded_key=_RAW_RSA_PRIVATE_KEY_DER_ENCODED_WITH_PASSWORD, - password=b"mypassword", - wrapping_algorithm=_WRAPPING_ALGORITHM, - ), - RawRSAKeyring.from_der_encoding( - key_namespace=_PROVIDER_ID, - key_name=_KEY_ID, - public_encoded_key=_RAW_RSA_PUBLIC_KEY_DER_ENCODED, - password=b"mypassword", - wrapping_algorithm=_WRAPPING_ALGORITHM, - ), -] + RawRSAKeyring.from_der_encoding( + key_namespace=_PROVIDER_ID, + key_name=_KEY_ID, + public_encoded_key=_RAW_RSA_PUBLIC_KEY_DER_ENCODED, + password=b"mypassword", + wrapping_algorithm=_WRAPPING_ALGORITHM, + ), + ] + for keyring in pem_and_der_encoded_raw_rsa_keyring: + yield keyring @pytest.mark.parametrize("encryption_materials_samples", _ENCRYPTION_MATERIALS) -@pytest.mark.parametrize("test_raw_rsa_keyring", _RAW_RSA_KEYRINGS) +@pytest.mark.parametrize("test_raw_rsa_keyring", sample_raw_rsa_keyring_using_different_wrapping_algorithm()) def test_raw_rsa_encryption_decryption(encryption_materials_samples, test_raw_rsa_keyring): # Call on_encrypt function for the keyring diff --git a/test/unit/test_keyring_raw_aes.py b/test/unit/test_keyring_raw_aes.py index 3addf5381..3181c95cf 100644 --- a/test/unit/test_keyring_raw_aes.py +++ b/test/unit/test_keyring_raw_aes.py @@ -21,7 +21,7 @@ import aws_encryption_sdk.keyring.raw_keyring from aws_encryption_sdk.identifiers import Algorithm, KeyringTraceFlag, WrappingAlgorithm from aws_encryption_sdk.internal.crypto.wrapping_keys import WrappingKey -from aws_encryption_sdk.keyring.base import EncryptedDataKey, Keyring +from aws_encryption_sdk.keyring.base import Keyring from aws_encryption_sdk.keyring.raw_keyring import GenerateKeyError, RawAESKeyring, _generate_data_key from aws_encryption_sdk.materials_managers import EncryptionMaterials from aws_encryption_sdk.structures import MasterKeyInfo @@ -41,10 +41,19 @@ get_encryption_materials_without_data_encryption_key, ) - pytestmark = [pytest.mark.unit, pytest.mark.local] +@pytest.fixture +def raw_aes_keyring(): + return RawAESKeyring( + key_namespace=_PROVIDER_ID, + key_name=_KEY_ID, + wrapping_algorithm=WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING, + wrapping_key=_WRAPPING_KEY, + ) + + @pytest.fixture def patch_generate_data_key(mocker): mocker.patch.object(aws_encryption_sdk.keyring.raw_keyring, "_generate_data_key") @@ -67,58 +76,47 @@ def test_parent(): assert issubclass(RawAESKeyring, Keyring) -def test_valid_parameters(): - test = RawAESKeyring( - key_namespace=_PROVIDER_ID, - key_name=_KEY_ID, - wrapping_algorithm=WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING, - wrapping_key=_WRAPPING_KEY, - ) +def test_valid_parameters(raw_aes_keyring): + test = raw_aes_keyring assert test.key_name == _KEY_ID assert test.key_namespace == _PROVIDER_ID assert test._wrapping_algorithm == WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING assert test._wrapping_key == _WRAPPING_KEY -def test_missing_required_parameters(): - with pytest.raises(TypeError) as exc_info: - RawAESKeyring( - key_namespace=_PROVIDER_ID, wrapping_algorithm=WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING - ) - assert exc_info.errisinstance(TypeError) - - -def test_invalid_values_as_parameter(): - with pytest.raises(TypeError) as exc_info: +@pytest.mark.parametrize( + "key_namespace, key_name, wrapping_algorithm, wrapping_key", + ( + (_PROVIDER_ID, None, WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING, None), + (None, None, None, None), + ( + _PROVIDER_ID, + _KEY_ID, + WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING, + WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING, + ), + ), +) +def test_invalid_parameters(key_namespace, key_name, wrapping_algorithm, wrapping_key): + with pytest.raises(TypeError): RawAESKeyring( - key_namespace=_PROVIDER_ID, - key_name=_KEY_ID, - wrapping_algorithm=WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING, - wrapping_key=WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING, + key_namespace=key_namespace, + key_name=key_name, + wrapping_algorithm=wrapping_algorithm, + wrapping_key=wrapping_key, ) - assert exc_info.match("'_wrapping_key' must be Date: Thu, 1 Aug 2019 18:44:57 -0700 Subject: [PATCH 112/119] Pulled from keyring branch --- test/unit/test_keyring_base.py | 50 ++++++---------------------------- 1 file changed, 8 insertions(+), 42 deletions(-) diff --git a/test/unit/test_keyring_base.py b/test/unit/test_keyring_base.py index 02ebc0a98..70863de53 100644 --- a/test/unit/test_keyring_base.py +++ b/test/unit/test_keyring_base.py @@ -13,18 +13,10 @@ """Unit tests for base keyring.""" import pytest -import six from aws_encryption_sdk.identifiers import Algorithm -from aws_encryption_sdk.keyring.base import EncryptedDataKey, Keyring +from aws_encryption_sdk.keyring.base import Keyring from aws_encryption_sdk.materials_managers import DecryptionMaterials, EncryptionMaterials -from aws_encryption_sdk.structures import MasterKeyInfo - -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] @@ -38,42 +30,16 @@ algorithm=Algorithm.AES_256_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384, verification_key=b"ex_verification_key" ) -_encrypted_data_keys = [ - EncryptedDataKey( - key_provider=MasterKeyInfo(provider_id="Random Raw Keys", key_info=b"5325b043-5843-4629-869c-64794af77ada"), - encrypted_data_key=six.b( - "\n \x8b\xc6\xfd\x91\xc7\xd5\xdc+S\x15n\xd9P\x99n\x1d\xb2\xdd\x15\xeaW" - "\xc3\x13k2\xf6\x02\xd0\x0f\x85\xec\x9e\x12\xa7\x01\x01\x01\x01\x00x" - "\x8b\xc6\xfd\x91\xc7\xd5\xdc+S\x15n\xd9P\x99n\x1d\xb2\xdd\x15\xeaW" - "\xc3\x13k2\xf6\x02\xd0\x0f\x85\xec\x9e\x00\x00\x00~0|\x06\t*\x86H" - "\x86\xf7\r\x01\x07\x06\xa0o0m\x02\x01\x000h\x06\t*\x86H\x86\xf7\r" - "\x01\x07\x010\x1e\x06\t`\x86H\x01e\x03\x04\x01.0\x11\x04\x0c\xc9rP" - "\xa1\x08t6{\xf2\xfd\xf1\xb3\x02\x01\x10\x80;D\xa4\xed`qP~c\x0f\xa0d" - "\xd5\xa2Kj\xc7\xb2\xc6\x1e\xec\xfb\x0fK\xb2*\xd5\t2\x81pR\xee\xd1" - '\x1a\xde<"\x1b\x98\x88\x8b\xf4&\xdaB\x95I\xd2\xff\x10\x13\xfc\x1aX' - "\x08,/\x8b\x8b" - ), - ) -] +_encrypted_data_keys = [] def test_keyring_no_encrypt(): - class KeyringNoEncrypt(Keyring): - def on_decrypt(self, _decryption_materials, _encrypted_data_keys): - # type: (DecryptionMaterials, Iterable[EncryptedDataKey]) -> DecryptionMaterials - return _decryption_materials - - with pytest.raises(TypeError) as exc_info: - KeyringNoEncrypt() - exc_info.match("Can't instantiate abstract class KeyringNoEncrypt with abstract methods on_encrypt") + with pytest.raises(NotImplementedError) as exc_info: + Keyring().on_encrypt(encryption_materials=_encryption_materials) + assert exc_info.match("Keyring does not implement on_encrypt function") def test_keyring_no_decrypt(): - class KeyringNoDecrypt(Keyring): - def on_encrypt(self, _encryption_materials): - # type: (EncryptionMaterials) -> EncryptionMaterials - return _encryption_materials - - with pytest.raises(TypeError) as exc_info: - KeyringNoDecrypt() - exc_info.match("Can't instantiate abstract class KeyringNoDecrypt with abstract methods on_decrypt") + with pytest.raises(NotImplementedError) as exc_info: + Keyring().on_decrypt(decryption_materials=_decryption_materials, encrypted_data_keys=_encrypted_data_keys) + assert exc_info.match("Keyring does not implement on_decrypt function") From 7ea1bd64304d22b03e710d713b10c9b3dd3f99c3 Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Thu, 1 Aug 2019 18:51:28 -0700 Subject: [PATCH 113/119] Updated base API --- src/aws_encryption_sdk/keyring/base.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/aws_encryption_sdk/keyring/base.py b/src/aws_encryption_sdk/keyring/base.py index f253ce500..770b53c0b 100644 --- a/src/aws_encryption_sdk/keyring/base.py +++ b/src/aws_encryption_sdk/keyring/base.py @@ -11,10 +11,6 @@ # 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.""" -import abc - -import six - from aws_encryption_sdk.materials_managers import DecryptionMaterials, EncryptionMaterials from aws_encryption_sdk.structures import EncryptedDataKey @@ -25,14 +21,12 @@ pass -@six.add_metaclass(abc.ABCMeta) class Keyring(object): """Parent interface for Keyring classes. .. versionadded:: 1.5.0 """ - @abc.abstractmethod def on_encrypt(self, encryption_materials): # type: (EncryptionMaterials) -> EncryptionMaterials """Generate a data key if not present and encrypt it using any available wrapping key. @@ -45,7 +39,6 @@ def on_encrypt(self, encryption_materials): """ raise NotImplementedError("Keyring does not implement on_encrypt function") - @abc.abstractmethod def on_decrypt(self, decryption_materials, encrypted_data_keys): # type: (DecryptionMaterials, Iterable[EncryptedDataKey]) -> DecryptionMaterials """Attempt to decrypt the encrypted data keys. From acbd5b4b442fa2eaa9e71a3b157b23a25bcb3481 Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Thu, 1 Aug 2019 19:34:28 -0700 Subject: [PATCH 114/119] Added test for key info prefix --- test/functional/test_f_keyring_raw_aes.py | 37 +++++++++++++++++------ test/unit/test_keyring_raw_aes.py | 5 ++- 2 files changed, 31 insertions(+), 11 deletions(-) diff --git a/test/functional/test_f_keyring_raw_aes.py b/test/functional/test_f_keyring_raw_aes.py index 372d3be41..dc8d646af 100644 --- a/test/functional/test_f_keyring_raw_aes.py +++ b/test/functional/test_f_keyring_raw_aes.py @@ -14,7 +14,15 @@ import pytest -from aws_encryption_sdk.identifiers import Algorithm, EncryptionType, KeyringTraceFlag, WrappingAlgorithm +from aws_encryption_sdk.identifiers import ( + Algorithm, + EncryptionKeyType, + EncryptionType, + KeyringTraceFlag, + WrappingAlgorithm, +) +from aws_encryption_sdk.internal.crypto import WrappingKey +from aws_encryption_sdk.internal.formatting.serialize import serialize_raw_master_key_prefix from aws_encryption_sdk.key_providers.raw import RawMasterKey from aws_encryption_sdk.keyring.raw_keyring import RawAESKeyring from aws_encryption_sdk.materials_managers import DecryptionMaterials, EncryptionMaterials @@ -81,15 +89,6 @@ def sample_encryption_materials(): ] -# -# _KEY_INFO_VECTORS = [ -# (b"5325b043-5843-4629-869c-64794af77ada", b"5325b043-5843-4629-869c-64794af77ada\x00\x00\x00\x80\x00\x00\x00\x0c", -# WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING), -# (b"30456b043-0323-4452-332a", b"30456b043-0323-4452-332a\x00\x00\x00\x80\x00\x00\x00\x0c", -# WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING) -# ] - - @pytest.mark.parametrize("encryption_materials_samples", sample_encryption_materials()) @pytest.mark.parametrize("wrapping_algorithm_samples", _WRAPPING_ALGORITHM) def test_raw_aes_encryption_decryption(encryption_materials_samples, wrapping_algorithm_samples): @@ -205,3 +204,21 @@ def test_raw_keyring_decrypts_what_raw_master_key_encrypts(encryption_materials_ encrypted_data_keys=[raw_master_key_encrypted_data_key], ).data_encryption_key.data_key ) + + +@pytest.mark.parametrize("wrapping_algorithm", _WRAPPING_ALGORITHM) +def test_key_info_prefix_vectors(wrapping_algorithm): + assert ( + serialize_raw_master_key_prefix( + raw_master_key=RawMasterKey( + provider_id=_PROVIDER_ID, + key_id=_KEY_ID, + wrapping_key=WrappingKey( + wrapping_algorithm=wrapping_algorithm, + wrapping_key=_WRAPPING_KEY, + wrapping_key_type=EncryptionKeyType.SYMMETRIC, + ), + ) + ) + == _KEY_ID + b"\x00\x00\x00\x80\x00\x00\x00\x0c" + ) diff --git a/test/unit/test_keyring_raw_aes.py b/test/unit/test_keyring_raw_aes.py index 3181c95cf..36a3834a1 100644 --- a/test/unit/test_keyring_raw_aes.py +++ b/test/unit/test_keyring_raw_aes.py @@ -13,6 +13,7 @@ """Unit tests for Raw AES keyring.""" import os +import unittest.mock import pytest from pytest_mock import mocker # noqa pylint: disable=unused-import @@ -213,7 +214,9 @@ def test_on_decrypt_when_data_key_not_provided_and_edk_provided(raw_aes_keyring, decryption_materials=get_decryption_materials_without_data_encryption_key(), encrypted_data_keys=[_ENCRYPTED_DATA_KEY_AES], ) - patch_decrypt_on_wrapping_key.assert_called_once() + patch_decrypt_on_wrapping_key.assert_called_once_with( + encrypted_wrapped_data_key=unittest.mock.ANY, encryption_context=unittest.mock.ANY + ) def test_keyring_trace_when_data_key_not_provided_and_edk_provided(raw_aes_keyring): From 837413034cfe645d6705c4bab8bf72a174596d5f Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Thu, 1 Aug 2019 20:35:05 -0700 Subject: [PATCH 115/119] Changed unittest.mock to mock --- test/unit/test_keyring_raw_aes.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/unit/test_keyring_raw_aes.py b/test/unit/test_keyring_raw_aes.py index 36a3834a1..935a01eea 100644 --- a/test/unit/test_keyring_raw_aes.py +++ b/test/unit/test_keyring_raw_aes.py @@ -13,8 +13,8 @@ """Unit tests for Raw AES keyring.""" import os -import unittest.mock +import mock import pytest from pytest_mock import mocker # noqa pylint: disable=unused-import @@ -215,7 +215,7 @@ def test_on_decrypt_when_data_key_not_provided_and_edk_provided(raw_aes_keyring, encrypted_data_keys=[_ENCRYPTED_DATA_KEY_AES], ) patch_decrypt_on_wrapping_key.assert_called_once_with( - encrypted_wrapped_data_key=unittest.mock.ANY, encryption_context=unittest.mock.ANY + encrypted_wrapped_data_key=mock.ANY, encryption_context=mock.ANY ) From 1dc5a77868c986fa96c2eaf8d046c65f3c144ca9 Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Fri, 2 Aug 2019 00:09:53 -0700 Subject: [PATCH 116/119] Raw keyrings test partial commit --- src/aws_encryption_sdk/keyring/raw_keyring.py | 10 ++-- test/functional/test_f_keyring_raw_aes.py | 52 +++++++++++-------- test/functional/test_f_keyring_raw_rsa.py | 51 +++++++++++++++++- test/unit/test_keyring_raw_aes.py | 2 + test/unit/test_keyring_raw_rsa.py | 16 ++++-- test/unit/test_utils.py | 13 +---- test/unit/unit_test_utils.py | 19 ++++++- 7 files changed, 120 insertions(+), 43 deletions(-) diff --git a/src/aws_encryption_sdk/keyring/raw_keyring.py b/src/aws_encryption_sdk/keyring/raw_keyring.py index 71c798374..513119246 100644 --- a/src/aws_encryption_sdk/keyring/raw_keyring.py +++ b/src/aws_encryption_sdk/keyring/raw_keyring.py @@ -80,13 +80,17 @@ def _generate_data_key( @attr.s class RawAESKeyring(Keyring): - """Generate an instance for Raw AES Keyring using provided parameters + """Generate an instance of Raw AES Keyring which encrypts using AES-GCM algorithm using wrapping key provided as a + byte array :param str key_namespace: String defining the keyring. :param bytes key_name: Key ID :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 + + .. note:: + Only one wrapping key can be specified in a Raw AES Keyring """ key_namespace = attr.ib(validator=instance_of(six.string_types)) @@ -225,8 +229,8 @@ def on_decrypt(self, decryption_materials, encrypted_data_keys): @attr.s class RawRSAKeyring(Keyring): - """Generate an instance for Raw RSA Keyring using public and private keys which are instances of RSAPublicKey - and RSAPrivateKey + """Generate an instance of Raw RSA Keyring which performs asymmetric encryption and decryption using public + and private keys provided :param str key_namespace: String defining the keyring ID :param bytes key_name: Key ID diff --git a/test/functional/test_f_keyring_raw_aes.py b/test/functional/test_f_keyring_raw_aes.py index dc8d646af..d24bf89fd 100644 --- a/test/functional/test_f_keyring_raw_aes.py +++ b/test/functional/test_f_keyring_raw_aes.py @@ -70,8 +70,9 @@ def sample_encryption_materials(): 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", + encrypted_data_key=b"\xde^\x97\x7f\x84\xe9\x9e\x98\xd0\xe2\xf8\xd5\xcb\xe9\x7f.}\x87\x16," + b"\x11n#\xc8p\xdb\xbf\x94\x86*Q\x06\xd2\xf5\xdah\x08\xa4p\x81\xf7\xf4G" + b"\x07FzE\xde", ) ], encryption_context=_ENCRYPTION_CONTEXT, @@ -153,13 +154,15 @@ def test_raw_master_key_decrypts_what_raw_keyring_encrypts(encryption_materials_ encryption_materials = test_raw_aes_keyring.on_encrypt(encryption_materials=encryption_materials_samples) # Check if plaintext data key encrypted by raw keyring is decrypted by raw master key - assert ( - encryption_materials.data_encryption_key.data_key - == test_raw_master_key.decrypt_data_key_from_list( + + raw_mkp_decrypted_data_key = test_raw_master_key.decrypt_data_key_from_list( encrypted_data_keys=encryption_materials._encrypted_data_keys, algorithm=encryption_materials.algorithm, encryption_context=encryption_materials.encryption_context, ).data_key + + assert ( + encryption_materials.data_encryption_key.data_key == raw_mkp_decrypted_data_key ) @@ -187,23 +190,28 @@ def test_raw_keyring_decrypts_what_raw_master_key_encrypts(encryption_materials_ wrapping_key=test_raw_aes_keyring._wrapping_key_structure, ) - if encryption_materials_samples.data_encryption_key is not None: - raw_master_key_encrypted_data_key = test_raw_master_key.encrypt_data_key( - data_key=encryption_materials_samples.data_encryption_key, - algorithm=encryption_materials_samples.algorithm, - encryption_context=encryption_materials_samples.encryption_context, - ) - assert ( - encryption_materials_samples.data_encryption_key.data_key - == test_raw_aes_keyring.on_decrypt( - decryption_materials=DecryptionMaterials( - algorithm=encryption_materials_samples.algorithm, - encryption_context=encryption_materials_samples.encryption_context, - verification_key=b"ex_verification_key", - ), - encrypted_data_keys=[raw_master_key_encrypted_data_key], - ).data_encryption_key.data_key - ) + if encryption_materials_samples.data_encryption_key is None: + return + raw_master_key_encrypted_data_key = test_raw_master_key.encrypt_data_key( + data_key=encryption_materials_samples.data_encryption_key, + algorithm=encryption_materials_samples.algorithm, + encryption_context=encryption_materials_samples.encryption_context, + ) + + # Check if plaintext data key encrypted by raw master key is decrypted by raw keyring + + raw_aes_keyring_decrypted_data_key = test_raw_aes_keyring.on_decrypt( + decryption_materials=DecryptionMaterials( + algorithm=encryption_materials_samples.algorithm, + encryption_context=encryption_materials_samples.encryption_context, + verification_key=b"ex_verification_key", + ), + encrypted_data_keys=[raw_master_key_encrypted_data_key], + ).data_encryption_key.data_key + + assert ( + encryption_materials_samples.data_encryption_key.data_key == raw_aes_keyring_decrypted_data_key + ) @pytest.mark.parametrize("wrapping_algorithm", _WRAPPING_ALGORITHM) diff --git a/test/functional/test_f_keyring_raw_rsa.py b/test/functional/test_f_keyring_raw_rsa.py index 3a7700983..e7b710ff3 100644 --- a/test/functional/test_f_keyring_raw_rsa.py +++ b/test/functional/test_f_keyring_raw_rsa.py @@ -17,7 +17,10 @@ from cryptography.hazmat.primitives import serialization from cryptography.hazmat.primitives.asymmetric import rsa -from aws_encryption_sdk.identifiers import Algorithm, EncryptionType, KeyringTraceFlag, WrappingAlgorithm +from aws_encryption_sdk.identifiers import Algorithm, EncryptionType, KeyringTraceFlag, WrappingAlgorithm, \ + EncryptionKeyType +from aws_encryption_sdk.internal.crypto import WrappingKey +from aws_encryption_sdk.key_providers.raw import RawMasterKey from aws_encryption_sdk.keyring.raw_keyring import RawRSAKeyring from aws_encryption_sdk.materials_managers import DecryptionMaterials, EncryptionMaterials from aws_encryption_sdk.structures import EncryptedDataKey, KeyringTrace, MasterKeyInfo, RawDataKey @@ -195,7 +198,8 @@ def test_raw_rsa_encryption_decryption(encryption_materials_samples, test_raw_rs # 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 @@ -206,3 +210,46 @@ def test_raw_rsa_encryption_decryption(encryption_materials_samples, test_raw_rs if test_raw_rsa_keyring._private_wrapping_key is not None: # Check if the data keys match assert encryption_materials.data_encryption_key.data_key == decryption_materials.data_encryption_key.data_key + + +@pytest.mark.parametrize("encryption_materials_samples", _ENCRYPTION_MATERIALS) +def test_raw_master_key_decrypts_what_raw_keyring_encrypts(encryption_materials_samples): + test_raw_rsa_keyring = RawRSAKeyring( + key_namespace=_PROVIDER_ID, + key_name=_KEY_ID, + wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, + private_wrapping_key=_PRIVATE_WRAPPING_KEY, + ) + + # Creating an instance of a raw master key + test_raw_master_key = RawMasterKey( + key_id=test_raw_rsa_keyring.key_name, + provider_id=test_raw_rsa_keyring.key_namespace, + wrapping_key=WrappingKey( + wrapping_algorithm=test_raw_rsa_keyring._wrapping_algorithm, + ###--------HOWWWWWWW---------- + wrapping_key=test_raw_rsa_keyring._private_wrapping_key.private_bytes( + encoding=serialization.Encoding.Raw, + format=serialization.PrivateFormat.Raw, + encryption_algorithm=serialization.NoEncryption() + ), + wrapping_key_type=EncryptionKeyType.PRIVATE, + ), + ) + + # Call on_encrypt function for the keyring + encryption_materials = test_raw_rsa_keyring.on_encrypt(encryption_materials=encryption_materials_samples) + + # Check if plaintext data key encrypted by raw keyring is decrypted by raw master key + + raw_mkp_decrypted_data_key = test_raw_master_key.decrypt_data_key_from_list( + encrypted_data_keys=encryption_materials._encrypted_data_keys, + algorithm=encryption_materials.algorithm, + encryption_context=encryption_materials.encryption_context, + ).data_key + + assert (encryption_materials.data_encryption_key.data_key == raw_mkp_decrypted_data_key) + + +@pytest.mark.parametrize("encryption_materials_samples", _ENCRYPTION_MATERIALS) +def test_raw_keyring_decrypts_what_raw_master_key_encrypts(encryption_materials_samples): diff --git a/test/unit/test_keyring_raw_aes.py b/test/unit/test_keyring_raw_aes.py index 935a01eea..a573a6d31 100644 --- a/test/unit/test_keyring_raw_aes.py +++ b/test/unit/test_keyring_raw_aes.py @@ -96,6 +96,8 @@ def test_valid_parameters(raw_aes_keyring): WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING, WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING, ), + (Algorithm.AES_256_GCM_IV12_TAG16_HKDF_SHA256, Algorithm.AES_256_GCM_IV12_TAG16, + Algorithm.AES_128_GCM_IV12_TAG16, Algorithm.AES_128_GCM_IV12_TAG16) ), ) def test_invalid_parameters(key_namespace, key_name, wrapping_algorithm, wrapping_key): diff --git a/test/unit/test_keyring_raw_rsa.py b/test/unit/test_keyring_raw_rsa.py index 20d5c2ed1..3b38ec82f 100644 --- a/test/unit/test_keyring_raw_rsa.py +++ b/test/unit/test_keyring_raw_rsa.py @@ -25,14 +25,14 @@ from .test_values import VALUES from .unit_test_utils import ( - _BACKEND, _DATA_KEY, _ENCRYPTED_DATA_KEY_RSA, _ENCRYPTION_CONTEXT, _KEY_ID, - _KEY_SIZE, _PROVIDER_ID, _PUBLIC_EXPONENT, + _BACKEND, + _KEY_SIZE, get_decryption_materials_with_data_encryption_key, get_decryption_materials_without_data_encryption_key, get_encryption_materials_with_data_encryption_key, @@ -52,6 +52,14 @@ def raw_rsa_keyring(): ) +def raw_rsa_private_key(): + return rsa.generate_private_key( + public_exponent=_PUBLIC_EXPONENT, + key_size=_KEY_SIZE, + backend=_BACKEND + ) + + @pytest.fixture def patch_generate_data_key(mocker): mocker.patch.object(aws_encryption_sdk.keyring.raw_keyring, "_generate_data_key") @@ -85,9 +93,11 @@ def test_valid_parameters(raw_rsa_keyring): @pytest.mark.parametrize( "key_namespace, key_name, wrapping_algorithm, private_wrapping_key, public_wrapping_key", ( - (_PROVIDER_ID, None, WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, VALUES["private_rsa_key_bytes"][1], None), + (_PROVIDER_ID, None, WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, raw_rsa_private_key(), None), (None, None, None, None, None), (_PROVIDER_ID, _KEY_ID, WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, None), + (None, None, None, raw_rsa_private_key(), raw_rsa_private_key().public_key()), + (len(_PROVIDER_ID), len(_KEY_ID), _PROVIDER_ID, _PROVIDER_ID, _KEY_ID) ), ) def test_invalid_parameters(key_namespace, key_name, wrapping_algorithm, private_wrapping_key, public_wrapping_key): diff --git a/test/unit/test_utils.py b/test/unit/test_utils.py index 3273ba1e0..0dee36b41 100644 --- a/test/unit/test_utils.py +++ b/test/unit/test_utils.py @@ -21,8 +21,7 @@ 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.keyring.base import EncryptedDataKey, Keyring -from aws_encryption_sdk.materials_managers import DecryptionMaterials, EncryptionMaterials +from aws_encryption_sdk.keyring.base import EncryptedDataKey from aws_encryption_sdk.structures import DataKey, MasterKeyInfo, RawDataKey from .test_values import VALUES @@ -44,16 +43,6 @@ def test_prep_stream_data_wrap(source): assert_prepped_stream_identity(test, io.BytesIO) -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 TestUtils(object): @pytest.fixture(autouse=True) def apply_fixtures(self): diff --git a/test/unit/unit_test_utils.py b/test/unit/unit_test_utils.py index 317bb588f..f841c4c80 100644 --- a/test/unit/unit_test_utils.py +++ b/test/unit/unit_test_utils.py @@ -19,10 +19,17 @@ from aws_encryption_sdk.identifiers import Algorithm, KeyringTraceFlag from aws_encryption_sdk.internal.utils.streams import InsistentReaderBytesIO -from aws_encryption_sdk.keyring.base import EncryptedDataKey +from aws_encryption_sdk.keyring.base import EncryptedDataKey, Keyring from aws_encryption_sdk.materials_managers import DecryptionMaterials, EncryptionMaterials from aws_encryption_sdk.structures import 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" @@ -71,6 +78,16 @@ ) +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 + + def get_encryption_materials_with_data_encryption_key(): return EncryptionMaterials( algorithm=Algorithm.AES_256_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384, From 5a7e4b2de7195a202f45d19909b3806c4837b66b Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Fri, 2 Aug 2019 12:28:33 -0700 Subject: [PATCH 117/119] All tests for raw keyrings work --- test/functional/test_f_keyring_raw_aes.py | 56 ++----- test/functional/test_f_keyring_raw_rsa.py | 176 ++++++++++++++-------- test/unit/test_keyring_raw_aes.py | 8 +- test/unit/test_keyring_raw_rsa.py | 12 +- test/unit/unit_test_utils.py | 1 - 5 files changed, 132 insertions(+), 121 deletions(-) diff --git a/test/functional/test_f_keyring_raw_aes.py b/test/functional/test_f_keyring_raw_aes.py index d24bf89fd..34e66f1df 100644 --- a/test/functional/test_f_keyring_raw_aes.py +++ b/test/functional/test_f_keyring_raw_aes.py @@ -61,32 +61,6 @@ def sample_encryption_materials(): ) ], ), - 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," - b"\x11n#\xc8p\xdb\xbf\x94\x86*Q\x06\xd2\xf5\xdah\x08\xa4p\x81\xf7\xf4G" - b"\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, - }, - ) - ], - ), ] @@ -156,14 +130,12 @@ def test_raw_master_key_decrypts_what_raw_keyring_encrypts(encryption_materials_ # Check if plaintext data key encrypted by raw keyring is decrypted by raw master key raw_mkp_decrypted_data_key = test_raw_master_key.decrypt_data_key_from_list( - encrypted_data_keys=encryption_materials._encrypted_data_keys, - algorithm=encryption_materials.algorithm, - encryption_context=encryption_materials.encryption_context, - ).data_key + encrypted_data_keys=encryption_materials._encrypted_data_keys, + algorithm=encryption_materials.algorithm, + encryption_context=encryption_materials.encryption_context, + ).data_key - assert ( - encryption_materials.data_encryption_key.data_key == raw_mkp_decrypted_data_key - ) + assert encryption_materials.data_encryption_key.data_key == raw_mkp_decrypted_data_key @pytest.mark.parametrize("encryption_materials_samples", sample_encryption_materials()) @@ -201,17 +173,15 @@ def test_raw_keyring_decrypts_what_raw_master_key_encrypts(encryption_materials_ # Check if plaintext data key encrypted by raw master key is decrypted by raw keyring raw_aes_keyring_decrypted_data_key = test_raw_aes_keyring.on_decrypt( - decryption_materials=DecryptionMaterials( - algorithm=encryption_materials_samples.algorithm, - encryption_context=encryption_materials_samples.encryption_context, - verification_key=b"ex_verification_key", - ), - encrypted_data_keys=[raw_master_key_encrypted_data_key], - ).data_encryption_key.data_key + decryption_materials=DecryptionMaterials( + algorithm=encryption_materials_samples.algorithm, + encryption_context=encryption_materials_samples.encryption_context, + verification_key=b"ex_verification_key", + ), + encrypted_data_keys=[raw_master_key_encrypted_data_key], + ).data_encryption_key.data_key - assert ( - encryption_materials_samples.data_encryption_key.data_key == raw_aes_keyring_decrypted_data_key - ) + assert encryption_materials_samples.data_encryption_key.data_key == raw_aes_keyring_decrypted_data_key @pytest.mark.parametrize("wrapping_algorithm", _WRAPPING_ALGORITHM) diff --git a/test/functional/test_f_keyring_raw_rsa.py b/test/functional/test_f_keyring_raw_rsa.py index e7b710ff3..b9d8f679d 100644 --- a/test/functional/test_f_keyring_raw_rsa.py +++ b/test/functional/test_f_keyring_raw_rsa.py @@ -17,8 +17,13 @@ from cryptography.hazmat.primitives import serialization from cryptography.hazmat.primitives.asymmetric import rsa -from aws_encryption_sdk.identifiers import Algorithm, EncryptionType, KeyringTraceFlag, WrappingAlgorithm, \ - EncryptionKeyType +from aws_encryption_sdk.identifiers import ( + Algorithm, + EncryptionKeyType, + EncryptionType, + KeyringTraceFlag, + WrappingAlgorithm, +) from aws_encryption_sdk.internal.crypto import WrappingKey from aws_encryption_sdk.key_providers.raw import RawMasterKey from aws_encryption_sdk.keyring.raw_keyring import RawRSAKeyring @@ -30,7 +35,6 @@ _ENCRYPTION_CONTEXT = {"encryption": "context", "values": "here"} _PROVIDER_ID = "Random Raw Keys" _KEY_ID = b"5325b043-5843-4629-869c-64794af77ada" -_SIGNING_KEY = b"aws-crypto-public-key" _WRAPPING_ALGORITHM = WrappingAlgorithm.RSA_OAEP_SHA256_MGF1 _PUBLIC_EXPONENT = 65537 @@ -39,6 +43,35 @@ _PRIVATE_WRAPPING_KEY = rsa.generate_private_key(public_exponent=_PUBLIC_EXPONENT, key_size=_KEY_SIZE, backend=_BACKEND) +_PRIVATE_WRAPPING_KEY_PEM = ( + 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" +) _RAW_RSA_PRIVATE_KEY_PEM_ENCODED_WITHOUT_PASSWORD = rsa.generate_private_key( public_exponent=_PUBLIC_EXPONENT, key_size=_KEY_SIZE, backend=_BACKEND @@ -84,53 +117,27 @@ .public_bytes(encoding=serialization.Encoding.DER, format=serialization.PublicFormat.SubjectPublicKeyInfo) ) -_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(', + +def sample_encryption_materials(): + return [ + EncryptionMaterials( + algorithm=Algorithm.AES_256_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384, encryption_context=_ENCRYPTION_CONTEXT ), - encrypted_data_keys=[ - EncryptedDataKey( + 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), - 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, - }, - ) - ], - ), -] + data_key=b'*!\xa1"^-(\xf3\x105\x05i@B\xc2\xa2\xb7\xdd\xd5\xd5\xa9\xddm\xfae\xa8\\$\xf9d\x1e(', + ), + encryption_context=_ENCRYPTION_CONTEXT, + keyring_trace=[ + KeyringTrace( + wrapping_key=MasterKeyInfo(provider_id=_PROVIDER_ID, key_info=_KEY_ID), + flags={KeyringTraceFlag.WRAPPING_KEY_GENERATED_DATA_KEY}, + ) + ], + ), + ] def sample_raw_rsa_keyring_using_different_wrapping_algorithm(): @@ -187,7 +194,7 @@ def sample_raw_rsa_keyring_using_different_wrapping_algorithm(): yield keyring -@pytest.mark.parametrize("encryption_materials_samples", _ENCRYPTION_MATERIALS) +@pytest.mark.parametrize("encryption_materials_samples", sample_encryption_materials()) @pytest.mark.parametrize("test_raw_rsa_keyring", sample_raw_rsa_keyring_using_different_wrapping_algorithm()) def test_raw_rsa_encryption_decryption(encryption_materials_samples, test_raw_rsa_keyring): @@ -198,8 +205,9 @@ def test_raw_rsa_encryption_decryption(encryption_materials_samples, test_raw_rs # 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.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 @@ -212,27 +220,22 @@ def test_raw_rsa_encryption_decryption(encryption_materials_samples, test_raw_rs assert encryption_materials.data_encryption_key.data_key == decryption_materials.data_encryption_key.data_key -@pytest.mark.parametrize("encryption_materials_samples", _ENCRYPTION_MATERIALS) +@pytest.mark.parametrize("encryption_materials_samples", sample_encryption_materials()) def test_raw_master_key_decrypts_what_raw_keyring_encrypts(encryption_materials_samples): - test_raw_rsa_keyring = RawRSAKeyring( + test_raw_rsa_keyring = RawRSAKeyring.from_pem_encoding( key_namespace=_PROVIDER_ID, key_name=_KEY_ID, - wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, - private_wrapping_key=_PRIVATE_WRAPPING_KEY, + wrapping_algorithm=_WRAPPING_ALGORITHM, + private_encoded_key=_PRIVATE_WRAPPING_KEY_PEM, ) # Creating an instance of a raw master key test_raw_master_key = RawMasterKey( - key_id=test_raw_rsa_keyring.key_name, - provider_id=test_raw_rsa_keyring.key_namespace, + key_id=_KEY_ID, + provider_id=_PROVIDER_ID, wrapping_key=WrappingKey( - wrapping_algorithm=test_raw_rsa_keyring._wrapping_algorithm, - ###--------HOWWWWWWW---------- - wrapping_key=test_raw_rsa_keyring._private_wrapping_key.private_bytes( - encoding=serialization.Encoding.Raw, - format=serialization.PrivateFormat.Raw, - encryption_algorithm=serialization.NoEncryption() - ), + wrapping_algorithm=_WRAPPING_ALGORITHM, + wrapping_key=_PRIVATE_WRAPPING_KEY_PEM, wrapping_key_type=EncryptionKeyType.PRIVATE, ), ) @@ -241,15 +244,54 @@ def test_raw_master_key_decrypts_what_raw_keyring_encrypts(encryption_materials_ encryption_materials = test_raw_rsa_keyring.on_encrypt(encryption_materials=encryption_materials_samples) # Check if plaintext data key encrypted by raw keyring is decrypted by raw master key - raw_mkp_decrypted_data_key = test_raw_master_key.decrypt_data_key_from_list( encrypted_data_keys=encryption_materials._encrypted_data_keys, algorithm=encryption_materials.algorithm, encryption_context=encryption_materials.encryption_context, ).data_key - assert (encryption_materials.data_encryption_key.data_key == raw_mkp_decrypted_data_key) + assert encryption_materials.data_encryption_key.data_key == raw_mkp_decrypted_data_key -@pytest.mark.parametrize("encryption_materials_samples", _ENCRYPTION_MATERIALS) +@pytest.mark.parametrize("encryption_materials_samples", sample_encryption_materials()) def test_raw_keyring_decrypts_what_raw_master_key_encrypts(encryption_materials_samples): + + # Create instance of raw master key + test_raw_master_key = RawMasterKey( + key_id=_KEY_ID, + provider_id=_PROVIDER_ID, + wrapping_key=WrappingKey( + wrapping_algorithm=_WRAPPING_ALGORITHM, + wrapping_key=_PRIVATE_WRAPPING_KEY_PEM, + wrapping_key_type=EncryptionKeyType.PRIVATE, + ), + ) + + test_raw_rsa_keyring = RawRSAKeyring.from_pem_encoding( + key_namespace=_PROVIDER_ID, + key_name=_KEY_ID, + wrapping_algorithm=_WRAPPING_ALGORITHM, + private_encoded_key=_PRIVATE_WRAPPING_KEY_PEM, + ) + + raw_mkp_generated_data_key = test_raw_master_key.generate_data_key( + algorithm=encryption_materials_samples.algorithm, + encryption_context=encryption_materials_samples.encryption_context, + ) + + raw_mkp_encrypted_data_key = test_raw_master_key.encrypt_data_key( + data_key=raw_mkp_generated_data_key, + algorithm=encryption_materials_samples.algorithm, + encryption_context=encryption_materials_samples.encryption_context, + ) + + decryption_materials = test_raw_rsa_keyring.on_decrypt( + decryption_materials=DecryptionMaterials( + algorithm=encryption_materials_samples.algorithm, + encryption_context=encryption_materials_samples.encryption_context, + verification_key=b"ex_verification_key", + ), + encrypted_data_keys=[raw_mkp_encrypted_data_key], + ) + + assert raw_mkp_generated_data_key.data_key == decryption_materials.data_encryption_key.data_key diff --git a/test/unit/test_keyring_raw_aes.py b/test/unit/test_keyring_raw_aes.py index a573a6d31..b98279d04 100644 --- a/test/unit/test_keyring_raw_aes.py +++ b/test/unit/test_keyring_raw_aes.py @@ -96,8 +96,12 @@ def test_valid_parameters(raw_aes_keyring): WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING, WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING, ), - (Algorithm.AES_256_GCM_IV12_TAG16_HKDF_SHA256, Algorithm.AES_256_GCM_IV12_TAG16, - Algorithm.AES_128_GCM_IV12_TAG16, Algorithm.AES_128_GCM_IV12_TAG16) + ( + Algorithm.AES_256_GCM_IV12_TAG16_HKDF_SHA256, + Algorithm.AES_256_GCM_IV12_TAG16, + Algorithm.AES_128_GCM_IV12_TAG16, + Algorithm.AES_128_GCM_IV12_TAG16, + ), ), ) def test_invalid_parameters(key_namespace, key_name, wrapping_algorithm, wrapping_key): diff --git a/test/unit/test_keyring_raw_rsa.py b/test/unit/test_keyring_raw_rsa.py index 3b38ec82f..1fcf23da5 100644 --- a/test/unit/test_keyring_raw_rsa.py +++ b/test/unit/test_keyring_raw_rsa.py @@ -25,14 +25,14 @@ from .test_values import VALUES from .unit_test_utils import ( + _BACKEND, _DATA_KEY, _ENCRYPTED_DATA_KEY_RSA, _ENCRYPTION_CONTEXT, _KEY_ID, + _KEY_SIZE, _PROVIDER_ID, _PUBLIC_EXPONENT, - _BACKEND, - _KEY_SIZE, get_decryption_materials_with_data_encryption_key, get_decryption_materials_without_data_encryption_key, get_encryption_materials_with_data_encryption_key, @@ -53,11 +53,7 @@ def raw_rsa_keyring(): def raw_rsa_private_key(): - return rsa.generate_private_key( - public_exponent=_PUBLIC_EXPONENT, - key_size=_KEY_SIZE, - backend=_BACKEND - ) + return rsa.generate_private_key(public_exponent=_PUBLIC_EXPONENT, key_size=_KEY_SIZE, backend=_BACKEND) @pytest.fixture @@ -97,7 +93,7 @@ def test_valid_parameters(raw_rsa_keyring): (None, None, None, None, None), (_PROVIDER_ID, _KEY_ID, WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, WrappingAlgorithm.RSA_OAEP_SHA256_MGF1, None), (None, None, None, raw_rsa_private_key(), raw_rsa_private_key().public_key()), - (len(_PROVIDER_ID), len(_KEY_ID), _PROVIDER_ID, _PROVIDER_ID, _KEY_ID) + (len(_PROVIDER_ID), len(_KEY_ID), _PROVIDER_ID, _PROVIDER_ID, _KEY_ID), ), ) def test_invalid_parameters(key_namespace, key_name, wrapping_algorithm, private_wrapping_key, public_wrapping_key): diff --git a/test/unit/unit_test_utils.py b/test/unit/unit_test_utils.py index f841c4c80..087c8dfa5 100644 --- a/test/unit/unit_test_utils.py +++ b/test/unit/unit_test_utils.py @@ -23,7 +23,6 @@ from aws_encryption_sdk.materials_managers import DecryptionMaterials, EncryptionMaterials from aws_encryption_sdk.structures import 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 ced07c4a44abfe3cb1a79f322e8c4c39273a67a7 Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Fri, 2 Aug 2019 12:52:39 -0700 Subject: [PATCH 118/119] Removed unused imports --- test/functional/test_f_keyring_raw_aes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/functional/test_f_keyring_raw_aes.py b/test/functional/test_f_keyring_raw_aes.py index 34e66f1df..aa08b07ff 100644 --- a/test/functional/test_f_keyring_raw_aes.py +++ b/test/functional/test_f_keyring_raw_aes.py @@ -26,7 +26,7 @@ from aws_encryption_sdk.key_providers.raw import RawMasterKey from aws_encryption_sdk.keyring.raw_keyring import RawAESKeyring 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 88cd0974694bb910b2f52299e699cf026d153d30 Mon Sep 17 00:00:00 2001 From: Megha Vasant Shetty Date: Fri, 2 Aug 2019 13:17:39 -0700 Subject: [PATCH 119/119] Removed unused imports --- test/functional/test_f_keyring_raw_rsa.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/functional/test_f_keyring_raw_rsa.py b/test/functional/test_f_keyring_raw_rsa.py index b9d8f679d..bdf5bf25c 100644 --- a/test/functional/test_f_keyring_raw_rsa.py +++ b/test/functional/test_f_keyring_raw_rsa.py @@ -28,7 +28,7 @@ from aws_encryption_sdk.key_providers.raw import RawMasterKey from aws_encryption_sdk.keyring.raw_keyring import 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]