diff --git a/README.rst b/README.rst
index c0ab1b00..fc71a793 100644
--- a/README.rst
+++ b/README.rst
@@ -10,6 +10,10 @@ Amazon DynamoDB Encryption Client for Python
:target: https://pypi.org/project/dynamodb-encryption-sdk
:alt: Supported Python Versions
+.. image:: https://img.shields.io/badge/code_style-black-000000.svg
+ :target: https://github.com/ambv/black
+ :alt: Code style: black
+
.. image:: https://readthedocs.org/projects/aws-dynamodb-encryption-python/badge/?version=latest
:target: http://aws-dynamodb-encryption-python.readthedocs.io/en/latest/?badge=latest
:alt: Documentation Status
diff --git a/doc/conf.py b/doc/conf.py
index 70858231..576f77c5 100644
--- a/doc/conf.py
+++ b/doc/conf.py
@@ -1,70 +1,76 @@
# pylint: disable=invalid-name
"""Sphinx configuration."""
-from datetime import datetime
import io
import os
import re
+from datetime import datetime
-VERSION_RE = re.compile(r'''__version__ = ['"]([0-9.]+)['"]''')
+VERSION_RE = re.compile(r"""__version__ = ['"]([0-9.]+)['"]""")
HERE = os.path.abspath(os.path.dirname(__file__))
def read(*args):
"""Reads complete file contents."""
- return io.open(os.path.join(HERE, *args), encoding='utf-8').read()
+ return io.open(os.path.join(HERE, *args), encoding="utf-8").read()
def get_release():
"""Reads the release (full three-part version number) from this module."""
- init = read('..', 'src', 'dynamodb_encryption_sdk', 'identifiers.py')
+ init = read("..", "src", "dynamodb_encryption_sdk", "identifiers.py")
return VERSION_RE.search(init).group(1)
def get_version():
"""Reads the version (MAJOR.MINOR) from this module."""
_release = get_release()
- split_version = _release.split('.')
+ split_version = _release.split(".")
if len(split_version) == 3:
- return '.'.join(split_version[:2])
+ return ".".join(split_version[:2])
return _release
-project = u'dynamodb-encryption-sdk-python'
+project = u"dynamodb-encryption-sdk-python"
version = get_version()
release = get_release()
# Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
-extensions = ['sphinx.ext.autodoc', 'sphinx.ext.doctest',
- 'sphinx.ext.intersphinx', 'sphinx.ext.todo',
- 'sphinx.ext.coverage', 'sphinx.ext.autosummary',
- 'sphinx.ext.napoleon', 'sphinx.ext.viewcode']
+extensions = [
+ "sphinx.ext.autodoc",
+ "sphinx.ext.doctest",
+ "sphinx.ext.intersphinx",
+ "sphinx.ext.todo",
+ "sphinx.ext.coverage",
+ "sphinx.ext.autosummary",
+ "sphinx.ext.napoleon",
+ "sphinx.ext.viewcode",
+]
napoleon_include_special_with_doc = False
# Add any paths that contain templates here, relative to this directory.
-templates_path = ['_templates']
+templates_path = ["_templates"]
-source_suffix = '.rst' # The suffix of source filenames.
-master_doc = 'index' # The master toctree document.
+source_suffix = ".rst" # The suffix of source filenames.
+master_doc = "index" # The master toctree document.
-copyright = u'%s, Amazon' % datetime.now().year # pylint: disable=redefined-builtin
+copyright = u"%s, Amazon" % datetime.now().year # pylint: disable=redefined-builtin
# List of directories, relative to source directory, that shouldn't be searched
# for source files.
-exclude_trees = ['_build']
+exclude_trees = ["_build"]
-pygments_style = 'sphinx'
+pygments_style = "sphinx"
autoclass_content = "both"
-autodoc_default_flags = ['show-inheritance', 'members']
-autodoc_member_order = 'bysource'
+autodoc_default_flags = ["show-inheritance", "members"]
+autodoc_member_order = "bysource"
-html_theme = 'sphinx_rtd_theme'
-html_static_path = ['_static']
-htmlhelp_basename = '%sdoc' % project
+html_theme = "sphinx_rtd_theme"
+html_static_path = ["_static"]
+htmlhelp_basename = "%sdoc" % project
# Example configuration for intersphinx: refer to the Python standard library.
-intersphinx_mapping = {'python': ('http://docs.python.org/', None)}
+intersphinx_mapping = {"python": ("http://docs.python.org/", None)}
# autosummary
autosummary_generate = True
diff --git a/examples/src/aws_kms_encrypted_client.py b/examples/src/aws_kms_encrypted_client.py
index 691951c1..c3f4bd53 100644
--- a/examples/src/aws_kms_encrypted_client.py
+++ b/examples/src/aws_kms_encrypted_client.py
@@ -12,6 +12,7 @@
# language governing permissions and limitations under the License.
"""Example showing use of AWS KMS CMP with EncryptedClient."""
import boto3
+
from dynamodb_encryption_sdk.encrypted.client import EncryptedClient
from dynamodb_encryption_sdk.identifiers import CryptoAction
from dynamodb_encryption_sdk.material_providers.aws_kms import AwsKmsCryptographicMaterialsProvider
@@ -20,51 +21,41 @@
def encrypt_item(table_name, aws_cmk_id):
"""Demonstrate use of EncryptedClient to transparently encrypt an item."""
- index_key = {
- 'partition_attribute': {'S': 'is this'},
- 'sort_attribute': {'N': '55'}
- }
+ index_key = {"partition_attribute": {"S": "is this"}, "sort_attribute": {"N": "55"}}
plaintext_item = {
- 'example': {'S': 'data'},
- 'some numbers': {'N': '99'},
- 'and some binary': {'B': b'\x00\x01\x02'},
- 'leave me': {'S': 'alone'} # We want to ignore this attribute
+ "example": {"S": "data"},
+ "some numbers": {"N": "99"},
+ "and some binary": {"B": b"\x00\x01\x02"},
+ "leave me": {"S": "alone"}, # We want to ignore this attribute
}
# Collect all of the attributes that will be encrypted (used later).
encrypted_attributes = set(plaintext_item.keys())
- encrypted_attributes.remove('leave me')
+ encrypted_attributes.remove("leave me")
# Collect all of the attributes that will not be encrypted (used later).
unencrypted_attributes = set(index_key.keys())
- unencrypted_attributes.add('leave me')
+ unencrypted_attributes.add("leave me")
# Add the index pairs to the item.
plaintext_item.update(index_key)
# Create a normal client.
- client = boto3.client('dynamodb')
+ client = boto3.client("dynamodb")
# Create a crypto materials provider using the specified AWS KMS key.
aws_kms_cmp = AwsKmsCryptographicMaterialsProvider(key_id=aws_cmk_id)
# Create attribute actions that tells the encrypted client to encrypt all attributes except one.
actions = AttributeActions(
- default_action=CryptoAction.ENCRYPT_AND_SIGN,
- attribute_actions={
- 'leave me': CryptoAction.DO_NOTHING
- }
+ default_action=CryptoAction.ENCRYPT_AND_SIGN, attribute_actions={"leave me": CryptoAction.DO_NOTHING}
)
# Use these objects to create an encrypted client.
- encrypted_client = EncryptedClient(
- client=client,
- materials_provider=aws_kms_cmp,
- attribute_actions=actions
- )
+ encrypted_client = EncryptedClient(client=client, materials_provider=aws_kms_cmp, attribute_actions=actions)
# Put the item to the table, using the encrypted client to transparently encrypt it.
encrypted_client.put_item(TableName=table_name, Item=plaintext_item)
# Get the encrypted item using the standard client.
- encrypted_item = client.get_item(TableName=table_name, Key=index_key)['Item']
+ encrypted_item = client.get_item(TableName=table_name, Key=index_key)["Item"]
# Get the item using the encrypted client, transparently decyrpting it.
- decrypted_item = encrypted_client.get_item(TableName=table_name, Key=index_key)['Item']
+ decrypted_item = encrypted_client.get_item(TableName=table_name, Key=index_key)["Item"]
# Verify that all of the attributes are different in the encrypted item
for name in encrypted_attributes:
@@ -82,28 +73,16 @@ def encrypt_item(table_name, aws_cmk_id):
def encrypt_batch_items(table_name, aws_cmk_id):
"""Demonstrate use of EncryptedClient to transparently encrypt multiple items in a batch request."""
index_keys = [
- {
- 'partition_attribute': {'S': 'is this'},
- 'sort_attribute': {'N': '55'}
- },
- {
- 'partition_attribute': {'S': 'is this'},
- 'sort_attribute': {'N': '56'}
- },
- {
- 'partition_attribute': {'S': 'is this'},
- 'sort_attribute': {'N': '57'}
- },
- {
- 'partition_attribute': {'S': 'another'},
- 'sort_attribute': {'N': '55'}
- }
+ {"partition_attribute": {"S": "is this"}, "sort_attribute": {"N": "55"}},
+ {"partition_attribute": {"S": "is this"}, "sort_attribute": {"N": "56"}},
+ {"partition_attribute": {"S": "is this"}, "sort_attribute": {"N": "57"}},
+ {"partition_attribute": {"S": "another"}, "sort_attribute": {"N": "55"}},
]
plaintext_additional_attributes = {
- 'example': {'S': 'data'},
- 'some numbers': {'N': '99'},
- 'and some binary': {'B': b'\x00\x01\x02'},
- 'leave me': {'S': 'alone'} # We want to ignore this attribute
+ "example": {"S": "data"},
+ "some numbers": {"N": "99"},
+ "and some binary": {"B": b"\x00\x01\x02"},
+ "leave me": {"S": "alone"}, # We want to ignore this attribute
}
plaintext_items = []
for key in index_keys:
@@ -113,43 +92,34 @@ def encrypt_batch_items(table_name, aws_cmk_id):
# Collect all of the attributes that will be encrypted (used later).
encrypted_attributes = set(plaintext_additional_attributes.keys())
- encrypted_attributes.remove('leave me')
+ encrypted_attributes.remove("leave me")
# Collect all of the attributes that will not be encrypted (used later).
unencrypted_attributes = set(index_keys[0].keys())
- unencrypted_attributes.add('leave me')
+ unencrypted_attributes.add("leave me")
# Create a normal client.
- client = boto3.client('dynamodb')
+ client = boto3.client("dynamodb")
# Create a crypto materials provider using the specified AWS KMS key.
aws_kms_cmp = AwsKmsCryptographicMaterialsProvider(key_id=aws_cmk_id)
# Create attribute actions that tells the encrypted client to encrypt all attributes except one.
actions = AttributeActions(
- default_action=CryptoAction.ENCRYPT_AND_SIGN,
- attribute_actions={
- 'leave me': CryptoAction.DO_NOTHING
- }
+ default_action=CryptoAction.ENCRYPT_AND_SIGN, attribute_actions={"leave me": CryptoAction.DO_NOTHING}
)
# Use these objects to create an encrypted client.
- encrypted_client = EncryptedClient(
- client=client,
- materials_provider=aws_kms_cmp,
- attribute_actions=actions
- )
+ encrypted_client = EncryptedClient(client=client, materials_provider=aws_kms_cmp, attribute_actions=actions)
# Put the items to the table, using the encrypted client to transparently encrypt them.
- encrypted_client.batch_write_item(RequestItems={
- table_name: [{'PutRequest': {'Item': item}} for item in plaintext_items]
- })
+ encrypted_client.batch_write_item(
+ RequestItems={table_name: [{"PutRequest": {"Item": item}} for item in plaintext_items]}
+ )
# Get the encrypted item using the standard client.
- encrypted_items = client.batch_get_item(
- RequestItems={table_name: {'Keys': index_keys}}
- )['Responses'][table_name]
+ encrypted_items = client.batch_get_item(RequestItems={table_name: {"Keys": index_keys}})["Responses"][table_name]
# Get the item using the encrypted client, transparently decyrpting it.
- decrypted_items = encrypted_client.batch_get_item(
- RequestItems={table_name: {'Keys': index_keys}}
- )['Responses'][table_name]
+ decrypted_items = encrypted_client.batch_get_item(RequestItems={table_name: {"Keys": index_keys}})["Responses"][
+ table_name
+ ]
def _select_index_from_item(item):
"""Find the index keys that match this item."""
@@ -178,6 +148,6 @@ def _select_item_from_index(index, all_items):
assert decrypted_item[name] == encrypted_item[name] == plaintext_item[name]
# Clean up the item
- encrypted_client.batch_write_item(RequestItems={
- table_name: [{'DeleteRequest': {'Key': key}} for key in index_keys]
- })
+ encrypted_client.batch_write_item(
+ RequestItems={table_name: [{"DeleteRequest": {"Key": key}} for key in index_keys]}
+ )
diff --git a/examples/src/aws_kms_encrypted_item.py b/examples/src/aws_kms_encrypted_item.py
index dd4eef4d..8527d3f2 100644
--- a/examples/src/aws_kms_encrypted_item.py
+++ b/examples/src/aws_kms_encrypted_item.py
@@ -13,6 +13,7 @@
"""Example showing use of AWS KMS CMP with item encryption functions directly."""
import boto3
from boto3.dynamodb.types import Binary
+
from dynamodb_encryption_sdk.encrypted import CryptoConfig
from dynamodb_encryption_sdk.encrypted.item import decrypt_python_item, encrypt_python_item
from dynamodb_encryption_sdk.identifiers import CryptoAction
@@ -23,27 +24,24 @@
def encrypt_item(table_name, aws_cmk_id):
"""Demonstrate use of EncryptedTable to transparently encrypt an item."""
- index_key = {
- 'partition_attribute': 'is this',
- 'sort_attribute': 55
- }
+ index_key = {"partition_attribute": "is this", "sort_attribute": 55}
plaintext_item = {
- 'example': 'data',
- 'some numbers': 99,
- 'and some binary': Binary(b'\x00\x01\x02'),
- 'leave me': 'alone' # We want to ignore this attribute
+ "example": "data",
+ "some numbers": 99,
+ "and some binary": Binary(b"\x00\x01\x02"),
+ "leave me": "alone", # We want to ignore this attribute
}
# Collect all of the attributes that will be encrypted (used later).
encrypted_attributes = set(plaintext_item.keys())
- encrypted_attributes.remove('leave me')
+ encrypted_attributes.remove("leave me")
# Collect all of the attributes that will not be encrypted (used later).
unencrypted_attributes = set(index_key.keys())
- unencrypted_attributes.add('leave me')
+ unencrypted_attributes.add("leave me")
# Add the index pairs to the item.
plaintext_item.update(index_key)
# Create a normal table resource.
- table = boto3.resource('dynamodb').Table(table_name)
+ table = boto3.resource("dynamodb").Table(table_name)
# Use the TableInfo helper to collect information about the indexes.
table_info = TableInfo(name=table_name)
@@ -60,24 +58,21 @@ def encrypt_item(table_name, aws_cmk_id):
# are the primary index attributes.
# These attributes need to be in the form of a DynamoDB JSON structure, so first
# convert the standard dictionary.
- attributes=dict_to_ddb(index_key)
+ attributes=dict_to_ddb(index_key),
)
# Create attribute actions that tells the encrypted table to encrypt all attributes,
# only sign the primary index attributes, and ignore the one identified attribute to
# ignore.
actions = AttributeActions(
- default_action=CryptoAction.ENCRYPT_AND_SIGN,
- attribute_actions={'leave me': CryptoAction.DO_NOTHING}
+ default_action=CryptoAction.ENCRYPT_AND_SIGN, attribute_actions={"leave me": CryptoAction.DO_NOTHING}
)
actions.set_index_keys(*table_info.protected_index_keys())
# Build the crypto config to use for this item.
# When using the higher-level helpers, this is handled for you.
crypto_config = CryptoConfig(
- materials_provider=aws_kms_cmp,
- encryption_context=encryption_context,
- attribute_actions=actions
+ materials_provider=aws_kms_cmp, encryption_context=encryption_context, attribute_actions=actions
)
# Encrypt the plaintext item directly
diff --git a/examples/src/aws_kms_encrypted_resource.py b/examples/src/aws_kms_encrypted_resource.py
index 42f20460..1fcb3336 100644
--- a/examples/src/aws_kms_encrypted_resource.py
+++ b/examples/src/aws_kms_encrypted_resource.py
@@ -13,6 +13,7 @@
"""Example showing use of AWS KMS CMP with EncryptedResource."""
import boto3
from boto3.dynamodb.types import Binary
+
from dynamodb_encryption_sdk.encrypted.resource import EncryptedResource
from dynamodb_encryption_sdk.identifiers import CryptoAction
from dynamodb_encryption_sdk.material_providers.aws_kms import AwsKmsCryptographicMaterialsProvider
@@ -22,28 +23,16 @@
def encrypt_batch_items(table_name, aws_cmk_id):
"""Demonstrate use of EncryptedResource to transparently encrypt multiple items in a batch request."""
index_keys = [
- {
- 'partition_attribute': 'is this',
- 'sort_attribute': 55
- },
- {
- 'partition_attribute': 'is this',
- 'sort_attribute': 56
- },
- {
- 'partition_attribute': 'is this',
- 'sort_attribute': 57
- },
- {
- 'partition_attribute': 'another',
- 'sort_attribute': 55
- }
+ {"partition_attribute": "is this", "sort_attribute": 55},
+ {"partition_attribute": "is this", "sort_attribute": 56},
+ {"partition_attribute": "is this", "sort_attribute": 57},
+ {"partition_attribute": "another", "sort_attribute": 55},
]
plaintext_additional_attributes = {
- 'example': 'data',
- 'some numbers': 99,
- 'and some binary': Binary(b'\x00\x01\x02'),
- 'leave me': 'alone' # We want to ignore this attribute
+ "example": "data",
+ "some numbers": 99,
+ "and some binary": Binary(b"\x00\x01\x02"),
+ "leave me": "alone", # We want to ignore this attribute
}
plaintext_items = []
for key in index_keys:
@@ -53,43 +42,34 @@ def encrypt_batch_items(table_name, aws_cmk_id):
# Collect all of the attributes that will be encrypted (used later).
encrypted_attributes = set(plaintext_additional_attributes.keys())
- encrypted_attributes.remove('leave me')
+ encrypted_attributes.remove("leave me")
# Collect all of the attributes that will not be encrypted (used later).
unencrypted_attributes = set(index_keys[0].keys())
- unencrypted_attributes.add('leave me')
+ unencrypted_attributes.add("leave me")
# Create a normal service resource.
- resource = boto3.resource('dynamodb')
+ resource = boto3.resource("dynamodb")
# Create a crypto materials provider using the specified AWS KMS key.
aws_kms_cmp = AwsKmsCryptographicMaterialsProvider(key_id=aws_cmk_id)
# Create attribute actions that tells the encrypted resource to encrypt all attributes except one.
actions = AttributeActions(
- default_action=CryptoAction.ENCRYPT_AND_SIGN,
- attribute_actions={
- 'leave me': CryptoAction.DO_NOTHING
- }
+ default_action=CryptoAction.ENCRYPT_AND_SIGN, attribute_actions={"leave me": CryptoAction.DO_NOTHING}
)
# Use these objects to create an encrypted service resource.
- encrypted_resource = EncryptedResource(
- resource=resource,
- materials_provider=aws_kms_cmp,
- attribute_actions=actions
- )
+ encrypted_resource = EncryptedResource(resource=resource, materials_provider=aws_kms_cmp, attribute_actions=actions)
# Put the items to the table, using the encrypted service resource to transparently encrypt them.
- encrypted_resource.batch_write_item(RequestItems={
- table_name: [{'PutRequest': {'Item': item}} for item in plaintext_items]
- })
+ encrypted_resource.batch_write_item(
+ RequestItems={table_name: [{"PutRequest": {"Item": item}} for item in plaintext_items]}
+ )
# Get the encrypted item using the standard service resource.
- encrypted_items = resource.batch_get_item(
- RequestItems={table_name: {'Keys': index_keys}}
- )['Responses'][table_name]
+ encrypted_items = resource.batch_get_item(RequestItems={table_name: {"Keys": index_keys}})["Responses"][table_name]
# Get the item using the encrypted service resource, transparently decyrpting it.
- decrypted_items = encrypted_resource.batch_get_item(
- RequestItems={table_name: {'Keys': index_keys}}
- )['Responses'][table_name]
+ decrypted_items = encrypted_resource.batch_get_item(RequestItems={table_name: {"Keys": index_keys}})["Responses"][
+ table_name
+ ]
def _select_index_from_item(item):
"""Find the index keys that match this item."""
@@ -118,6 +98,6 @@ def _select_item_from_index(index, all_items):
assert decrypted_item[name] == encrypted_item[name] == plaintext_item[name]
# Clean up the item
- encrypted_resource.batch_write_item(RequestItems={
- table_name: [{'DeleteRequest': {'Key': key}} for key in index_keys]
- })
+ encrypted_resource.batch_write_item(
+ RequestItems={table_name: [{"DeleteRequest": {"Key": key}} for key in index_keys]}
+ )
diff --git a/examples/src/aws_kms_encrypted_table.py b/examples/src/aws_kms_encrypted_table.py
index 9607a258..f781f64c 100644
--- a/examples/src/aws_kms_encrypted_table.py
+++ b/examples/src/aws_kms_encrypted_table.py
@@ -13,6 +13,7 @@
"""Example showing use of AWS KMS CMP with EncryptedTable."""
import boto3
from boto3.dynamodb.types import Binary
+
from dynamodb_encryption_sdk.encrypted.table import EncryptedTable
from dynamodb_encryption_sdk.identifiers import CryptoAction
from dynamodb_encryption_sdk.material_providers.aws_kms import AwsKmsCryptographicMaterialsProvider
@@ -21,51 +22,41 @@
def encrypt_item(table_name, aws_cmk_id):
"""Demonstrate use of EncryptedTable to transparently encrypt an item."""
- index_key = {
- 'partition_attribute': 'is this',
- 'sort_attribute': 55
- }
+ index_key = {"partition_attribute": "is this", "sort_attribute": 55}
plaintext_item = {
- 'example': 'data',
- 'some numbers': 99,
- 'and some binary': Binary(b'\x00\x01\x02'),
- 'leave me': 'alone' # We want to ignore this attribute
+ "example": "data",
+ "some numbers": 99,
+ "and some binary": Binary(b"\x00\x01\x02"),
+ "leave me": "alone", # We want to ignore this attribute
}
# Collect all of the attributes that will be encrypted (used later).
encrypted_attributes = set(plaintext_item.keys())
- encrypted_attributes.remove('leave me')
+ encrypted_attributes.remove("leave me")
# Collect all of the attributes that will not be encrypted (used later).
unencrypted_attributes = set(index_key.keys())
- unencrypted_attributes.add('leave me')
+ unencrypted_attributes.add("leave me")
# Add the index pairs to the item.
plaintext_item.update(index_key)
# Create a normal table resource.
- table = boto3.resource('dynamodb').Table(table_name)
+ table = boto3.resource("dynamodb").Table(table_name)
# Create a crypto materials provider using the specified AWS KMS key.
aws_kms_cmp = AwsKmsCryptographicMaterialsProvider(key_id=aws_cmk_id)
# Create attribute actions that tells the encrypted table to encrypt all attributes except one.
actions = AttributeActions(
- default_action=CryptoAction.ENCRYPT_AND_SIGN,
- attribute_actions={
- 'leave me': CryptoAction.DO_NOTHING
- }
+ default_action=CryptoAction.ENCRYPT_AND_SIGN, attribute_actions={"leave me": CryptoAction.DO_NOTHING}
)
# Use these objects to create an encrypted table resource.
- encrypted_table = EncryptedTable(
- table=table,
- materials_provider=aws_kms_cmp,
- attribute_actions=actions
- )
+ encrypted_table = EncryptedTable(table=table, materials_provider=aws_kms_cmp, attribute_actions=actions)
# Put the item to the table, using the encrypted table resource to transparently encrypt it.
encrypted_table.put_item(Item=plaintext_item)
# Get the encrypted item using the standard table resource.
- encrypted_item = table.get_item(Key=index_key)['Item']
+ encrypted_item = table.get_item(Key=index_key)["Item"]
# Get the item using the encrypted table resource, transparently decyrpting it.
- decrypted_item = encrypted_table.get_item(Key=index_key)['Item']
+ decrypted_item = encrypted_table.get_item(Key=index_key)["Item"]
# Verify that all of the attributes are different in the encrypted item
for name in encrypted_attributes:
diff --git a/examples/src/most_recent_provider_encrypted_table.py b/examples/src/most_recent_provider_encrypted_table.py
index c75bb405..81e0cc73 100644
--- a/examples/src/most_recent_provider_encrypted_table.py
+++ b/examples/src/most_recent_provider_encrypted_table.py
@@ -15,6 +15,7 @@
"""
import boto3
from boto3.dynamodb.types import Binary
+
from dynamodb_encryption_sdk.encrypted.table import EncryptedTable
from dynamodb_encryption_sdk.identifiers import CryptoAction
from dynamodb_encryption_sdk.material_providers.aws_kms import AwsKmsCryptographicMaterialsProvider
@@ -25,64 +26,51 @@
def encrypt_item(table_name, aws_cmk_id, meta_table_name, material_name):
"""Demonstrate use of EncryptedTable to transparently encrypt an item."""
- index_key = {
- 'partition_attribute': 'is this',
- 'sort_attribute': 55
- }
+ index_key = {"partition_attribute": "is this", "sort_attribute": 55}
plaintext_item = {
- 'example': 'data',
- 'some numbers': 99,
- 'and some binary': Binary(b'\x00\x01\x02'),
- 'leave me': 'alone' # We want to ignore this attribute
+ "example": "data",
+ "some numbers": 99,
+ "and some binary": Binary(b"\x00\x01\x02"),
+ "leave me": "alone", # We want to ignore this attribute
}
# Collect all of the attributes that will be encrypted (used later).
encrypted_attributes = set(plaintext_item.keys())
- encrypted_attributes.remove('leave me')
+ encrypted_attributes.remove("leave me")
# Collect all of the attributes that will not be encrypted (used later).
unencrypted_attributes = set(index_key.keys())
- unencrypted_attributes.add('leave me')
+ unencrypted_attributes.add("leave me")
# Add the index pairs to the item.
plaintext_item.update(index_key)
# Create a normal table resource for the meta store.
- meta_table = boto3.resource('dynamodb').Table(meta_table_name)
+ meta_table = boto3.resource("dynamodb").Table(meta_table_name)
# Create a crypto materials provider for the meta store using the specified AWS KMS key.
aws_kms_cmp = AwsKmsCryptographicMaterialsProvider(key_id=aws_cmk_id)
# Create a meta store using the AWS KMS crypto materials provider.
- meta_store = MetaStore(
- table=meta_table,
- materials_provider=aws_kms_cmp
- )
+ meta_store = MetaStore(table=meta_table, materials_provider=aws_kms_cmp)
# Create a most recent provider using the meta store.
most_recent_cmp = MostRecentProvider(
provider_store=meta_store,
material_name=material_name,
- version_ttl=600.0 # Check for a new material version every five minutes.
+ version_ttl=600.0, # Check for a new material version every five minutes.
)
# Create a normal table resource.
- table = boto3.resource('dynamodb').Table(table_name)
+ table = boto3.resource("dynamodb").Table(table_name)
# Create attribute actions that tells the encrypted table to encrypt all attributes except one.
actions = AttributeActions(
- default_action=CryptoAction.ENCRYPT_AND_SIGN,
- attribute_actions={
- 'leave me': CryptoAction.DO_NOTHING
- }
+ default_action=CryptoAction.ENCRYPT_AND_SIGN, attribute_actions={"leave me": CryptoAction.DO_NOTHING}
)
# Use these objects to create an encrypted table resource.
- encrypted_table = EncryptedTable(
- table=table,
- materials_provider=most_recent_cmp,
- attribute_actions=actions
- )
+ encrypted_table = EncryptedTable(table=table, materials_provider=most_recent_cmp, attribute_actions=actions)
# Put the item to the table, using the encrypted table resource to transparently encrypt it.
encrypted_table.put_item(Item=plaintext_item)
# Get the encrypted item using the standard table resource.
- encrypted_item = table.get_item(Key=index_key)['Item']
+ encrypted_item = table.get_item(Key=index_key)["Item"]
# Get the item using the encrypted table resource, transparently decyrpting it.
- decrypted_item = encrypted_table.get_item(Key=index_key)['Item']
+ decrypted_item = encrypted_table.get_item(Key=index_key)["Item"]
# Verify that all of the attributes are different in the encrypted item
for name in encrypted_attributes:
diff --git a/examples/src/wrapped_rsa_encrypted_table.py b/examples/src/wrapped_rsa_encrypted_table.py
index 85816593..d6eed86f 100644
--- a/examples/src/wrapped_rsa_encrypted_table.py
+++ b/examples/src/wrapped_rsa_encrypted_table.py
@@ -13,6 +13,7 @@
"""Example showing use of a RSA wrapped CMP with EncryptedTable."""
import boto3
from boto3.dynamodb.types import Binary
+
from dynamodb_encryption_sdk.delegated_keys.jce import JceNameLocalDelegatedKey
from dynamodb_encryption_sdk.encrypted.table import EncryptedTable
from dynamodb_encryption_sdk.identifiers import CryptoAction, EncryptionKeyType, KeyEncodingType
@@ -22,69 +23,57 @@
def encrypt_item(table_name, rsa_wrapping_private_key_bytes, rsa_signing_private_key_bytes):
"""Demonstrate use of EncryptedTable to transparently encrypt an item."""
- index_key = {
- 'partition_attribute': 'is this',
- 'sort_attribute': 55
- }
+ index_key = {"partition_attribute": "is this", "sort_attribute": 55}
plaintext_item = {
- 'example': 'data',
- 'some numbers': 99,
- 'and some binary': Binary(b'\x00\x01\x02'),
- 'leave me': 'alone' # We want to ignore this attribute
+ "example": "data",
+ "some numbers": 99,
+ "and some binary": Binary(b"\x00\x01\x02"),
+ "leave me": "alone", # We want to ignore this attribute
}
# Collect all of the attributes that will be encrypted (used later).
encrypted_attributes = set(plaintext_item.keys())
- encrypted_attributes.remove('leave me')
+ encrypted_attributes.remove("leave me")
# Collect all of the attributes that will not be encrypted (used later).
unencrypted_attributes = set(index_key.keys())
- unencrypted_attributes.add('leave me')
+ unencrypted_attributes.add("leave me")
# Add the index pairs to the item.
plaintext_item.update(index_key)
# Create a normal table resource.
- table = boto3.resource('dynamodb').Table(table_name)
+ table = boto3.resource("dynamodb").Table(table_name)
# Create a crypto materials provider using the provided wrapping and signing keys.
# We show private keys used here, but public keys could be used as well, allowing
# only wrapping or signature verification.
wrapping_key = JceNameLocalDelegatedKey(
key=rsa_wrapping_private_key_bytes,
- algorithm='RSA',
+ algorithm="RSA",
key_type=EncryptionKeyType.PRIVATE,
- key_encoding=KeyEncodingType.DER
+ key_encoding=KeyEncodingType.DER,
)
signing_key = JceNameLocalDelegatedKey(
key=rsa_signing_private_key_bytes,
- algorithm='SHA512withRSA',
+ algorithm="SHA512withRSA",
key_type=EncryptionKeyType.PRIVATE,
- key_encoding=KeyEncodingType.DER
+ key_encoding=KeyEncodingType.DER,
)
wrapped_cmp = WrappedCryptographicMaterialsProvider(
- wrapping_key=wrapping_key,
- unwrapping_key=wrapping_key,
- signing_key=signing_key
+ wrapping_key=wrapping_key, unwrapping_key=wrapping_key, signing_key=signing_key
)
# Create attribute actions that tells the encrypted table to encrypt all attributes except one.
actions = AttributeActions(
- default_action=CryptoAction.ENCRYPT_AND_SIGN,
- attribute_actions={
- 'leave me': CryptoAction.DO_NOTHING
- }
+ default_action=CryptoAction.ENCRYPT_AND_SIGN, attribute_actions={"leave me": CryptoAction.DO_NOTHING}
)
# Use these objects to create an encrypted table resource.
- encrypted_table = EncryptedTable(
- table=table,
- materials_provider=wrapped_cmp,
- attribute_actions=actions
- )
+ encrypted_table = EncryptedTable(table=table, materials_provider=wrapped_cmp, attribute_actions=actions)
# Put the item to the table, using the encrypted table resource to transparently encrypt it.
encrypted_table.put_item(Item=plaintext_item)
# Get the encrypted item using the standard table resource.
- encrypted_item = table.get_item(Key=index_key)['Item']
+ encrypted_item = table.get_item(Key=index_key)["Item"]
# Get the item using the encrypted table resource, transparently decyrpting it.
- decrypted_item = encrypted_table.get_item(Key=index_key)['Item']
+ decrypted_item = encrypted_table.get_item(Key=index_key)["Item"]
# Verify that all of the attributes are different in the encrypted item
for name in encrypted_attributes:
diff --git a/examples/src/wrapped_symmetric_encrypted_table.py b/examples/src/wrapped_symmetric_encrypted_table.py
index 6295a630..22a65087 100644
--- a/examples/src/wrapped_symmetric_encrypted_table.py
+++ b/examples/src/wrapped_symmetric_encrypted_table.py
@@ -13,6 +13,7 @@
"""Example showing use of a symmetric wrapped CMP with EncryptedTable."""
import boto3
from boto3.dynamodb.types import Binary
+
from dynamodb_encryption_sdk.delegated_keys.jce import JceNameLocalDelegatedKey
from dynamodb_encryption_sdk.encrypted.table import EncryptedTable
from dynamodb_encryption_sdk.identifiers import CryptoAction, EncryptionKeyType, KeyEncodingType
@@ -22,67 +23,55 @@
def encrypt_item(table_name, aes_wrapping_key_bytes, hmac_signing_key_bytes):
"""Demonstrate use of EncryptedTable to transparently encrypt an item."""
- index_key = {
- 'partition_attribute': 'is this',
- 'sort_attribute': 55
- }
+ index_key = {"partition_attribute": "is this", "sort_attribute": 55}
plaintext_item = {
- 'example': 'data',
- 'some numbers': 99,
- 'and some binary': Binary(b'\x00\x01\x02'),
- 'leave me': 'alone' # We want to ignore this attribute
+ "example": "data",
+ "some numbers": 99,
+ "and some binary": Binary(b"\x00\x01\x02"),
+ "leave me": "alone", # We want to ignore this attribute
}
# Collect all of the attributes that will be encrypted (used later).
encrypted_attributes = set(plaintext_item.keys())
- encrypted_attributes.remove('leave me')
+ encrypted_attributes.remove("leave me")
# Collect all of the attributes that will not be encrypted (used later).
unencrypted_attributes = set(index_key.keys())
- unencrypted_attributes.add('leave me')
+ unencrypted_attributes.add("leave me")
# Add the index pairs to the item.
plaintext_item.update(index_key)
# Create a normal table resource.
- table = boto3.resource('dynamodb').Table(table_name)
+ table = boto3.resource("dynamodb").Table(table_name)
# Create a crypto materials provider using the provided wrapping and signing keys.
wrapping_key = JceNameLocalDelegatedKey(
key=aes_wrapping_key_bytes,
- algorithm='AES',
+ algorithm="AES",
key_type=EncryptionKeyType.SYMMETRIC,
- key_encoding=KeyEncodingType.RAW
+ key_encoding=KeyEncodingType.RAW,
)
signing_key = JceNameLocalDelegatedKey(
key=hmac_signing_key_bytes,
- algorithm='HmacSHA512',
+ algorithm="HmacSHA512",
key_type=EncryptionKeyType.SYMMETRIC,
- key_encoding=KeyEncodingType.RAW
+ key_encoding=KeyEncodingType.RAW,
)
wrapped_cmp = WrappedCryptographicMaterialsProvider(
- wrapping_key=wrapping_key,
- unwrapping_key=wrapping_key,
- signing_key=signing_key
+ wrapping_key=wrapping_key, unwrapping_key=wrapping_key, signing_key=signing_key
)
# Create attribute actions that tells the encrypted table to encrypt all attributes except one.
actions = AttributeActions(
- default_action=CryptoAction.ENCRYPT_AND_SIGN,
- attribute_actions={
- 'leave me': CryptoAction.DO_NOTHING
- }
+ default_action=CryptoAction.ENCRYPT_AND_SIGN, attribute_actions={"leave me": CryptoAction.DO_NOTHING}
)
# Use these objects to create an encrypted table resource.
- encrypted_table = EncryptedTable(
- table=table,
- materials_provider=wrapped_cmp,
- attribute_actions=actions
- )
+ encrypted_table = EncryptedTable(table=table, materials_provider=wrapped_cmp, attribute_actions=actions)
# Put the item to the table, using the encrypted table resource to transparently encrypt it.
encrypted_table.put_item(Item=plaintext_item)
# Get the encrypted item using the standard table resource.
- encrypted_item = table.get_item(Key=index_key)['Item']
+ encrypted_item = table.get_item(Key=index_key)["Item"]
# Get the item using the encrypted table resource, transparently decyrpting it.
- decrypted_item = encrypted_table.get_item(Key=index_key)['Item']
+ decrypted_item = encrypted_table.get_item(Key=index_key)["Item"]
# Verify that all of the attributes are different in the encrypted item
for name in encrypted_attributes:
diff --git a/examples/test/test_aws_kms_encrypted_examples.py b/examples/test/test_aws_kms_encrypted_examples.py
index 3427a592..8b8b5551 100644
--- a/examples/test/test_aws_kms_encrypted_examples.py
+++ b/examples/test/test_aws_kms_encrypted_examples.py
@@ -13,10 +13,13 @@
"""Test ``aws_kms_encrypted_*`` examples."""
import os
import sys
-sys.path.extend([ # noqa
- os.sep.join([os.path.dirname(__file__), '..', '..', 'test', 'integration']),
- os.sep.join([os.path.dirname(__file__), '..', 'src'])
-])
+
+sys.path.extend(
+ [ # noqa
+ os.sep.join([os.path.dirname(__file__), "..", "..", "test", "integration"]),
+ os.sep.join([os.path.dirname(__file__), "..", "src"]),
+ ]
+)
import pytest
diff --git a/examples/test/test_most_recent_provider_encrypted_examples.py b/examples/test/test_most_recent_provider_encrypted_examples.py
index 5427f1ee..7db4160b 100644
--- a/examples/test/test_most_recent_provider_encrypted_examples.py
+++ b/examples/test/test_most_recent_provider_encrypted_examples.py
@@ -13,10 +13,13 @@
"""Test most recent provider examples."""
import os
import sys
-sys.path.extend([ # noqa
- os.sep.join([os.path.dirname(__file__), '..', '..', 'test', 'integration']),
- os.sep.join([os.path.dirname(__file__), '..', 'src'])
-])
+
+sys.path.extend(
+ [ # noqa
+ os.sep.join([os.path.dirname(__file__), "..", "..", "test", "integration"]),
+ os.sep.join([os.path.dirname(__file__), "..", "src"]),
+ ]
+)
import uuid
import boto3
@@ -31,13 +34,13 @@
def test_most_recent_encrypted_table(ddb_table_name, cmk_arn):
# define random new names for material and metastore table
- meta_table_name = 'meta-table-{}'.format(uuid.uuid4())
- material_name = 'material-{}'.format(uuid.uuid4())
+ meta_table_name = "meta-table-{}".format(uuid.uuid4())
+ material_name = "material-{}".format(uuid.uuid4())
# create the metastore table
- client = boto3.client('dynamodb')
+ client = boto3.client("dynamodb")
MetaStore.create_table(client, meta_table_name, 10, 10)
- waiter = client.get_waiter('table_exists')
+ waiter = client.get_waiter("table_exists")
waiter.wait(TableName=meta_table_name)
# run the actual test
@@ -45,5 +48,5 @@ def test_most_recent_encrypted_table(ddb_table_name, cmk_arn):
# clean up the meta store table
client.delete_table(TableName=meta_table_name)
- waiter = client.get_waiter('table_not_exists')
+ waiter = client.get_waiter("table_not_exists")
waiter.wait(TableName=meta_table_name)
diff --git a/examples/test/test_wrapped_encrypted_examples.py b/examples/test/test_wrapped_encrypted_examples.py
index 9988e819..fc69f186 100644
--- a/examples/test/test_wrapped_encrypted_examples.py
+++ b/examples/test/test_wrapped_encrypted_examples.py
@@ -13,10 +13,13 @@
"""Test ``wrapped_*_encrypted_*`` examples."""
import os
import sys
-sys.path.extend([ # noqa
- os.sep.join([os.path.dirname(__file__), '..', '..', 'test', 'integration']),
- os.sep.join([os.path.dirname(__file__), '..', 'src'])
-])
+
+sys.path.extend(
+ [ # noqa
+ os.sep.join([os.path.dirname(__file__), "..", "..", "test", "integration"]),
+ os.sep.join([os.path.dirname(__file__), "..", "src"]),
+ ]
+)
import pytest
@@ -29,12 +32,12 @@
def test_wrapped_rsa_encrypted_table(ddb_table_name):
- wrapping_key_bytes = JceNameLocalDelegatedKey.generate('RSA', 4096).key
- signing_key_bytes = JceNameLocalDelegatedKey.generate('SHA512withRSA', 4096).key
+ wrapping_key_bytes = JceNameLocalDelegatedKey.generate("RSA", 4096).key
+ signing_key_bytes = JceNameLocalDelegatedKey.generate("SHA512withRSA", 4096).key
wrapped_rsa_encrypted_table.encrypt_item(ddb_table_name, wrapping_key_bytes, signing_key_bytes)
def test_wrapped_symmetric_encrypted_table(ddb_table_name):
- wrapping_key_bytes = JceNameLocalDelegatedKey.generate('AES', 256).key
- signing_key_bytes = JceNameLocalDelegatedKey.generate('HmacSHA512', 256).key
+ wrapping_key_bytes = JceNameLocalDelegatedKey.generate("AES", 256).key
+ signing_key_bytes = JceNameLocalDelegatedKey.generate("HmacSHA512", 256).key
wrapped_symmetric_encrypted_table.encrypt_item(ddb_table_name, wrapping_key_bytes, signing_key_bytes)
diff --git a/setup.cfg b/setup.cfg
index 4e518fd4..0a82e619 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -42,9 +42,24 @@ ignore =
# Ignoring D401 pending discussion of imperative mood
D401,
# Ignoring D202 (no blank lines after function docstring) because mypy confuses flake8
- D202
+ D202,
+ # E203 is not PEP8 compliant https://github.com/ambv/black#slices
+ E203,
+ # W503 is not PEP8 compliant https://github.com/ambv/black#line-breaks--binary-operators
+ W503
# Doc8 Configuration
[doc8]
max-line-length = 120
+
+[isort]
+line_length = 120
+# https://github.com/timothycrosley/isort#multi-line-output-modes
+multi_line_output = 3
+include_trailing_comma = True
+force_grid_wrap = 0
+combine_as_imports = True
+not_skip = __init__.py
+known_first_party = dynamodb_encryption_sdk
+known_third_party =attr,aws_kms_encrypted_client,aws_kms_encrypted_item,aws_kms_encrypted_resource,aws_kms_encrypted_table,boto3,botocore,cryptography,dynamodb_encryption_sdk,functional_test_utils,functional_test_vector_generators,hypothesis,hypothesis_strategies,integration_test_utils,mock,most_recent_provider_encrypted_table,moto,mypy_extensions,pytest,pytest_mock,setuptools,six,wrapped_rsa_encrypted_table,wrapped_symmetric_encrypted_table
diff --git a/setup.py b/setup.py
index 0a331375..a1c79400 100644
--- a/setup.py
+++ b/setup.py
@@ -5,62 +5,57 @@
from setuptools import find_packages, setup
-VERSION_RE = re.compile(r'''__version__ = ['"]([0-9.]+)['"]''')
+VERSION_RE = re.compile(r"""__version__ = ['"]([0-9.]+)['"]""")
HERE = os.path.abspath(os.path.dirname(__file__))
def read(*args):
"""Reads complete file contents."""
- return io.open(os.path.join(HERE, *args), encoding='utf-8').read()
+ return io.open(os.path.join(HERE, *args), encoding="utf-8").read()
def get_version():
"""Reads the version from this module."""
- init = read('src', 'dynamodb_encryption_sdk', 'identifiers.py')
+ init = read("src", "dynamodb_encryption_sdk", "identifiers.py")
return VERSION_RE.search(init).group(1)
def get_requirements():
"""Reads the requirements file."""
- requirements = read('requirements.txt')
+ requirements = read("requirements.txt")
return [r for r in requirements.strip().splitlines()]
setup(
- name='dynamodb-encryption-sdk',
+ name="dynamodb-encryption-sdk",
version=get_version(),
- packages=find_packages('src'),
- package_dir={'': 'src'},
- url='https://github.com/aws/aws-dynamodb-encryption-python',
- author='Amazon Web Services',
- author_email='aws-cryptools@amazon.com',
- maintainer='Amazon Web Services',
- description='DynamoDB Encryption Client for Python',
- long_description=read('README.rst'),
- keywords='dynamodb-encryption-sdk aws kms encryption dynamodb',
- data_files=[
- 'README.rst',
- 'CHANGELOG.rst',
- 'LICENSE',
- 'requirements.txt'
- ],
- license='Apache License 2.0',
+ packages=find_packages("src"),
+ package_dir={"": "src"},
+ url="https://github.com/aws/aws-dynamodb-encryption-python",
+ author="Amazon Web Services",
+ author_email="aws-cryptools@amazon.com",
+ maintainer="Amazon Web Services",
+ description="DynamoDB Encryption Client for Python",
+ long_description=read("README.rst"),
+ keywords="dynamodb-encryption-sdk aws kms encryption dynamodb",
+ data_files=["README.rst", "CHANGELOG.rst", "LICENSE", "requirements.txt"],
+ license="Apache License 2.0",
install_requires=get_requirements(),
classifiers=[
- 'Development Status :: 5 - Production/Stable',
- 'Intended Audience :: Developers',
- 'Natural Language :: English',
- 'License :: OSI Approved :: Apache Software License',
- 'Programming Language :: Python',
- 'Programming Language :: Python :: 2',
- 'Programming Language :: Python :: 2.7',
- 'Programming Language :: Python :: 3',
- 'Programming Language :: Python :: 3.4',
- 'Programming Language :: Python :: 3.5',
- 'Programming Language :: Python :: 3.6',
- 'Programming Language :: Python :: 3.7',
- 'Programming Language :: Python :: Implementation :: CPython',
- 'Topic :: Security',
- 'Topic :: Security :: Cryptography'
- ]
+ "Development Status :: 5 - Production/Stable",
+ "Intended Audience :: Developers",
+ "Natural Language :: English",
+ "License :: OSI Approved :: Apache Software License",
+ "Programming Language :: Python",
+ "Programming Language :: Python :: 2",
+ "Programming Language :: Python :: 2.7",
+ "Programming Language :: Python :: 3",
+ "Programming Language :: Python :: 3.4",
+ "Programming Language :: Python :: 3.5",
+ "Programming Language :: Python :: 3.6",
+ "Programming Language :: Python :: 3.7",
+ "Programming Language :: Python :: Implementation :: CPython",
+ "Topic :: Security",
+ "Topic :: Security :: Cryptography",
+ ],
)
diff --git a/src/dynamodb_encryption_sdk/__init__.py b/src/dynamodb_encryption_sdk/__init__.py
index 2b66fba4..7b5dba80 100644
--- a/src/dynamodb_encryption_sdk/__init__.py
+++ b/src/dynamodb_encryption_sdk/__init__.py
@@ -13,20 +13,22 @@
"""DynamoDB Encryption Client."""
from dynamodb_encryption_sdk.encrypted.client import EncryptedClient
from dynamodb_encryption_sdk.encrypted.item import (
- decrypt_dynamodb_item, decrypt_python_item,
- encrypt_dynamodb_item, encrypt_python_item
+ decrypt_dynamodb_item,
+ decrypt_python_item,
+ encrypt_dynamodb_item,
+ encrypt_python_item,
)
from dynamodb_encryption_sdk.encrypted.resource import EncryptedResource
from dynamodb_encryption_sdk.encrypted.table import EncryptedTable
from dynamodb_encryption_sdk.identifiers import __version__
-# TableConfiguration
-# MaterialDescription
-# ItemConfiguration
-
__all__ = (
- 'decrypt_dynamodb_item', 'decrypt_python_item',
- 'encrypt_dynamodb_item', 'encrypt_python_item',
- 'EncryptedClient', 'EncryptedResource', 'EncryptedTable',
- '__version__'
+ "decrypt_dynamodb_item",
+ "decrypt_python_item",
+ "encrypt_dynamodb_item",
+ "encrypt_python_item",
+ "EncryptedClient",
+ "EncryptedResource",
+ "EncryptedTable",
+ "__version__",
)
diff --git a/src/dynamodb_encryption_sdk/delegated_keys/__init__.py b/src/dynamodb_encryption_sdk/delegated_keys/__init__.py
index 35542ef8..b41caeee 100644
--- a/src/dynamodb_encryption_sdk/delegated_keys/__init__.py
+++ b/src/dynamodb_encryption_sdk/delegated_keys/__init__.py
@@ -12,17 +12,19 @@
# language governing permissions and limitations under the License.
"""Delegated keys."""
import abc
+
+import six
+
+from dynamodb_encryption_sdk.identifiers import EncryptionKeyType # noqa pylint: disable=unused-import
+
try: # Python 3.5.0 and 3.5.1 have incompatible typing modules
from typing import Dict, Optional, Text # noqa pylint: disable=unused-import
except ImportError: # pragma: no cover
# We only actually need these imports when running the mypy checks
pass
-import six
-
-from dynamodb_encryption_sdk.identifiers import EncryptionKeyType # noqa pylint: disable=unused-import
-__all__ = ('DelegatedKey',)
+__all__ = ("DelegatedKey",)
def _raise_not_implemented(method_name):
@@ -70,7 +72,7 @@ def generate(cls, algorithm, key_length): # type: ignore
:returns: Generated delegated key
:rtype: DelegatedKey
"""
- _raise_not_implemented('generate')
+ _raise_not_implemented("generate")
def encrypt(self, algorithm, name, plaintext, additional_associated_data=None): # type: ignore
# type: (Text, Text, bytes, Optional[Dict[Text, Text]]) -> bytes
@@ -85,7 +87,7 @@ def encrypt(self, algorithm, name, plaintext, additional_associated_data=None):
:returns: Encrypted ciphertext
:rtype: bytes
"""
- _raise_not_implemented('encrypt')
+ _raise_not_implemented("encrypt")
def decrypt(self, algorithm, name, ciphertext, additional_associated_data=None): # type: ignore
# type: (Text, Text, bytes, Optional[Dict[Text, Text]]) -> bytes
@@ -100,7 +102,7 @@ def decrypt(self, algorithm, name, ciphertext, additional_associated_data=None):
:returns: Decrypted plaintext
:rtype: bytes
"""
- _raise_not_implemented('decrypt')
+ _raise_not_implemented("decrypt")
def wrap(self, algorithm, content_key, additional_associated_data=None): # type: ignore
# type: (Text, bytes, Optional[Dict[Text, Text]]) -> bytes
@@ -114,15 +116,10 @@ def wrap(self, algorithm, content_key, additional_associated_data=None): # type
:returns: Wrapped key
:rtype: bytes
"""
- _raise_not_implemented('wrap')
+ _raise_not_implemented("wrap")
def unwrap( # type: ignore
- self,
- algorithm,
- wrapped_key,
- wrapped_key_algorithm,
- wrapped_key_type,
- additional_associated_data=None
+ self, algorithm, wrapped_key, wrapped_key_algorithm, wrapped_key_type, additional_associated_data=None
):
# type: (Text, bytes, Text, EncryptionKeyType, Optional[Dict[Text, Text]]) -> DelegatedKey
# pylint: disable=unused-argument,no-self-use
@@ -137,7 +134,7 @@ def unwrap( # type: ignore
:returns: Delegated key using unwrapped key
:rtype: DelegatedKey
"""
- _raise_not_implemented('unwrap')
+ _raise_not_implemented("unwrap")
def sign(self, algorithm, data): # type: ignore
# type: (Text, bytes) -> bytes
@@ -149,7 +146,7 @@ def sign(self, algorithm, data): # type: ignore
:returns: Signature value
:rtype: bytes
"""
- _raise_not_implemented('sign')
+ _raise_not_implemented("sign")
def verify(self, algorithm, signature, data): # type: ignore
# type: (Text, bytes, bytes) -> None
@@ -160,7 +157,7 @@ def verify(self, algorithm, signature, data): # type: ignore
:param bytes signature: Signature to verify
:param bytes data: Data over which to verify signature
"""
- _raise_not_implemented('verify')
+ _raise_not_implemented("verify")
def signing_algorithm(self): # type: ignore
# type: () -> Text
@@ -173,4 +170,4 @@ def signing_algorithm(self): # type: ignore
:returns: Signing algorithm identifier
:rtype: str
"""
- _raise_not_implemented('signing_algorithm')
+ _raise_not_implemented("signing_algorithm")
diff --git a/src/dynamodb_encryption_sdk/delegated_keys/jce.py b/src/dynamodb_encryption_sdk/delegated_keys/jce.py
index 54ad38ce..4edc6b2c 100644
--- a/src/dynamodb_encryption_sdk/delegated_keys/jce.py
+++ b/src/dynamodb_encryption_sdk/delegated_keys/jce.py
@@ -17,10 +17,16 @@
import os
import attr
+import six
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import rsa
-import six
+
+from dynamodb_encryption_sdk.exceptions import JceTransformationError, UnwrappingError
+from dynamodb_encryption_sdk.identifiers import LOGGER_NAME, EncryptionKeyType, KeyEncodingType
+from dynamodb_encryption_sdk.internal.crypto.jce_bridge import authentication, encryption, primitives
+
+from . import DelegatedKey
try: # Python 3.5.0 and 3.5.1 have incompatible typing modules
from typing import Dict, Optional, Text # noqa pylint: disable=unused-import
@@ -28,12 +34,8 @@
# We only actually need these imports when running the mypy checks
pass
-from dynamodb_encryption_sdk.exceptions import JceTransformationError, UnwrappingError
-from dynamodb_encryption_sdk.identifiers import EncryptionKeyType, KeyEncodingType, LOGGER_NAME
-from dynamodb_encryption_sdk.internal.crypto.jce_bridge import authentication, encryption, primitives
-from . import DelegatedKey
-__all__ = ('JceNameLocalDelegatedKey',)
+__all__ = ("JceNameLocalDelegatedKey",)
_LOGGER = logging.getLogger(LOGGER_NAME)
@@ -54,23 +56,16 @@ def _generate_rsa_key(key_length):
:returns: DER-encoded private key, private key identifier, and DER encoding identifier
:rtype: tuple(bytes, :class:`EncryptionKeyType`, :class:`KeyEncodingType`)
"""
- private_key = rsa.generate_private_key(
- public_exponent=65537,
- key_size=key_length,
- backend=default_backend()
- )
+ private_key = rsa.generate_private_key(public_exponent=65537, key_size=key_length, backend=default_backend())
key_bytes = private_key.private_bytes(
encoding=serialization.Encoding.DER,
format=serialization.PrivateFormat.PKCS8,
- encryption_algorithm=serialization.NoEncryption()
+ encryption_algorithm=serialization.NoEncryption(),
)
return key_bytes, EncryptionKeyType.PRIVATE, KeyEncodingType.DER
-_ALGORITHM_GENERATE_MAP = {
- 'SYMMETRIC': _generate_symmetric_key,
- 'RSA': _generate_rsa_key
-}
+_ALGORITHM_GENERATE_MAP = {"SYMMETRIC": _generate_symmetric_key, "RSA": _generate_rsa_key}
@attr.s(init=False)
@@ -119,11 +114,11 @@ class JceNameLocalDelegatedKey(DelegatedKey):
_key_encoding = attr.ib(validator=attr.validators.instance_of(KeyEncodingType))
def __init__(
- self,
- key, # type: bytes
- algorithm, # type: Text
- key_type, # type: EncryptionKeyType
- key_encoding, # type: KeyEncodingType
+ self,
+ key, # type: bytes
+ algorithm, # type: Text
+ key_type, # type: EncryptionKeyType
+ key_encoding, # type: KeyEncodingType
): # noqa=D107
# type: (...) -> None
# Workaround pending resolution of attrs/mypy interaction.
@@ -172,9 +167,7 @@ def __attrs_post_init__(self):
pass
else:
self.__key = key_transformer.load_key( # attrs confuses pylint: disable=attribute-defined-outside-init
- self.key,
- self._key_type,
- self._key_encoding
+ self.key, self._key_type, self._key_encoding
)
self._enable_encryption()
self._enable_wrap()
@@ -189,9 +182,7 @@ def __attrs_post_init__(self):
pass
else:
self.__key = key_transformer.load_key( # attrs confuses pylint: disable=attribute-defined-outside-init
- self.key,
- self._key_type,
- self._key_encoding
+ self.key, self._key_type, self._key_encoding
)
self._enable_authentication()
return
@@ -211,15 +202,15 @@ def generate(cls, algorithm, key_length=None):
"""
# Normalize to allow generating both encryption and signing keys
algorithm_lookup = algorithm.upper()
- if 'HMAC' in algorithm_lookup or algorithm_lookup in ('AES', 'AESWRAP'):
- algorithm_lookup = 'SYMMETRIC'
- elif 'RSA' in algorithm_lookup:
- algorithm_lookup = 'RSA'
+ if "HMAC" in algorithm_lookup or algorithm_lookup in ("AES", "AESWRAP"):
+ algorithm_lookup = "SYMMETRIC"
+ elif "RSA" in algorithm_lookup:
+ algorithm_lookup = "RSA"
try:
key_generator = _ALGORITHM_GENERATE_MAP[algorithm_lookup]
except KeyError:
- raise ValueError('Unknown algorithm: {}'.format(algorithm))
+ raise ValueError("Unknown algorithm: {}".format(algorithm))
key, key_type, key_encoding = key_generator(key_length)
return cls(key=key, algorithm=algorithm, key_type=key_type, key_encoding=key_encoding)
@@ -233,7 +224,7 @@ def allowed_for_raw_materials(self):
:returns: decision
:rtype: bool
"""
- return self.algorithm == 'AES'
+ return self.algorithm == "AES"
def _encrypt(self, algorithm, name, plaintext, additional_associated_data=None):
# type: (Text, Text, bytes, Optional[Dict[Text, Text]]) -> bytes
@@ -281,10 +272,7 @@ def _wrap(self, algorithm, content_key, additional_associated_data=None):
:rtype: bytes
"""
wrapper = encryption.JavaCipher.from_transformation(algorithm)
- return wrapper.wrap(
- wrapping_key=self.__key,
- key_to_wrap=content_key
- )
+ return wrapper.wrap(wrapping_key=self.__key, key_to_wrap=content_key)
def _unwrap(self, algorithm, wrapped_key, wrapped_key_algorithm, wrapped_key_type, additional_associated_data=None):
# type: (Text, bytes, Text, EncryptionKeyType, Optional[Dict[Text, Text]]) -> DelegatedKey
@@ -303,15 +291,12 @@ def _unwrap(self, algorithm, wrapped_key, wrapped_key_algorithm, wrapped_key_typ
raise UnwrappingError('Unsupported wrapped key type: "{}"'.format(wrapped_key_type))
unwrapper = encryption.JavaCipher.from_transformation(algorithm)
- unwrapped_key = unwrapper.unwrap(
- wrapping_key=self.__key,
- wrapped_key=wrapped_key
- )
+ unwrapped_key = unwrapper.unwrap(wrapping_key=self.__key, wrapped_key=wrapped_key)
return JceNameLocalDelegatedKey(
key=unwrapped_key,
algorithm=wrapped_key_algorithm,
key_type=wrapped_key_type,
- key_encoding=KeyEncodingType.RAW
+ key_encoding=KeyEncodingType.RAW,
)
def _sign(self, algorithm, data):
diff --git a/src/dynamodb_encryption_sdk/encrypted/__init__.py b/src/dynamodb_encryption_sdk/encrypted/__init__.py
index 105f3d93..e3e89ec1 100644
--- a/src/dynamodb_encryption_sdk/encrypted/__init__.py
+++ b/src/dynamodb_encryption_sdk/encrypted/__init__.py
@@ -15,19 +15,20 @@
import attr
+from dynamodb_encryption_sdk.exceptions import InvalidArgumentError
+from dynamodb_encryption_sdk.identifiers import CryptoAction
+from dynamodb_encryption_sdk.material_providers import CryptographicMaterialsProvider
+from dynamodb_encryption_sdk.materials import CryptographicMaterials # noqa pylint: disable=unused-import
+from dynamodb_encryption_sdk.structures import AttributeActions, EncryptionContext
+
try: # Python 3.5.0 and 3.5.1 have incompatible typing modules
from typing import Dict # noqa pylint: disable=unused-import
except ImportError: # pragma: no cover
# We only actually need these imports when running the mypy checks
pass
-from dynamodb_encryption_sdk.exceptions import InvalidArgumentError
-from dynamodb_encryption_sdk.identifiers import CryptoAction
-from dynamodb_encryption_sdk.material_providers import CryptographicMaterialsProvider
-from dynamodb_encryption_sdk.materials import CryptographicMaterials # noqa pylint: disable=unused-import
-from dynamodb_encryption_sdk.structures import AttributeActions, EncryptionContext
-__all__ = ('CryptoConfig',)
+__all__ = ("CryptoConfig",)
@attr.s(init=False)
@@ -48,10 +49,10 @@ class CryptoConfig(object):
attribute_actions = attr.ib(validator=attr.validators.instance_of(AttributeActions))
def __init__(
- self,
- materials_provider, # type: CryptographicMaterialsProvider
- encryption_context, # type: EncryptionContext
- attribute_actions # type: AttributeActions
+ self,
+ materials_provider, # type: CryptographicMaterialsProvider
+ encryption_context, # type: EncryptionContext
+ attribute_actions, # type: AttributeActions
): # noqa=D107
# type: (...) -> None
# Workaround pending resolution of attrs/mypy interaction.
@@ -67,12 +68,15 @@ def __attrs_post_init__(self):
# type: () -> None
"""Make sure that primary index attributes are not being encrypted."""
if self.encryption_context.partition_key_name is not None:
- if self.attribute_actions.action(self.encryption_context.partition_key_name) is CryptoAction.ENCRYPT_AND_SIGN: # noqa pylint: disable=line-too-long
- raise InvalidArgumentError('Cannot encrypt partition key')
+ if (
+ self.attribute_actions.action(self.encryption_context.partition_key_name)
+ is CryptoAction.ENCRYPT_AND_SIGN
+ ): # noqa pylint: disable=line-too-long
+ raise InvalidArgumentError("Cannot encrypt partition key")
if self.encryption_context.sort_key_name is not None:
if self.attribute_actions.action(self.encryption_context.sort_key_name) is CryptoAction.ENCRYPT_AND_SIGN:
- raise InvalidArgumentError('Cannot encrypt sort key')
+ raise InvalidArgumentError("Cannot encrypt sort key")
def decryption_materials(self):
# type: () -> CryptographicMaterials
@@ -102,7 +106,7 @@ def copy(self):
return CryptoConfig(
materials_provider=self.materials_provider,
encryption_context=copy.copy(self.encryption_context),
- attribute_actions=self.attribute_actions
+ attribute_actions=self.attribute_actions,
)
def with_item(self, item):
diff --git a/src/dynamodb_encryption_sdk/encrypted/client.py b/src/dynamodb_encryption_sdk/encrypted/client.py
index 04490a60..21720a40 100644
--- a/src/dynamodb_encryption_sdk/encrypted/client.py
+++ b/src/dynamodb_encryption_sdk/encrypted/client.py
@@ -16,24 +16,31 @@
import attr
import botocore
-try: # Python 3.5.0 and 3.5.1 have incompatible typing modules
- from typing import Any, Callable, Dict, Iterator, Optional # noqa pylint: disable=unused-import
-except ImportError: # pragma: no cover
- # We only actually need these imports when running the mypy checks
- pass
-
from dynamodb_encryption_sdk.internal.utils import (
- crypto_config_from_cache, crypto_config_from_kwargs,
- decrypt_batch_get_item, decrypt_get_item, decrypt_multi_get,
- encrypt_batch_write_item, encrypt_put_item, TableInfoCache,
- validate_get_arguments
+ TableInfoCache,
+ crypto_config_from_cache,
+ crypto_config_from_kwargs,
+ decrypt_batch_get_item,
+ decrypt_get_item,
+ decrypt_multi_get,
+ encrypt_batch_write_item,
+ encrypt_put_item,
+ validate_get_arguments,
)
from dynamodb_encryption_sdk.internal.validators import callable_validator
from dynamodb_encryption_sdk.material_providers import CryptographicMaterialsProvider
from dynamodb_encryption_sdk.structures import AttributeActions
+
from .item import decrypt_dynamodb_item, decrypt_python_item, encrypt_dynamodb_item, encrypt_python_item
-__all__ = ('EncryptedClient', 'EncryptedPaginator')
+try: # Python 3.5.0 and 3.5.1 have incompatible typing modules
+ from typing import Any, Callable, Dict, Iterator, Optional # noqa pylint: disable=unused-import
+except ImportError: # pragma: no cover
+ # We only actually need these imports when running the mypy checks
+ pass
+
+
+__all__ = ("EncryptedClient", "EncryptedPaginator")
@attr.s(init=False)
@@ -51,10 +58,10 @@ class EncryptedPaginator(object):
_crypto_config_method = attr.ib(validator=callable_validator)
def __init__(
- self,
- paginator, # type: botocore.paginate.Paginator
- decrypt_method, # type: Callable
- crypto_config_method # type: Callable
+ self,
+ paginator, # type: botocore.paginate.Paginator
+ decrypt_method, # type: Callable
+ crypto_config_method, # type: Callable
): # noqa=D107
# type: (...) -> None
# Workaround pending resolution of attrs/mypy interaction.
@@ -97,11 +104,8 @@ def paginate(self, **kwargs):
crypto_config, ddb_kwargs = self._crypto_config_method(**kwargs)
for page in self._paginator.paginate(**ddb_kwargs):
- for pos, value in enumerate(page['Items']):
- page['Items'][pos] = self._decrypt_method(
- item=value,
- crypto_config=crypto_config
- )
+ for pos, value in enumerate(page["Items"]):
+ page["Items"][pos] = self._decrypt_method(item=value, crypto_config=crypto_config)
yield page
@@ -152,25 +156,18 @@ class EncryptedClient(object):
_client = attr.ib(validator=attr.validators.instance_of(botocore.client.BaseClient))
_materials_provider = attr.ib(validator=attr.validators.instance_of(CryptographicMaterialsProvider))
_attribute_actions = attr.ib(
- validator=attr.validators.instance_of(AttributeActions),
- default=attr.Factory(AttributeActions)
- )
- _auto_refresh_table_indexes = attr.ib(
- validator=attr.validators.instance_of(bool),
- default=True
- )
- _expect_standard_dictionaries = attr.ib(
- validator=attr.validators.instance_of(bool),
- default=False
+ validator=attr.validators.instance_of(AttributeActions), default=attr.Factory(AttributeActions)
)
+ _auto_refresh_table_indexes = attr.ib(validator=attr.validators.instance_of(bool), default=True)
+ _expect_standard_dictionaries = attr.ib(validator=attr.validators.instance_of(bool), default=False)
def __init__(
- self,
- client, # type: botocore.client.BaseClient
- materials_provider, # type: CryptographicMaterialsProvider
- attribute_actions=None, # type: Optional[AttributeActions]
- auto_refresh_table_indexes=True, # type: Optional[bool]
- expect_standard_dictionaries=False # type: Optional[bool]
+ self,
+ client, # type: botocore.client.BaseClient
+ materials_provider, # type: CryptographicMaterialsProvider
+ attribute_actions=None, # type: Optional[AttributeActions]
+ auto_refresh_table_indexes=True, # type: Optional[bool]
+ expect_standard_dictionaries=False, # type: Optional[bool]
): # noqa=D107
# type: (...) -> None
# Workaround pending resolution of attrs/mypy interaction.
@@ -196,54 +193,31 @@ def __attrs_post_init__(self):
self._encrypt_item = encrypt_dynamodb_item # attrs confuses pylint: disable=attribute-defined-outside-init
self._decrypt_item = decrypt_dynamodb_item # attrs confuses pylint: disable=attribute-defined-outside-init
self._table_info_cache = TableInfoCache( # attrs confuses pylint: disable=attribute-defined-outside-init
- client=self._client,
- auto_refresh_table_indexes=self._auto_refresh_table_indexes
+ client=self._client, auto_refresh_table_indexes=self._auto_refresh_table_indexes
)
self._table_crypto_config = partial( # attrs confuses pylint: disable=attribute-defined-outside-init
- crypto_config_from_cache,
- self._materials_provider,
- self._attribute_actions,
- self._table_info_cache
+ crypto_config_from_cache, self._materials_provider, self._attribute_actions, self._table_info_cache
)
self._item_crypto_config = partial( # attrs confuses pylint: disable=attribute-defined-outside-init
- crypto_config_from_kwargs,
- self._table_crypto_config
+ crypto_config_from_kwargs, self._table_crypto_config
)
self.get_item = partial( # attrs confuses pylint: disable=attribute-defined-outside-init
- decrypt_get_item,
- self._decrypt_item,
- self._item_crypto_config,
- self._client.get_item
+ decrypt_get_item, self._decrypt_item, self._item_crypto_config, self._client.get_item
)
self.put_item = partial( # attrs confuses pylint: disable=attribute-defined-outside-init
- encrypt_put_item,
- self._encrypt_item,
- self._item_crypto_config,
- self._client.put_item
+ encrypt_put_item, self._encrypt_item, self._item_crypto_config, self._client.put_item
)
self.query = partial( # attrs confuses pylint: disable=attribute-defined-outside-init
- decrypt_multi_get,
- self._decrypt_item,
- self._item_crypto_config,
- self._client.query
+ decrypt_multi_get, self._decrypt_item, self._item_crypto_config, self._client.query
)
self.scan = partial( # attrs confuses pylint: disable=attribute-defined-outside-init
- decrypt_multi_get,
- self._decrypt_item,
- self._item_crypto_config,
- self._client.scan
+ decrypt_multi_get, self._decrypt_item, self._item_crypto_config, self._client.scan
)
self.batch_get_item = partial( # attrs confuses pylint: disable=attribute-defined-outside-init
- decrypt_batch_get_item,
- self._decrypt_item,
- self._table_crypto_config,
- self._client.batch_get_item
+ decrypt_batch_get_item, self._decrypt_item, self._table_crypto_config, self._client.batch_get_item
)
self.batch_write_item = partial( # attrs confuses pylint: disable=attribute-defined-outside-init
- encrypt_batch_write_item,
- self._encrypt_item,
- self._table_crypto_config,
- self._client.batch_write_item
+ encrypt_batch_write_item, self._encrypt_item, self._table_crypto_config, self._client.batch_write_item
)
def __getattr__(self, name):
@@ -273,11 +247,9 @@ def get_paginator(self, operation_name):
"""
paginator = self._client.get_paginator(operation_name)
- if operation_name in ('scan', 'query'):
+ if operation_name in ("scan", "query"):
return EncryptedPaginator(
- paginator=paginator,
- decrypt_method=self._decrypt_item,
- crypto_config_method=self._item_crypto_config
+ paginator=paginator, decrypt_method=self._decrypt_item, crypto_config_method=self._item_crypto_config
)
return paginator
diff --git a/src/dynamodb_encryption_sdk/encrypted/item.py b/src/dynamodb_encryption_sdk/encrypted/item.py
index 23d8a050..8ef19631 100644
--- a/src/dynamodb_encryption_sdk/encrypted/item.py
+++ b/src/dynamodb_encryption_sdk/encrypted/item.py
@@ -22,15 +22,19 @@
from dynamodb_encryption_sdk.internal.crypto.authentication import sign_item, verify_item_signature
from dynamodb_encryption_sdk.internal.crypto.encryption import decrypt_attribute, encrypt_attribute
from dynamodb_encryption_sdk.internal.formatting.material_description import (
- deserialize as deserialize_material_description, serialize as serialize_material_description
+ deserialize as deserialize_material_description,
+ serialize as serialize_material_description,
)
from dynamodb_encryption_sdk.internal.identifiers import (
- MaterialDescriptionKeys, MaterialDescriptionValues, ReservedAttributes
+ MaterialDescriptionKeys,
+ MaterialDescriptionValues,
+ ReservedAttributes,
)
from dynamodb_encryption_sdk.transform import ddb_to_dict, dict_to_ddb
+
from . import CryptoConfig # noqa pylint: disable=unused-import
-__all__ = ('encrypt_dynamodb_item', 'encrypt_python_item', 'decrypt_dynamodb_item', 'decrypt_python_item')
+__all__ = ("encrypt_dynamodb_item", "encrypt_python_item", "decrypt_dynamodb_item", "decrypt_python_item")
def encrypt_dynamodb_item(item, crypto_config):
@@ -62,9 +66,9 @@ def encrypt_dynamodb_item(item, crypto_config):
for reserved_name in ReservedAttributes:
if reserved_name.value in item:
- raise EncryptionError('Reserved attribute name "{}" is not allowed in plaintext item.'.format(
- reserved_name.value
- ))
+ raise EncryptionError(
+ 'Reserved attribute name "{}" is not allowed in plaintext item.'.format(reserved_name.value)
+ )
crypto_config.materials_provider.refresh()
encryption_materials = crypto_config.encryption_materials()
@@ -75,16 +79,14 @@ def encrypt_dynamodb_item(item, crypto_config):
except AttributeError:
if crypto_config.attribute_actions.contains_action(CryptoAction.ENCRYPT_AND_SIGN):
raise EncryptionError(
- 'Attribute actions ask for some attributes to be encrypted but no encryption key is available'
+ "Attribute actions ask for some attributes to be encrypted but no encryption key is available"
)
encrypted_item = item.copy()
else:
# Add the attribute encryption mode to the inner material description
encryption_mode = MaterialDescriptionValues.CBC_PKCS5_ATTRIBUTE_ENCRYPTION.value
- inner_material_description[
- MaterialDescriptionKeys.ATTRIBUTE_ENCRYPTION_MODE.value
- ] = encryption_mode
+ inner_material_description[MaterialDescriptionKeys.ATTRIBUTE_ENCRYPTION_MODE.value] = encryption_mode
algorithm_descriptor = encryption_materials.encryption_key.algorithm + encryption_mode
@@ -95,7 +97,7 @@ def encrypt_dynamodb_item(item, crypto_config):
attribute_name=name,
attribute=attribute,
encryption_key=encryption_materials.encryption_key,
- algorithm=algorithm_descriptor
+ algorithm=algorithm_descriptor,
)
else:
encrypted_item[name] = attribute.copy()
@@ -181,7 +183,7 @@ def decrypt_dynamodb_item(item, crypto_config):
except KeyError:
# The signature is always written, so if no signature is found then the item was not
# encrypted or signed.
- raise DecryptionError('No signature attribute found in item')
+ raise DecryptionError("No signature attribute found in item")
inner_crypto_config = crypto_config.copy()
# Retrieve the material description from the item if found.
@@ -204,7 +206,7 @@ def decrypt_dynamodb_item(item, crypto_config):
except AttributeError:
if inner_crypto_config.attribute_actions.contains_action(CryptoAction.ENCRYPT_AND_SIGN):
raise DecryptionError(
- 'Attribute actions ask for some attributes to be decrypted but no decryption key is available'
+ "Attribute actions ask for some attributes to be decrypted but no decryption key is available"
)
return item.copy()
@@ -219,10 +221,7 @@ def decrypt_dynamodb_item(item, crypto_config):
for name, attribute in item.items():
if inner_crypto_config.attribute_actions.action(name) is CryptoAction.ENCRYPT_AND_SIGN:
decrypted_item[name] = decrypt_attribute(
- attribute_name=name,
- attribute=attribute,
- decryption_key=decryption_key,
- algorithm=algorithm_descriptor
+ attribute_name=name, attribute=attribute, decryption_key=decryption_key, algorithm=algorithm_descriptor
)
else:
decrypted_item[name] = attribute.copy()
diff --git a/src/dynamodb_encryption_sdk/encrypted/resource.py b/src/dynamodb_encryption_sdk/encrypted/resource.py
index fb982c32..58b5c776 100644
--- a/src/dynamodb_encryption_sdk/encrypted/resource.py
+++ b/src/dynamodb_encryption_sdk/encrypted/resource.py
@@ -17,21 +17,26 @@
from boto3.resources.base import ServiceResource
from boto3.resources.collection import CollectionManager
-try: # Python 3.5.0 and 3.5.1 have incompatible typing modules
- from typing import Optional # noqa pylint: disable=unused-import
-except ImportError: # pragma: no cover
- # We only actually need these imports when running the mypy checks
- pass
-
from dynamodb_encryption_sdk.internal.utils import (
- crypto_config_from_cache, decrypt_batch_get_item, encrypt_batch_write_item, TableInfoCache
+ TableInfoCache,
+ crypto_config_from_cache,
+ decrypt_batch_get_item,
+ encrypt_batch_write_item,
)
from dynamodb_encryption_sdk.material_providers import CryptographicMaterialsProvider
from dynamodb_encryption_sdk.structures import AttributeActions
+
from .item import decrypt_python_item, encrypt_python_item
from .table import EncryptedTable
-__all__ = ('EncryptedResource', 'EncryptedTablesCollectionManager')
+try: # Python 3.5.0 and 3.5.1 have incompatible typing modules
+ from typing import Optional # noqa pylint: disable=unused-import
+except ImportError: # pragma: no cover
+ # We only actually need these imports when running the mypy checks
+ pass
+
+
+__all__ = ("EncryptedResource", "EncryptedTablesCollectionManager")
@attr.s(init=False)
@@ -54,11 +59,11 @@ class EncryptedTablesCollectionManager(object):
_table_info_cache = attr.ib(validator=attr.validators.instance_of(TableInfoCache))
def __init__(
- self,
- collection, # type: CollectionManager
- materials_provider, # type: CryptographicMaterialsProvider
- attribute_actions, # type: AttributeActions
- table_info_cache # type: TableInfoCache
+ self,
+ collection, # type: CollectionManager
+ materials_provider, # type: CryptographicMaterialsProvider
+ attribute_actions, # type: AttributeActions
+ table_info_cache, # type: TableInfoCache
): # noqa=D107
# type: (...) -> None
# Workaround pending resolution of attrs/mypy interaction.
@@ -74,20 +79,16 @@ def __init__(
def __attrs_post_init__(self):
"""Set up the translation methods."""
self.all = partial( # attrs confuses pylint: disable=attribute-defined-outside-init
- self._transform_table,
- self._collection.all
+ self._transform_table, self._collection.all
)
self.filter = partial( # attrs confuses pylint: disable=attribute-defined-outside-init
- self._transform_table,
- self._collection.filter
+ self._transform_table, self._collection.filter
)
self.limit = partial( # attrs confuses pylint: disable=attribute-defined-outside-init
- self._transform_table,
- self._collection.limit
+ self._transform_table, self._collection.limit
)
self.page_size = partial( # attrs confuses pylint: disable=attribute-defined-outside-init
- self._transform_table,
- self._collection.page_size
+ self._transform_table, self._collection.page_size
)
def __getattr__(self, name):
@@ -112,7 +113,7 @@ def _transform_table(self, method, **kwargs):
table=table,
materials_provider=self._materials_provider,
table_info=self._table_info_cache.table_info(table.name),
- attribute_actions=self._attribute_actions
+ attribute_actions=self._attribute_actions,
)
@@ -153,20 +154,16 @@ class EncryptedResource(object):
_resource = attr.ib(validator=attr.validators.instance_of(ServiceResource))
_materials_provider = attr.ib(validator=attr.validators.instance_of(CryptographicMaterialsProvider))
_attribute_actions = attr.ib(
- validator=attr.validators.instance_of(AttributeActions),
- default=attr.Factory(AttributeActions)
- )
- _auto_refresh_table_indexes = attr.ib(
- validator=attr.validators.instance_of(bool),
- default=True
+ validator=attr.validators.instance_of(AttributeActions), default=attr.Factory(AttributeActions)
)
+ _auto_refresh_table_indexes = attr.ib(validator=attr.validators.instance_of(bool), default=True)
def __init__(
- self,
- resource, # type: ServiceResource
- materials_provider, # type: CryptographicMaterialsProvider
- attribute_actions=None, # type: Optional[AttributeActions]
- auto_refresh_table_indexes=True # type: Optional[bool]
+ self,
+ resource, # type: ServiceResource
+ materials_provider, # type: CryptographicMaterialsProvider
+ attribute_actions=None, # type: Optional[AttributeActions]
+ auto_refresh_table_indexes=True, # type: Optional[bool]
): # noqa=D107
# type: (...) -> None
# Workaround pending resolution of attrs/mypy interaction.
@@ -185,32 +182,22 @@ def __init__(
def __attrs_post_init__(self):
"""Set up the table info cache, encrypted tables collection manager, and translation methods."""
self._table_info_cache = TableInfoCache( # attrs confuses pylint: disable=attribute-defined-outside-init
- client=self._resource.meta.client,
- auto_refresh_table_indexes=self._auto_refresh_table_indexes
+ client=self._resource.meta.client, auto_refresh_table_indexes=self._auto_refresh_table_indexes
)
self._crypto_config = partial( # attrs confuses pylint: disable=attribute-defined-outside-init
- crypto_config_from_cache,
- self._materials_provider,
- self._attribute_actions,
- self._table_info_cache
+ crypto_config_from_cache, self._materials_provider, self._attribute_actions, self._table_info_cache
)
self.tables = EncryptedTablesCollectionManager( # attrs confuses pylint: disable=attribute-defined-outside-init
collection=self._resource.tables,
materials_provider=self._materials_provider,
attribute_actions=self._attribute_actions,
- table_info_cache=self._table_info_cache
+ table_info_cache=self._table_info_cache,
)
self.batch_get_item = partial( # attrs confuses pylint: disable=attribute-defined-outside-init
- decrypt_batch_get_item,
- decrypt_python_item,
- self._crypto_config,
- self._resource.batch_get_item
+ decrypt_batch_get_item, decrypt_python_item, self._crypto_config, self._resource.batch_get_item
)
self.batch_write_item = partial( # attrs confuses pylint: disable=attribute-defined-outside-init
- encrypt_batch_write_item,
- encrypt_python_item,
- self._crypto_config,
- self._resource.batch_write_item
+ encrypt_batch_write_item, encrypt_python_item, self._crypto_config, self._resource.batch_write_item
)
def __getattr__(self, name):
@@ -241,10 +228,10 @@ def Table(self, name, **kwargs):
"""
table_kwargs = dict(
table=self._resource.Table(name),
- materials_provider=kwargs.get('materials_provider', self._materials_provider),
- attribute_actions=kwargs.get('attribute_actions', self._attribute_actions),
- auto_refresh_table_indexes=kwargs.get('auto_refresh_table_indexes', self._auto_refresh_table_indexes),
- table_info=self._table_info_cache.table_info(name)
+ materials_provider=kwargs.get("materials_provider", self._materials_provider),
+ attribute_actions=kwargs.get("attribute_actions", self._attribute_actions),
+ auto_refresh_table_indexes=kwargs.get("auto_refresh_table_indexes", self._auto_refresh_table_indexes),
+ table_info=self._table_info_cache.table_info(name),
)
return EncryptedTable(**table_kwargs)
diff --git a/src/dynamodb_encryption_sdk/encrypted/table.py b/src/dynamodb_encryption_sdk/encrypted/table.py
index c49e073d..51c69b74 100644
--- a/src/dynamodb_encryption_sdk/encrypted/table.py
+++ b/src/dynamodb_encryption_sdk/encrypted/table.py
@@ -17,22 +17,27 @@
from boto3.dynamodb.table import BatchWriter
from boto3.resources.base import ServiceResource
-try: # Python 3.5.0 and 3.5.1 have incompatible typing modules
- from typing import Optional # noqa pylint: disable=unused-import
-except ImportError: # pragma: no cover
- # We only actually need these imports when running the mypy checks
- pass
-
from dynamodb_encryption_sdk.internal.utils import (
- crypto_config_from_kwargs, crypto_config_from_table_info,
- decrypt_get_item, decrypt_multi_get, encrypt_put_item
+ crypto_config_from_kwargs,
+ crypto_config_from_table_info,
+ decrypt_get_item,
+ decrypt_multi_get,
+ encrypt_put_item,
)
from dynamodb_encryption_sdk.material_providers import CryptographicMaterialsProvider
from dynamodb_encryption_sdk.structures import AttributeActions, TableInfo
+
from .client import EncryptedClient
from .item import decrypt_python_item, encrypt_python_item
-__all__ = ('EncryptedTable',)
+try: # Python 3.5.0 and 3.5.1 have incompatible typing modules
+ from typing import Optional # noqa pylint: disable=unused-import
+except ImportError: # pragma: no cover
+ # We only actually need these imports when running the mypy checks
+ pass
+
+
+__all__ = ("EncryptedTable",)
@attr.s(init=False)
@@ -78,26 +83,19 @@ class EncryptedTable(object):
_table = attr.ib(validator=attr.validators.instance_of(ServiceResource))
_materials_provider = attr.ib(validator=attr.validators.instance_of(CryptographicMaterialsProvider))
- _table_info = attr.ib(
- validator=attr.validators.optional(attr.validators.instance_of(TableInfo)),
- default=None
- )
+ _table_info = attr.ib(validator=attr.validators.optional(attr.validators.instance_of(TableInfo)), default=None)
_attribute_actions = attr.ib(
- validator=attr.validators.instance_of(AttributeActions),
- default=attr.Factory(AttributeActions)
- )
- _auto_refresh_table_indexes = attr.ib(
- validator=attr.validators.instance_of(bool),
- default=True
+ validator=attr.validators.instance_of(AttributeActions), default=attr.Factory(AttributeActions)
)
+ _auto_refresh_table_indexes = attr.ib(validator=attr.validators.instance_of(bool), default=True)
def __init__(
- self,
- table, # type: ServiceResource
- materials_provider, # type: CryptographicMaterialsProvider
- table_info=None, # type: Optional[TableInfo]
- attribute_actions=None, # type: Optional[AttributeActions]
- auto_refresh_table_indexes=True # type: Optional[bool]
+ self,
+ table, # type: ServiceResource
+ materials_provider, # type: CryptographicMaterialsProvider
+ table_info=None, # type: Optional[TableInfo]
+ attribute_actions=None, # type: Optional[AttributeActions]
+ auto_refresh_table_indexes=True, # type: Optional[bool]
): # noqa=D107
# type: (...) -> None
# Workaround pending resolution of attrs/mypy interaction.
@@ -128,36 +126,19 @@ def __attrs_post_init__(self):
self._crypto_config = partial( # attrs confuses pylint: disable=attribute-defined-outside-init
crypto_config_from_kwargs,
- partial(
- crypto_config_from_table_info,
- self._materials_provider,
- self._attribute_actions,
- self._table_info
- )
+ partial(crypto_config_from_table_info, self._materials_provider, self._attribute_actions, self._table_info),
)
self.get_item = partial( # attrs confuses pylint: disable=attribute-defined-outside-init
- decrypt_get_item,
- decrypt_python_item,
- self._crypto_config,
- self._table.get_item
+ decrypt_get_item, decrypt_python_item, self._crypto_config, self._table.get_item
)
self.put_item = partial( # attrs confuses pylint: disable=attribute-defined-outside-init
- encrypt_put_item,
- encrypt_python_item,
- self._crypto_config,
- self._table.put_item
+ encrypt_put_item, encrypt_python_item, self._crypto_config, self._table.put_item
)
self.query = partial( # attrs confuses pylint: disable=attribute-defined-outside-init
- decrypt_multi_get,
- decrypt_python_item,
- self._crypto_config,
- self._table.query
+ decrypt_multi_get, decrypt_python_item, self._crypto_config, self._table.query
)
self.scan = partial( # attrs confuses pylint: disable=attribute-defined-outside-init
- decrypt_multi_get,
- decrypt_python_item,
- self._crypto_config,
- self._table.scan
+ decrypt_multi_get, decrypt_python_item, self._crypto_config, self._table.scan
)
def __getattr__(self, name):
@@ -188,10 +169,6 @@ def batch_writer(self, overwrite_by_pkeys=None):
materials_provider=self._materials_provider,
attribute_actions=self._attribute_actions,
auto_refresh_table_indexes=self._auto_refresh_table_indexes,
- expect_standard_dictionaries=True
- )
- return BatchWriter(
- table_name=self._table.name,
- client=encrypted_client,
- overwrite_by_pkeys=overwrite_by_pkeys
+ expect_standard_dictionaries=True,
)
+ return BatchWriter(table_name=self._table.name, client=encrypted_client, overwrite_by_pkeys=overwrite_by_pkeys)
diff --git a/src/dynamodb_encryption_sdk/identifiers.py b/src/dynamodb_encryption_sdk/identifiers.py
index 5b8b1954..92502590 100644
--- a/src/dynamodb_encryption_sdk/identifiers.py
+++ b/src/dynamodb_encryption_sdk/identifiers.py
@@ -13,11 +13,11 @@
"""Unique identifiers used by the DynamoDB Encryption Client."""
from enum import Enum
-__all__ = ('LOGGER_NAME', 'CryptoAction', 'EncryptionKeyType', 'KeyEncodingType')
-__version__ = '1.0.5'
+__all__ = ("LOGGER_NAME", "CryptoAction", "EncryptionKeyType", "KeyEncodingType")
+__version__ = "1.0.5"
-LOGGER_NAME = 'dynamodb_encryption_sdk'
-USER_AGENT_SUFFIX = 'DynamodbEncryptionSdkPython/{}'.format(__version__)
+LOGGER_NAME = "dynamodb_encryption_sdk"
+USER_AGENT_SUFFIX = "DynamodbEncryptionSdkPython/{}".format(__version__)
class CryptoAction(Enum):
diff --git a/src/dynamodb_encryption_sdk/internal/crypto/authentication.py b/src/dynamodb_encryption_sdk/internal/crypto/authentication.py
index 3a3ba3a8..c45ead11 100644
--- a/src/dynamodb_encryption_sdk/internal/crypto/authentication.py
+++ b/src/dynamodb_encryption_sdk/internal/crypto/authentication.py
@@ -19,6 +19,13 @@
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes
+from dynamodb_encryption_sdk.delegated_keys import DelegatedKey # noqa pylint: disable=unused-import
+from dynamodb_encryption_sdk.encrypted import CryptoConfig # noqa pylint: disable=unused-import
+from dynamodb_encryption_sdk.identifiers import CryptoAction
+from dynamodb_encryption_sdk.internal.formatting.serialize.attribute import serialize_attribute
+from dynamodb_encryption_sdk.internal.identifiers import TEXT_ENCODING, SignatureValues, Tag
+from dynamodb_encryption_sdk.structures import AttributeActions # noqa pylint: disable=unused-import
+
try: # Python 3.5.0 and 3.5.1 have incompatible typing modules
from typing import Text # noqa pylint: disable=unused-import
from dynamodb_encryption_sdk.internal import dynamodb_types # noqa pylint: disable=unused-import
@@ -26,14 +33,8 @@
# We only actually need these imports when running the mypy checks
pass
-from dynamodb_encryption_sdk.delegated_keys import DelegatedKey # noqa pylint: disable=unused-import
-from dynamodb_encryption_sdk.encrypted import CryptoConfig # noqa pylint: disable=unused-import
-from dynamodb_encryption_sdk.identifiers import CryptoAction
-from dynamodb_encryption_sdk.internal.formatting.serialize.attribute import serialize_attribute
-from dynamodb_encryption_sdk.internal.identifiers import SignatureValues, Tag, TEXT_ENCODING
-from dynamodb_encryption_sdk.structures import AttributeActions # noqa pylint: disable=unused-import
-__all__ = ('sign_item', 'verify_item_signature')
+__all__ = ("sign_item", "verify_item_signature")
def sign_item(encrypted_item, signing_key, crypto_config):
@@ -51,8 +52,8 @@ def sign_item(encrypted_item, signing_key, crypto_config):
data=_string_to_sign(
item=encrypted_item,
table_name=crypto_config.encryption_context.table_name,
- attribute_actions=crypto_config.attribute_actions
- )
+ attribute_actions=crypto_config.attribute_actions,
+ ),
)
return {Tag.BINARY.dynamodb_tag: signature}
@@ -73,8 +74,8 @@ def verify_item_signature(signature_attribute, encrypted_item, verification_key,
data=_string_to_sign(
item=encrypted_item,
table_name=crypto_config.encryption_context.table_name,
- attribute_actions=crypto_config.attribute_actions
- )
+ attribute_actions=crypto_config.attribute_actions,
+ ),
)
@@ -86,34 +87,22 @@ def _string_to_sign(item, table_name, attribute_actions):
:param str table_name: Table name to use when generating the string to sign
:param AttributeActions attribute_actions: Actions to take for item
"""
- hasher = hashes.Hash(
- hashes.SHA256(),
- backend=default_backend()
- )
+ hasher = hashes.Hash(hashes.SHA256(), backend=default_backend())
data_to_sign = bytearray()
- data_to_sign.extend(_hash_data(
- hasher=hasher,
- data='TABLE>{}
None
# Workaround pending resolution of attrs/mypy interaction.
@@ -123,11 +122,7 @@ def _build_hmac_signer(self, key):
:param bytes key: Key to use in signer
"""
- return self.algorithm_type(
- key,
- self.hash_type(),
- backend=default_backend()
- )
+ return self.algorithm_type(key, self.hash_type(), backend=default_backend())
def load_key(self, key, key_type, key_encoding):
# (bytes, EncryptionKeyType, KeyEncodingType) -> bytes
@@ -141,7 +136,7 @@ def load_key(self, key, key_type, key_encoding):
:raises ValueError: if ``key_type`` is not symmetric or ``key_encoding`` is not raw
"""
if not (key_type is EncryptionKeyType.SYMMETRIC and key_encoding is KeyEncodingType.RAW):
- raise ValueError('Key type must be symmetric and encoding must be raw.')
+ raise ValueError("Key type must be symmetric and encoding must be raw.")
return key
@@ -155,8 +150,7 @@ def validate_algorithm(self, algorithm):
if not algorithm.startswith(self.java_name):
raise InvalidAlgorithmError(
'Requested algorithm "{requested}" is not compatible with signature "{actual}"'.format(
- requested=algorithm,
- actual=self.java_name
+ requested=algorithm, actual=self.java_name
)
)
@@ -175,7 +169,7 @@ def sign(self, key, data):
signer.update(data)
return signer.finalize()
except Exception:
- message = 'Unable to sign data'
+ message = "Unable to sign data"
_LOGGER.exception(message)
raise SigningError(message)
@@ -193,7 +187,7 @@ def verify(self, key, signature, data):
verifier.update(data)
verifier.verify(signature)
except Exception:
- message = 'Unable to verify signature'
+ message = "Unable to verify signature"
_LOGGER.exception(message)
raise SignatureVerificationError(message)
@@ -212,11 +206,7 @@ class JavaSignature(JavaAuthenticator):
padding_type = attr.ib(validator=callable_validator)
def __init__(
- self,
- java_name, # type: Text
- algorithm_type,
- hash_type, # type: Callable
- padding_type # type: Callable
+ self, java_name, algorithm_type, hash_type, padding_type # type: Text # type: Callable # type: Callable
): # noqa=D107
# type: (...) -> None
# Workaround pending resolution of attrs/mypy interaction.
@@ -238,8 +228,7 @@ def validate_algorithm(self, algorithm):
if not algorithm.endswith(self.java_name):
raise InvalidAlgorithmError(
'Requested algorithm "{requested}" is not compatible with signature "{actual}"'.format(
- requested=algorithm,
- actual=self.java_name
+ requested=algorithm, actual=self.java_name
)
)
@@ -269,16 +258,12 @@ def sign(self, key, data):
:rtype: bytes
:raises SigningError: if unable to sign ``data`` with ``key``
"""
- if hasattr(key, 'public_bytes'):
+ if hasattr(key, "public_bytes"):
raise SigningError('"sign" is not supported by public keys')
try:
- return key.sign(
- data,
- self.padding_type(),
- self.hash_type()
- )
+ return key.sign(data, self.padding_type(), self.hash_type())
except Exception:
- message = 'Unable to sign data'
+ message = "Unable to sign data"
_LOGGER.exception(message)
raise SigningError(message)
@@ -293,19 +278,14 @@ def verify(self, key, signature, data):
:param bytes data: Data over which to verify signature
:raises SignatureVerificationError: if unable to verify ``signature``
"""
- if hasattr(key, 'private_bytes'):
+ if hasattr(key, "private_bytes"):
_key = key.public_key()
else:
_key = key
try:
- _key.verify(
- signature,
- data,
- self.padding_type(),
- self.hash_type()
- )
+ _key.verify(signature, data, self.padding_type(), self.hash_type())
except Exception:
- message = 'Unable to verify signature'
+ message = "Unable to verify signature"
_LOGGER.exception(message)
raise SignatureVerificationError(message)
@@ -315,12 +295,12 @@ def verify(self, key, signature, data):
# SHA(1|224|256|384|512)with(|EC)DSA
# If this changes, remember to update the JceNameLocalDelegatedKey docs.
JAVA_AUTHENTICATOR = {
- 'HmacSHA224': JavaMac('HmacSHA224', hmac.HMAC, hashes.SHA224),
- 'HmacSHA256': JavaMac('HmacSHA256', hmac.HMAC, hashes.SHA256),
- 'HmacSHA384': JavaMac('HmacSHA384', hmac.HMAC, hashes.SHA384),
- 'HmacSHA512': JavaMac('HmacSHA512', hmac.HMAC, hashes.SHA512),
- 'SHA224withRSA': JavaSignature('SHA224withRSA', rsa, hashes.SHA224, padding.PKCS1v15),
- 'SHA256withRSA': JavaSignature('SHA256withRSA', rsa, hashes.SHA256, padding.PKCS1v15),
- 'SHA384withRSA': JavaSignature('SHA384withRSA', rsa, hashes.SHA384, padding.PKCS1v15),
- 'SHA512withRSA': JavaSignature('SHA512withRSA', rsa, hashes.SHA512, padding.PKCS1v15)
+ "HmacSHA224": JavaMac("HmacSHA224", hmac.HMAC, hashes.SHA224),
+ "HmacSHA256": JavaMac("HmacSHA256", hmac.HMAC, hashes.SHA256),
+ "HmacSHA384": JavaMac("HmacSHA384", hmac.HMAC, hashes.SHA384),
+ "HmacSHA512": JavaMac("HmacSHA512", hmac.HMAC, hashes.SHA512),
+ "SHA224withRSA": JavaSignature("SHA224withRSA", rsa, hashes.SHA224, padding.PKCS1v15),
+ "SHA256withRSA": JavaSignature("SHA256withRSA", rsa, hashes.SHA256, padding.PKCS1v15),
+ "SHA384withRSA": JavaSignature("SHA384withRSA", rsa, hashes.SHA384, padding.PKCS1v15),
+ "SHA512withRSA": JavaSignature("SHA512withRSA", rsa, hashes.SHA512, padding.PKCS1v15),
}
diff --git a/src/dynamodb_encryption_sdk/internal/crypto/jce_bridge/encryption.py b/src/dynamodb_encryption_sdk/internal/crypto/jce_bridge/encryption.py
index 95a6c369..b09f60a1 100644
--- a/src/dynamodb_encryption_sdk/internal/crypto/jce_bridge/encryption.py
+++ b/src/dynamodb_encryption_sdk/internal/crypto/jce_bridge/encryption.py
@@ -19,11 +19,17 @@
import attr
from dynamodb_encryption_sdk.exceptions import JceTransformationError
+
from .primitives import (
- JAVA_ENCRYPTION_ALGORITHM, JAVA_MODE, JAVA_PADDING, JavaEncryptionAlgorithm, JavaMode, JavaPadding
+ JAVA_ENCRYPTION_ALGORITHM,
+ JAVA_MODE,
+ JAVA_PADDING,
+ JavaEncryptionAlgorithm,
+ JavaMode,
+ JavaPadding,
)
-__all__ = ('JavaCipher',)
+__all__ = ("JavaCipher",)
@attr.s(init=False)
@@ -42,10 +48,7 @@ class JavaCipher(object):
padding = attr.ib(validator=attr.validators.instance_of(JavaPadding))
def __init__(
- self,
- cipher, # type: JavaEncryptionAlgorithm
- mode, # type: JavaMode
- padding # type: JavaPadding
+ self, cipher, mode, padding # type: JavaEncryptionAlgorithm # type: JavaMode # type: JavaPadding
): # noqa=D107
# type: (...) -> None
# Workaround pending resolution of attrs/mypy interaction.
@@ -84,14 +87,9 @@ def wrap(self, wrapping_key, key_to_wrap):
:returns: Wrapped key
:rtype: bytes
"""
- if hasattr(self.cipher, 'wrap'):
+ if hasattr(self.cipher, "wrap"):
return self.cipher.wrap(wrapping_key, key_to_wrap)
- return self.cipher.encrypt(
- key=wrapping_key,
- data=key_to_wrap,
- mode=self.mode,
- padding=self.padding
- )
+ return self.cipher.encrypt(key=wrapping_key, data=key_to_wrap, mode=self.mode, padding=self.padding)
def unwrap(self, wrapping_key, wrapped_key):
"""Wrap key using loaded key.
@@ -101,14 +99,9 @@ def unwrap(self, wrapping_key, wrapped_key):
:returns: Unwrapped key
:rtype: bytes
"""
- if hasattr(self.cipher, 'unwrap'):
+ if hasattr(self.cipher, "unwrap"):
return self.cipher.unwrap(wrapping_key, wrapped_key)
- return self.cipher.decrypt(
- key=wrapping_key,
- data=wrapped_key,
- mode=self.mode,
- padding=self.padding
- )
+ return self.cipher.decrypt(key=wrapping_key, data=wrapped_key, mode=self.mode, padding=self.padding)
@property
def transformation(self):
@@ -119,10 +112,8 @@ def transformation(self):
:returns: Formatted transformation
:rtype: str
"""
- return '{cipher}/{mode}/{padding}'.format(
- cipher=self.cipher.java_name,
- mode=self.mode.java_name,
- padding=self.padding.java_name
+ return "{cipher}/{mode}/{padding}".format(
+ cipher=self.cipher.java_name, mode=self.mode.java_name, padding=self.padding.java_name
)
@staticmethod
@@ -136,10 +127,7 @@ def _map_load_or_error(name_type, name, mappings):
try:
return mappings[name]
except KeyError:
- raise JceTransformationError('Invalid {type} name: "{name}"'.format(
- type=name_type,
- name=name
- ))
+ raise JceTransformationError('Invalid {type} name: "{name}"'.format(type=name_type, name=name))
@classmethod
def from_transformation(cls, cipher_transformation):
@@ -151,16 +139,16 @@ def from_transformation(cls, cipher_transformation):
:returns: JavaCipher instance
:rtype: JavaCipher
"""
- if cipher_transformation == 'AESWrap':
+ if cipher_transformation == "AESWrap":
# AESWrap does not support encrypt or decrypt, so mode and padding are never
# used, but we use ECB and NoPadding as placeholders to simplify handling.
- return cls.from_transformation('AESWrap/ECB/NoPadding')
+ return cls.from_transformation("AESWrap/ECB/NoPadding")
- if cipher_transformation == 'RSA':
+ if cipher_transformation == "RSA":
# RSA does not use mode, but as with JCE, we use ECB as a placeholder to simplify handling.
- return cls.from_transformation('RSA/ECB/PKCS1Padding')
+ return cls.from_transformation("RSA/ECB/PKCS1Padding")
- cipher_transformation_parts = cipher_transformation.split('/')
+ cipher_transformation_parts = cipher_transformation.split("/")
if len(cipher_transformation_parts) != 3:
raise JceTransformationError(
'Invalid transformation: "{}": must be three parts ALGORITHM/MODE/PADDING, "RSA", or "AESWrap"'.format(
@@ -168,8 +156,8 @@ def from_transformation(cls, cipher_transformation):
)
)
- cipher = cls._map_load_or_error('algorithm', cipher_transformation_parts[0], JAVA_ENCRYPTION_ALGORITHM)
- mode = cls._map_load_or_error('mode', cipher_transformation_parts[1], JAVA_MODE)
- padding = cls._map_load_or_error('padding', cipher_transformation_parts[2], JAVA_PADDING)
+ cipher = cls._map_load_or_error("algorithm", cipher_transformation_parts[0], JAVA_ENCRYPTION_ALGORITHM)
+ mode = cls._map_load_or_error("mode", cipher_transformation_parts[1], JAVA_MODE)
+ padding = cls._map_load_or_error("padding", cipher_transformation_parts[2], JAVA_PADDING)
return cls(cipher, mode, padding)
diff --git a/src/dynamodb_encryption_sdk/internal/crypto/jce_bridge/primitives.py b/src/dynamodb_encryption_sdk/internal/crypto/jce_bridge/primitives.py
index c3dafccb..8d99fcf7 100644
--- a/src/dynamodb_encryption_sdk/internal/crypto/jce_bridge/primitives.py
+++ b/src/dynamodb_encryption_sdk/internal/crypto/jce_bridge/primitives.py
@@ -21,11 +21,21 @@
import os
import attr
+import six
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes, keywrap, padding as symmetric_padding, serialization
from cryptography.hazmat.primitives.asymmetric import padding as asymmetric_padding, rsa
-from cryptography.hazmat.primitives.ciphers import algorithms, Cipher, modes
-import six
+from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
+
+from dynamodb_encryption_sdk.exceptions import (
+ DecryptionError,
+ EncryptionError,
+ InvalidAlgorithmError,
+ UnwrappingError,
+ WrappingError,
+)
+from dynamodb_encryption_sdk.identifiers import LOGGER_NAME, EncryptionKeyType, KeyEncodingType
+from dynamodb_encryption_sdk.internal.validators import callable_validator
try: # Python 3.5.0 and 3.5.1 have incompatible typing modules
from typing import Any, Callable, Text # noqa pylint: disable=unused-import
@@ -33,17 +43,19 @@
# We only actually need these imports when running the mypy checks
pass
-from dynamodb_encryption_sdk.exceptions import (
- DecryptionError, EncryptionError, InvalidAlgorithmError, UnwrappingError, WrappingError
-)
-from dynamodb_encryption_sdk.identifiers import EncryptionKeyType, KeyEncodingType, LOGGER_NAME
-from dynamodb_encryption_sdk.internal.validators import callable_validator
__all__ = (
- 'JavaPadding', 'SimplePadding', 'BlockSizePadding', 'OaepPadding',
- 'JavaMode',
- 'JavaEncryptionAlgorithm', 'JavaSymmetricEncryptionAlgorithm', 'JavaAsymmetricEncryptionAlgorithm',
- 'JAVA_ENCRYPTION_ALGORITHM', 'JAVA_MODE', 'JAVA_PADDING'
+ "JavaPadding",
+ "SimplePadding",
+ "BlockSizePadding",
+ "OaepPadding",
+ "JavaMode",
+ "JavaEncryptionAlgorithm",
+ "JavaSymmetricEncryptionAlgorithm",
+ "JavaAsymmetricEncryptionAlgorithm",
+ "JAVA_ENCRYPTION_ALGORITHM",
+ "JAVA_MODE",
+ "JAVA_PADDING",
)
_LOGGER = logging.getLogger(LOGGER_NAME)
@@ -69,7 +81,7 @@ def finalize(self):
:returns: Empty bytestring
:rtype: bytes
"""
- return b''
+ return b""
def padder(self):
"""Return NoPadder object.
@@ -108,11 +120,7 @@ class SimplePadding(JavaPadding):
java_name = attr.ib(validator=attr.validators.instance_of(six.string_types))
padding = attr.ib(validator=callable_validator)
- def __init__(
- self,
- java_name, # type: Text
- padding # type: Callable
- ): # noqa=D107
+ def __init__(self, java_name, padding): # type: Text # type: Callable # noqa=D107
# type: (...) -> None
# Workaround pending resolution of attrs/mypy interaction.
# https://github.com/python/mypy/issues/2088
@@ -139,11 +147,7 @@ class BlockSizePadding(JavaPadding):
java_name = attr.ib(validator=attr.validators.instance_of(six.string_types))
padding = attr.ib(validator=callable_validator)
- def __init__(
- self,
- java_name, # type: Text
- padding # type: Callable
- ): # noqa=D107
+ def __init__(self, java_name, padding): # type: Text # type: Callable # noqa=D107
# type: (...) -> None
# Workaround pending resolution of attrs/mypy interaction.
# https://github.com/python/mypy/issues/2088
@@ -184,12 +188,12 @@ class OaepPadding(JavaPadding):
mgf_digest = attr.ib(validator=callable_validator)
def __init__(
- self,
- java_name, # type: Text
- padding, # type: Callable
- digest, # type: Callable
- mgf, # type: Callable
- mgf_digest # type: Callable
+ self,
+ java_name, # type: Text
+ padding, # type: Callable
+ digest, # type: Callable
+ mgf, # type: Callable
+ mgf_digest, # type: Callable
): # noqa=D107
# type: (...) -> None
# Workaround pending resolution of attrs/mypy interaction.
@@ -209,11 +213,7 @@ def build(self, block_size=None):
:param int block_size: Not used by OaepPadding. Ignored and not required.
:returns: Padding instance
"""
- return self.padding(
- mgf=self.mgf(algorithm=self.mgf_digest()),
- algorithm=self.digest(),
- label=None
- )
+ return self.padding(mgf=self.mgf(algorithm=self.mgf_digest()), algorithm=self.digest(), label=None)
@attr.s(init=False)
@@ -226,11 +226,7 @@ class JavaMode(object):
java_name = attr.ib(validator=attr.validators.instance_of(six.string_types))
mode = attr.ib(validator=callable_validator)
- def __init__(
- self,
- java_name, # type: Text
- mode # type: Callable
- ): # noqa=D107
+ def __init__(self, java_name, mode): # type: Text # type: Callable # noqa=D107
# type: (...) -> None
# Workaround pending resolution of attrs/mypy interaction.
# https://github.com/python/mypy/issues/2088
@@ -259,11 +255,7 @@ class JavaEncryptionAlgorithm(object):
java_name = attr.ib(validator=attr.validators.instance_of(six.string_types))
cipher = attr.ib()
- def __init__(
- self,
- java_name, # type: Text
- cipher # type: Callable
- ): # noqa=D107
+ def __init__(self, java_name, cipher): # type: Text # type: Callable # noqa=D107
# type: (...) -> None
# Workaround pending resolution of attrs/mypy interaction.
# https://github.com/python/mypy/issues/2088
@@ -282,8 +274,7 @@ def validate_algorithm(self, algorithm):
if not algorithm == self.java_name:
raise InvalidAlgorithmError(
'Requested algorithm "{requested}" is not compatible with cipher "{actual}"'.format(
- requested=algorithm,
- actual=self.java_name
+ requested=algorithm, actual=self.java_name
)
)
@@ -310,7 +301,7 @@ def _disable_encryption(self):
def __attrs_post_init__(self):
# () -> None
"""Disable encryption if algorithm is AESWrap."""
- if self.java_name == 'AESWrap':
+ if self.java_name == "AESWrap":
self._disable_encryption()
def load_key(self, key, key_type, key_encoding):
@@ -322,16 +313,16 @@ def load_key(self, key, key_type, key_encoding):
:returns: Loaded key
"""
if key_type is not EncryptionKeyType.SYMMETRIC:
- raise ValueError('Invalid key type "{key_type}" for cipher "{cipher}"'.format(
- key_type=key_type,
- cipher=self.java_name
- ))
+ raise ValueError(
+ 'Invalid key type "{key_type}" for cipher "{cipher}"'.format(key_type=key_type, cipher=self.java_name)
+ )
if key_encoding is not KeyEncodingType.RAW:
- raise ValueError('Invalid key encoding "{key_encoding}" for cipher "{cipher}"'.format(
- key_encoding=key_encoding,
- cipher=self.java_name
- ))
+ raise ValueError(
+ 'Invalid key encoding "{key_encoding}" for cipher "{cipher}"'.format(
+ key_encoding=key_encoding, cipher=self.java_name
+ )
+ )
return key
@@ -344,17 +335,13 @@ def wrap(self, wrapping_key, key_to_wrap):
:returns: Wrapped key
:rtype: bytes
"""
- if self.java_name not in ('AES', 'AESWrap'):
+ if self.java_name not in ("AES", "AESWrap"):
raise NotImplementedError('"wrap" is not supported by the "{}" cipher'.format(self.java_name))
try:
- return keywrap.aes_key_wrap(
- wrapping_key=wrapping_key,
- key_to_wrap=key_to_wrap,
- backend=default_backend()
- )
+ return keywrap.aes_key_wrap(wrapping_key=wrapping_key, key_to_wrap=key_to_wrap, backend=default_backend())
except Exception:
- error_message = 'Key wrap failed'
+ error_message = "Key wrap failed"
_LOGGER.exception(error_message)
raise WrappingError(error_message)
@@ -367,17 +354,13 @@ def unwrap(self, wrapping_key, wrapped_key):
:returns: Unwrapped key
:rtype: bytes
"""
- if self.java_name not in ('AES', 'AESWrap'):
+ if self.java_name not in ("AES", "AESWrap"):
raise NotImplementedError('"unwrap" is not supported by this cipher')
try:
- return keywrap.aes_key_unwrap(
- wrapping_key=wrapping_key,
- wrapped_key=wrapped_key,
- backend=default_backend()
- )
+ return keywrap.aes_key_unwrap(wrapping_key=wrapping_key, wrapped_key=wrapped_key, backend=default_backend())
except Exception:
- error_message = 'Key unwrap failed'
+ error_message = "Key unwrap failed"
_LOGGER.exception(error_message)
raise UnwrappingError(error_message)
@@ -397,17 +380,13 @@ def encrypt(self, key, data, mode, padding):
iv_len = block_size // 8
iv = os.urandom(iv_len)
- encryptor = Cipher(
- self.cipher(key),
- mode.build(iv),
- backend=default_backend()
- ).encryptor()
+ encryptor = Cipher(self.cipher(key), mode.build(iv), backend=default_backend()).encryptor()
padder = padding.build(block_size).padder()
padded_data = padder.update(data) + padder.finalize()
return iv + encryptor.update(padded_data) + encryptor.finalize()
except Exception:
- error_message = 'Encryption failed'
+ error_message = "Encryption failed"
_LOGGER.exception(error_message)
raise EncryptionError(error_message)
@@ -428,17 +407,13 @@ def decrypt(self, key, data, mode, padding):
iv = data[:iv_len]
data = data[iv_len:]
- decryptor = Cipher(
- self.cipher(key),
- mode.build(iv),
- backend=default_backend()
- ).decryptor()
+ decryptor = Cipher(self.cipher(key), mode.build(iv), backend=default_backend()).decryptor()
decrypted_data = decryptor.update(data) + decryptor.finalize()
unpadder = padding.build(block_size).unpadder()
return unpadder.update(decrypted_data) + unpadder.finalize()
except Exception:
- error_message = 'Decryption failed'
+ error_message = "Decryption failed"
_LOGGER.exception(error_message)
raise DecryptionError(error_message)
@@ -446,12 +421,12 @@ def decrypt(self, key, data, mode, padding):
_RSA_KEY_LOADING = {
EncryptionKeyType.PRIVATE: {
KeyEncodingType.DER: serialization.load_der_private_key,
- KeyEncodingType.PEM: serialization.load_pem_private_key
+ KeyEncodingType.PEM: serialization.load_pem_private_key,
},
EncryptionKeyType.PUBLIC: {
KeyEncodingType.DER: serialization.load_der_public_key,
- KeyEncodingType.PEM: serialization.load_pem_public_key
- }
+ KeyEncodingType.PEM: serialization.load_pem_public_key,
+ },
}
@@ -470,18 +445,16 @@ def load_rsa_key(key, key_type, key_encoding):
try:
loader = _RSA_KEY_LOADING[key_type][key_encoding]
except KeyError:
- raise ValueError('Invalid key type and encoding: {} and {}'.format(key_type, key_encoding))
+ raise ValueError("Invalid key type and encoding: {} and {}".format(key_type, key_encoding))
kwargs = dict(data=key, backend=default_backend())
if key_type is EncryptionKeyType.PRIVATE:
- kwargs['password'] = None
+ kwargs["password"] = None
return loader(**kwargs)
-_KEY_LOADERS = {
- rsa: load_rsa_key
-}
+_KEY_LOADERS = {rsa: load_rsa_key}
class JavaAsymmetricEncryptionAlgorithm(JavaEncryptionAlgorithm):
@@ -499,16 +472,16 @@ def load_key(self, key, key_type, key_encoding):
:returns: Loaded key
"""
if key_type not in (EncryptionKeyType.PRIVATE, EncryptionKeyType.PUBLIC):
- raise ValueError('Invalid key type "{key_type}" for cipher "{cipher}"'.format(
- key_type=key_type,
- cipher=self.java_name
- ))
+ raise ValueError(
+ 'Invalid key type "{key_type}" for cipher "{cipher}"'.format(key_type=key_type, cipher=self.java_name)
+ )
if key_encoding not in (KeyEncodingType.DER, KeyEncodingType.PEM):
- raise ValueError('Invalid key encoding "{key_encoding}" for cipher "{cipher}"'.format(
- key_encoding=key_encoding,
- cipher=self.java_name
- ))
+ raise ValueError(
+ 'Invalid key encoding "{key_encoding}" for cipher "{cipher}"'.format(
+ key_encoding=key_encoding, cipher=self.java_name
+ )
+ )
return _KEY_LOADERS[self.cipher](key, key_type, key_encoding)
@@ -523,14 +496,14 @@ def encrypt(self, key, data, mode, padding):
:returns: Encrypted data
:rtype: bytes
"""
- if hasattr(key, 'private_bytes'):
+ if hasattr(key, "private_bytes"):
_key = key.public_key()
else:
_key = key
try:
return _key.encrypt(data, padding.build())
except Exception:
- error_message = 'Encryption failed'
+ error_message = "Encryption failed"
_LOGGER.exception(error_message)
raise EncryptionError(error_message)
@@ -545,46 +518,46 @@ def decrypt(self, key, data, mode, padding):
:returns: Decrypted data
:rtype: bytes
"""
- if hasattr(key, 'public_bytes'):
+ if hasattr(key, "public_bytes"):
raise NotImplementedError('"decrypt" is not supported by public keys')
try:
return key.decrypt(data, padding.build())
except Exception:
- error_message = 'Decryption failed'
+ error_message = "Decryption failed"
_LOGGER.exception(error_message)
raise DecryptionError(error_message)
# If this changes, remember to update the JceNameLocalDelegatedKey docs.
JAVA_ENCRYPTION_ALGORITHM = {
- 'RSA': JavaAsymmetricEncryptionAlgorithm('RSA', rsa),
- 'AES': JavaSymmetricEncryptionAlgorithm('AES', algorithms.AES),
- 'AESWrap': JavaSymmetricEncryptionAlgorithm('AESWrap', algorithms.AES)
+ "RSA": JavaAsymmetricEncryptionAlgorithm("RSA", rsa),
+ "AES": JavaSymmetricEncryptionAlgorithm("AES", algorithms.AES),
+ "AESWrap": JavaSymmetricEncryptionAlgorithm("AESWrap", algorithms.AES),
}
JAVA_MODE = {
- 'ECB': JavaMode('ECB', modes.ECB),
- 'CBC': JavaMode('CBC', modes.CBC),
- 'CTR': JavaMode('CTR', modes.CTR),
- 'GCM': JavaMode('GCM', modes.GCM)
+ "ECB": JavaMode("ECB", modes.ECB),
+ "CBC": JavaMode("CBC", modes.CBC),
+ "CTR": JavaMode("CTR", modes.CTR),
+ "GCM": JavaMode("GCM", modes.GCM),
}
JAVA_PADDING = {
- 'NoPadding': SimplePadding('NoPadding', _NoPadding),
- 'PKCS1Padding': SimplePadding('PKCS1Padding', asymmetric_padding.PKCS1v15),
+ "NoPadding": SimplePadding("NoPadding", _NoPadding),
+ "PKCS1Padding": SimplePadding("PKCS1Padding", asymmetric_padding.PKCS1v15),
# PKCS7 padding is a generalization of PKCS5 padding.
- 'PKCS5Padding': BlockSizePadding('PKCS5Padding', symmetric_padding.PKCS7),
+ "PKCS5Padding": BlockSizePadding("PKCS5Padding", symmetric_padding.PKCS7),
# By default, Java incorrectly implements RSA OAEP for all hash functions besides SHA1.
# The same hashing algorithm should be used by both OAEP and the MGF, but by default
# Java always uses SHA1 for the MGF.
- 'OAEPWithSHA-1AndMGF1Padding': OaepPadding(
- 'OAEPWithSHA-1AndMGF1Padding', asymmetric_padding.OAEP, hashes.SHA1, asymmetric_padding.MGF1, hashes.SHA1
+ "OAEPWithSHA-1AndMGF1Padding": OaepPadding(
+ "OAEPWithSHA-1AndMGF1Padding", asymmetric_padding.OAEP, hashes.SHA1, asymmetric_padding.MGF1, hashes.SHA1
+ ),
+ "OAEPWithSHA-256AndMGF1Padding": OaepPadding(
+ "OAEPWithSHA-256AndMGF1Padding", asymmetric_padding.OAEP, hashes.SHA256, asymmetric_padding.MGF1, hashes.SHA1
),
- 'OAEPWithSHA-256AndMGF1Padding': OaepPadding(
- 'OAEPWithSHA-256AndMGF1Padding', asymmetric_padding.OAEP, hashes.SHA256, asymmetric_padding.MGF1, hashes.SHA1
+ "OAEPWithSHA-384AndMGF1Padding": OaepPadding(
+ "OAEPWithSHA-384AndMGF1Padding", asymmetric_padding.OAEP, hashes.SHA384, asymmetric_padding.MGF1, hashes.SHA1
),
- 'OAEPWithSHA-384AndMGF1Padding': OaepPadding(
- 'OAEPWithSHA-384AndMGF1Padding', asymmetric_padding.OAEP, hashes.SHA384, asymmetric_padding.MGF1, hashes.SHA1
+ "OAEPWithSHA-512AndMGF1Padding": OaepPadding(
+ "OAEPWithSHA-512AndMGF1Padding", asymmetric_padding.OAEP, hashes.SHA512, asymmetric_padding.MGF1, hashes.SHA1
),
- 'OAEPWithSHA-512AndMGF1Padding': OaepPadding(
- 'OAEPWithSHA-512AndMGF1Padding', asymmetric_padding.OAEP, hashes.SHA512, asymmetric_padding.MGF1, hashes.SHA1
- )
}
diff --git a/src/dynamodb_encryption_sdk/internal/formatting/deserialize/__init__.py b/src/dynamodb_encryption_sdk/internal/formatting/deserialize/__init__.py
index 6e58c9bc..7fb0dd52 100644
--- a/src/dynamodb_encryption_sdk/internal/formatting/deserialize/__init__.py
+++ b/src/dynamodb_encryption_sdk/internal/formatting/deserialize/__init__.py
@@ -20,7 +20,7 @@
from dynamodb_encryption_sdk.exceptions import DeserializationError
-__all__ = ('unpack_value', 'decode_length', 'decode_value', 'decode_tag')
+__all__ = ("unpack_value", "decode_length", "decode_value", "decode_tag")
def unpack_value(format_string, stream):
@@ -44,7 +44,7 @@ def decode_length(stream):
:returns: Decoded length
:rtype: int
"""
- (value,) = unpack_value('>I', stream)
+ (value,) = unpack_value(">I", stream)
return value
@@ -57,7 +57,7 @@ def decode_value(stream):
:rtype: bytes
"""
length = decode_length(stream)
- (value,) = unpack_value('>{:d}s'.format(length), stream)
+ (value,) = unpack_value(">{:d}s".format(length), stream)
return value
@@ -69,7 +69,7 @@ def decode_byte(stream):
:returns: Decoded value
:rtype: bytes
"""
- (value,) = unpack_value('>1s', stream)
+ (value,) = unpack_value(">1s", stream)
return value
@@ -81,9 +81,9 @@ def decode_tag(stream):
:returns: Decoded tag
:rtype: bytes
"""
- (reserved, tag) = unpack_value('>cc', stream)
+ (reserved, tag) = unpack_value(">cc", stream)
- if reserved != b'\x00':
- raise DeserializationError('Invalid tag: reserved byte is not null')
+ if reserved != b"\x00":
+ raise DeserializationError("Invalid tag: reserved byte is not null")
return tag
diff --git a/src/dynamodb_encryption_sdk/internal/formatting/deserialize/attribute.py b/src/dynamodb_encryption_sdk/internal/formatting/deserialize/attribute.py
index 795be8ca..13fe0d7b 100644
--- a/src/dynamodb_encryption_sdk/internal/formatting/deserialize/attribute.py
+++ b/src/dynamodb_encryption_sdk/internal/formatting/deserialize/attribute.py
@@ -17,10 +17,18 @@
namespace staying consistent. Directly reference at your own risk.
"""
import codecs
-from decimal import Decimal
import io
import logging
import struct
+from decimal import Decimal
+
+from boto3.dynamodb.types import Binary
+
+from dynamodb_encryption_sdk.exceptions import DeserializationError
+from dynamodb_encryption_sdk.identifiers import LOGGER_NAME
+from dynamodb_encryption_sdk.internal.formatting.deserialize import decode_byte, decode_length, decode_tag, decode_value
+from dynamodb_encryption_sdk.internal.identifiers import TEXT_ENCODING, Tag, TagValues
+from dynamodb_encryption_sdk.internal.str_ops import to_str
try: # Python 3.5.0 and 3.5.1 have incompatible typing modules
from typing import Callable, Dict, List, Text, Union # noqa pylint: disable=unused-import
@@ -29,15 +37,8 @@
# We only actually need these imports when running the mypy checks
pass
-from boto3.dynamodb.types import Binary
-
-from dynamodb_encryption_sdk.exceptions import DeserializationError
-from dynamodb_encryption_sdk.identifiers import LOGGER_NAME
-from dynamodb_encryption_sdk.internal.formatting.deserialize import decode_byte, decode_length, decode_tag, decode_value
-from dynamodb_encryption_sdk.internal.identifiers import Tag, TagValues, TEXT_ENCODING
-from dynamodb_encryption_sdk.internal.str_ops import to_str
-__all__ = ('deserialize_attribute',)
+__all__ = ("deserialize_attribute",)
_LOGGER = logging.getLogger(LOGGER_NAME)
@@ -101,7 +102,7 @@ def _transform_number_value(value):
"""
raw_value = codecs.decode(value, TEXT_ENCODING)
decimal_value = Decimal(to_str(raw_value)).normalize()
- return '{0:f}'.format(decimal_value)
+ return "{0:f}".format(decimal_value)
def _deserialize_number(stream):
# type: (io.BytesIO) -> Dict[Text, dynamodb_types.STRING]
@@ -114,10 +115,7 @@ def _deserialize_number(stream):
value = decode_value(stream)
return {Tag.NUMBER.dynamodb_tag: _transform_number_value(value)}
- _boolean_map = {
- TagValues.FALSE.value: False,
- TagValues.TRUE.value: True
- }
+ _boolean_map = {TagValues.FALSE.value: False, TagValues.TRUE.value: True}
def _deserialize_boolean(stream):
# type: (io.BytesIO) -> Dict[Text, dynamodb_types.BOOLEAN]
@@ -149,10 +147,7 @@ def _deserialize_set(stream, member_transform):
:rtype: list
"""
member_count = decode_length(stream)
- return sorted([
- member_transform(decode_value(stream))
- for _ in range(member_count)
- ])
+ return sorted([member_transform(decode_value(stream)) for _ in range(member_count)])
def _deserialize_binary_set(stream):
# type: (io.BytesIO) -> Dict[Text, dynamodb_types.SET[dynamodb_types.BINARY]]
@@ -193,10 +188,7 @@ def _deserialize_list(stream):
:rtype: dict
"""
member_count = decode_length(stream)
- return {Tag.LIST.dynamodb_tag: [
- _deserialize(stream)
- for _ in range(member_count)
- ]}
+ return {Tag.LIST.dynamodb_tag: [_deserialize(stream) for _ in range(member_count)]}
def _deserialize_map(stream):
# type: (io.BytesIO) -> Dict[Text, dynamodb_types.MAP]
@@ -238,7 +230,7 @@ def _deserialize_function(tag):
Tag.BOOLEAN.tag: _deserialize_boolean,
Tag.NULL.tag: _deserialize_null,
Tag.LIST.tag: _deserialize_list,
- Tag.MAP.tag: _deserialize_map
+ Tag.MAP.tag: _deserialize_map,
}
try:
return deserialize_functions[tag]
@@ -257,10 +249,10 @@ def _deserialize(stream):
tag = decode_tag(stream)
return _deserialize_function(tag)(stream)
except struct.error:
- raise DeserializationError('Malformed serialized data')
+ raise DeserializationError("Malformed serialized data")
if not serialized_attribute:
- raise DeserializationError('Empty serialized attribute data')
+ raise DeserializationError("Empty serialized attribute data")
stream = io.BytesIO(serialized_attribute)
return _deserialize(stream)
diff --git a/src/dynamodb_encryption_sdk/internal/formatting/material_description.py b/src/dynamodb_encryption_sdk/internal/formatting/material_description.py
index 004b80e6..aa0114c8 100644
--- a/src/dynamodb_encryption_sdk/internal/formatting/material_description.py
+++ b/src/dynamodb_encryption_sdk/internal/formatting/material_description.py
@@ -20,6 +20,14 @@
import logging
import struct
+from dynamodb_encryption_sdk.exceptions import InvalidMaterialDescriptionError, InvalidMaterialDescriptionVersionError
+from dynamodb_encryption_sdk.identifiers import LOGGER_NAME
+from dynamodb_encryption_sdk.internal.identifiers import Tag
+from dynamodb_encryption_sdk.internal.str_ops import to_bytes, to_str
+
+from .deserialize import decode_value, unpack_value
+from .serialize import encode_value
+
try: # Python 3.5.0 and 3.5.1 have incompatible typing modules
from typing import Dict, Text # noqa pylint: disable=unused-import
from dynamodb_encryption_sdk.internal import dynamodb_types # noqa pylint: disable=unused-import
@@ -27,16 +35,10 @@
# We only actually need these imports when running the mypy checks
pass
-from dynamodb_encryption_sdk.exceptions import InvalidMaterialDescriptionError, InvalidMaterialDescriptionVersionError
-from dynamodb_encryption_sdk.identifiers import LOGGER_NAME
-from dynamodb_encryption_sdk.internal.identifiers import Tag
-from dynamodb_encryption_sdk.internal.str_ops import to_bytes, to_str
-from .deserialize import decode_value, unpack_value
-from .serialize import encode_value
-__all__ = ('serialize', 'deserialize')
+__all__ = ("serialize", "deserialize")
_LOGGER = logging.getLogger(LOGGER_NAME)
-_MATERIAL_DESCRIPTION_VERSION = b'\00' * 4
+_MATERIAL_DESCRIPTION_VERSION = b"\00" * 4
def serialize(material_description):
@@ -57,10 +59,7 @@ def serialize(material_description):
material_description_bytes.extend(encode_value(to_bytes(value)))
except (TypeError, struct.error):
raise InvalidMaterialDescriptionError(
- 'Invalid name or value in material description: "{name}"="{value}"'.format(
- name=name,
- value=value
- )
+ 'Invalid name or value in material description: "{name}"="{value}"'.format(name=name, value=value)
)
return {Tag.BINARY.dynamodb_tag: bytes(material_description_bytes)}
@@ -82,7 +81,7 @@ def deserialize(serialized_material_description):
material_description_bytes = io.BytesIO(_raw_material_description)
total_bytes = len(_raw_material_description)
except (TypeError, KeyError):
- message = 'Invalid material description'
+ message = "Invalid material description"
_LOGGER.exception(message)
raise InvalidMaterialDescriptionError(message)
# We don't currently do anything with the version, but do check to make sure it is the one we know about.
@@ -95,7 +94,7 @@ def deserialize(serialized_material_description):
value = to_str(decode_value(material_description_bytes))
material_description[name] = value
except struct.error:
- message = 'Invalid material description'
+ message = "Invalid material description"
_LOGGER.exception(message)
raise InvalidMaterialDescriptionError(message)
return material_description
@@ -111,10 +110,10 @@ def _read_version(material_description_bytes):
:raises InvalidMaterialDescriptionVersionError: if unknown version is found
"""
try:
- (version,) = unpack_value('>4s', material_description_bytes)
+ (version,) = unpack_value(">4s", material_description_bytes)
except struct.error:
- message = 'Malformed material description version'
+ message = "Malformed material description version"
_LOGGER.exception(message)
raise InvalidMaterialDescriptionError(message)
if version != _MATERIAL_DESCRIPTION_VERSION:
- raise InvalidMaterialDescriptionVersionError('Invalid material description version: {}'.format(repr(version)))
+ raise InvalidMaterialDescriptionVersionError("Invalid material description version: {}".format(repr(version)))
diff --git a/src/dynamodb_encryption_sdk/internal/formatting/serialize/__init__.py b/src/dynamodb_encryption_sdk/internal/formatting/serialize/__init__.py
index 9e1723a2..1c7f7ee2 100644
--- a/src/dynamodb_encryption_sdk/internal/formatting/serialize/__init__.py
+++ b/src/dynamodb_encryption_sdk/internal/formatting/serialize/__init__.py
@@ -24,7 +24,7 @@
# We only actually need these imports when running the mypy checks
pass
-__all__ = ('encode_length', 'encode_value')
+__all__ = ("encode_length", "encode_value")
def encode_length(attribute):
@@ -35,7 +35,7 @@ def encode_length(attribute):
:returns: Encoded value
:rtype: bytes
"""
- return struct.pack('>I', len(attribute))
+ return struct.pack(">I", len(attribute))
def encode_value(value):
@@ -47,8 +47,4 @@ def encode_value(value):
:returns: Length-Value encoded value
:rtype: bytes
"""
- return struct.pack(
- '>I{attr_len:d}s'.format(attr_len=len(value)),
- len(value),
- value
- )
+ return struct.pack(">I{attr_len:d}s".format(attr_len=len(value)), len(value), value)
diff --git a/src/dynamodb_encryption_sdk/internal/formatting/serialize/attribute.py b/src/dynamodb_encryption_sdk/internal/formatting/serialize/attribute.py
index 2b4f5cca..cf2cca83 100644
--- a/src/dynamodb_encryption_sdk/internal/formatting/serialize/attribute.py
+++ b/src/dynamodb_encryption_sdk/internal/formatting/serialize/attribute.py
@@ -19,6 +19,14 @@
import io
import logging
+from boto3.dynamodb.types import DYNAMODB_CONTEXT, Binary
+
+from dynamodb_encryption_sdk.exceptions import SerializationError
+from dynamodb_encryption_sdk.identifiers import LOGGER_NAME
+from dynamodb_encryption_sdk.internal.formatting.serialize import encode_length, encode_value
+from dynamodb_encryption_sdk.internal.identifiers import Tag, TagValues
+from dynamodb_encryption_sdk.internal.str_ops import to_bytes
+
try: # Python 3.5.0 and 3.5.1 have incompatible typing modules
from typing import Callable # noqa pylint: disable=unused-import
from dynamodb_encryption_sdk.internal import dynamodb_types # noqa pylint: disable=unused-import,ungrouped-imports
@@ -26,17 +34,10 @@
# We only actually need these imports when running the mypy checks
pass
-from boto3.dynamodb.types import Binary, DYNAMODB_CONTEXT
-from dynamodb_encryption_sdk.exceptions import SerializationError
-from dynamodb_encryption_sdk.identifiers import LOGGER_NAME
-from dynamodb_encryption_sdk.internal.formatting.serialize import encode_length, encode_value
-from dynamodb_encryption_sdk.internal.identifiers import Tag, TagValues
-from dynamodb_encryption_sdk.internal.str_ops import to_bytes
-
-__all__ = ('serialize_attribute',)
+__all__ = ("serialize_attribute",)
_LOGGER = logging.getLogger(LOGGER_NAME)
-_RESERVED = b'\x00'
+_RESERVED = b"\x00"
def _sorted_key_map(item, transform=to_bytes):
@@ -99,7 +100,7 @@ def _transform_number_value(value):
# leaves trailing zeros if they are defined in the Decimal call, but we need to
# strip all trailing zeros.
decimal_value = DYNAMODB_CONTEXT.create_decimal(value).normalize()
- return '{0:f}'.format(decimal_value).encode('utf-8')
+ return "{0:f}".format(decimal_value).encode("utf-8")
def _serialize_number(_attribute):
# type: (str) -> bytes
@@ -228,10 +229,7 @@ def _serialize_map(_attribute):
serialized_attribute.write(Tag.MAP.tag)
serialized_attribute.write(encode_length(_attribute))
- sorted_items = _sorted_key_map(
- item=_attribute,
- transform=_transform_string_value
- )
+ sorted_items = _sorted_key_map(item=_attribute, transform=_transform_string_value)
for key, value, _original_key in sorted_items:
serialized_attribute.write(_serialize_string(key))
@@ -252,7 +250,7 @@ def _serialize_function(dynamodb_tag):
Tag.BOOLEAN.dynamodb_tag: _serialize_boolean,
Tag.NULL.dynamodb_tag: _serialize_null,
Tag.LIST.dynamodb_tag: _serialize_list,
- Tag.MAP.dynamodb_tag: _serialize_map
+ Tag.MAP.dynamodb_tag: _serialize_map,
}
try:
return serialize_functions[dynamodb_tag]
@@ -263,8 +261,8 @@ def _serialize_function(dynamodb_tag):
raise TypeError('Invalid attribute type "{}": must be dict'.format(type(attribute)))
if len(attribute) != 1:
- raise SerializationError('cannot serialize attribute: incorrect number of members {} != 1'.format(
- len(attribute)
- ))
+ raise SerializationError(
+ "cannot serialize attribute: incorrect number of members {} != 1".format(len(attribute))
+ )
key, value = list(attribute.items())[0]
return _serialize_function(key)(value)
diff --git a/src/dynamodb_encryption_sdk/internal/identifiers.py b/src/dynamodb_encryption_sdk/internal/identifiers.py
index 750edcc2..80183870 100644
--- a/src/dynamodb_encryption_sdk/internal/identifiers.py
+++ b/src/dynamodb_encryption_sdk/internal/identifiers.py
@@ -25,35 +25,40 @@
pass
__all__ = (
- 'ReservedAttributes', 'Tag', 'TagValues', 'TEXT_ENCODING',
- 'SignatureValues', 'MaterialDescriptionKeys', 'MaterialDescriptionValues'
+ "ReservedAttributes",
+ "Tag",
+ "TagValues",
+ "TEXT_ENCODING",
+ "SignatureValues",
+ "MaterialDescriptionKeys",
+ "MaterialDescriptionValues",
)
#: Encoding to use for all text values.
#: This is noted here for consistency but should not be changed.
-TEXT_ENCODING = 'utf-8'
+TEXT_ENCODING = "utf-8"
class ReservedAttributes(Enum):
"""Item attributes reserved for use by DynamoDBEncryptionClient"""
- MATERIAL_DESCRIPTION = '*amzn-ddb-map-desc*'
- SIGNATURE = '*amzn-ddb-map-sig*'
+ MATERIAL_DESCRIPTION = "*amzn-ddb-map-desc*"
+ SIGNATURE = "*amzn-ddb-map-sig*"
class Tag(Enum):
"""Attribute data type identifiers used for serialization and deserialization of attributes."""
- BINARY = (b'b', 'B')
- BINARY_SET = (b'B', 'BS', b'b')
- NUMBER = (b'n', 'N')
- NUMBER_SET = (b'N', 'NS', b'n')
- STRING = (b's', 'S')
- STRING_SET = (b'S', 'SS', b's')
- BOOLEAN = (b'?', 'BOOL')
- NULL = (b'\x00', 'NULL')
- LIST = (b'L', 'L')
- MAP = (b'M', 'M')
+ BINARY = (b"b", "B")
+ BINARY_SET = (b"B", "BS", b"b")
+ NUMBER = (b"n", "N")
+ NUMBER_SET = (b"N", "NS", b"n")
+ STRING = (b"s", "S")
+ STRING_SET = (b"S", "SS", b"s")
+ BOOLEAN = (b"?", "BOOL")
+ NULL = (b"\x00", "NULL")
+ LIST = (b"L", "L")
+ MAP = (b"M", "M")
def __init__(self, tag, dynamodb_tag, element_tag=None):
# type: (bytes, Text, Optional[bytes]) -> None
@@ -71,8 +76,8 @@ def __init__(self, tag, dynamodb_tag, element_tag=None):
class TagValues(Enum):
"""Static values to use when serializing attribute values."""
- FALSE = b'\x00'
- TRUE = b'\x01'
+ FALSE = b"\x00"
+ TRUE = b"\x01"
class SignatureValues(Enum):
@@ -85,12 +90,12 @@ class SignatureValues(Enum):
"""
ENCRYPTED = (
- b'ENCRYPTED',
- b"9A\x15\xacN\xb0\x9a\xa4\x94)4\x88\x16\xb2\x03\x81'\xb0\xf9\xe3\xa5 7*\xe1\x00\xca\x19\xfb\x08\xfdP"
+ b"ENCRYPTED",
+ b"9A\x15\xacN\xb0\x9a\xa4\x94)4\x88\x16\xb2\x03\x81'\xb0\xf9\xe3\xa5 7*\xe1\x00\xca\x19\xfb\x08\xfdP",
)
PLAINTEXT = (
- b'PLAINTEXT',
- b'\xcb@\xe7\xda\xdc\x86\x16\x1b\x97\x98\xdeHQ/3-!\xc1A\xfc\xc1\xe2\x8a\x08o\xdeJ3u\xaa\xb1\xb5'
+ b"PLAINTEXT",
+ b"\xcb@\xe7\xda\xdc\x86\x16\x1b\x97\x98\xdeHQ/3-!\xc1A\xfc\xc1\xe2\x8a\x08o\xdeJ3u\xaa\xb1\xb5",
)
def __init__(self, raw, sha256):
@@ -107,15 +112,15 @@ def __init__(self, raw, sha256):
class MaterialDescriptionKeys(Enum):
"""Static keys for use when building and reading material descriptions."""
- ATTRIBUTE_ENCRYPTION_MODE = 'amzn-ddb-map-sym-mode'
- SIGNING_KEY_ALGORITHM = 'amzn-ddb-map-signingAlg'
- WRAPPED_DATA_KEY = 'amzn-ddb-env-key'
- CONTENT_ENCRYPTION_ALGORITHM = 'amzn-ddb-env-alg'
- CONTENT_KEY_WRAPPING_ALGORITHM = 'amzn-ddb-wrap-alg'
- ITEM_SIGNATURE_ALGORITHM = 'amzn-ddb-sig-alg'
+ ATTRIBUTE_ENCRYPTION_MODE = "amzn-ddb-map-sym-mode"
+ SIGNING_KEY_ALGORITHM = "amzn-ddb-map-signingAlg"
+ WRAPPED_DATA_KEY = "amzn-ddb-env-key"
+ CONTENT_ENCRYPTION_ALGORITHM = "amzn-ddb-env-alg"
+ CONTENT_KEY_WRAPPING_ALGORITHM = "amzn-ddb-wrap-alg"
+ ITEM_SIGNATURE_ALGORITHM = "amzn-ddb-sig-alg"
class MaterialDescriptionValues(Enum):
"""Static default values for use when building material descriptions."""
- CBC_PKCS5_ATTRIBUTE_ENCRYPTION = '/CBC/PKCS5Padding'
+ CBC_PKCS5_ATTRIBUTE_ENCRYPTION = "/CBC/PKCS5Padding"
diff --git a/src/dynamodb_encryption_sdk/internal/str_ops.py b/src/dynamodb_encryption_sdk/internal/str_ops.py
index c72e42b4..561c6ad4 100644
--- a/src/dynamodb_encryption_sdk/internal/str_ops.py
+++ b/src/dynamodb_encryption_sdk/internal/str_ops.py
@@ -22,7 +22,7 @@
from dynamodb_encryption_sdk.internal.identifiers import TEXT_ENCODING
-__all__ = ('to_str', 'to_bytes')
+__all__ = ("to_str", "to_bytes")
def to_str(data):
diff --git a/src/dynamodb_encryption_sdk/internal/utils.py b/src/dynamodb_encryption_sdk/internal/utils.py
index 33a92a93..6b1ee127 100644
--- a/src/dynamodb_encryption_sdk/internal/utils.py
+++ b/src/dynamodb_encryption_sdk/internal/utils.py
@@ -32,11 +32,16 @@
pass
__all__ = (
- 'TableInfoCache',
- 'crypto_config_from_kwargs', 'crypto_config_from_table_info', 'crypto_config_from_cache',
- 'decrypt_get_item', 'decrypt_multi_get', 'decrypt_batch_get_item',
- 'encrypt_put_item', 'encrypt_batch_write_item',
- 'validate_get_arguments'
+ "TableInfoCache",
+ "crypto_config_from_kwargs",
+ "crypto_config_from_table_info",
+ "crypto_config_from_cache",
+ "decrypt_get_item",
+ "decrypt_multi_get",
+ "decrypt_batch_get_item",
+ "encrypt_put_item",
+ "encrypt_batch_write_item",
+ "validate_get_arguments",
)
@@ -55,9 +60,7 @@ class TableInfoCache(object):
_auto_refresh_table_indexes = attr.ib(validator=attr.validators.instance_of(bool))
def __init__(
- self,
- client, # type: botocore.client.BaseClient
- auto_refresh_table_indexes # type: bool
+ self, client, auto_refresh_table_indexes # type: botocore.client.BaseClient # type: bool
): # noqa=D107
# type: (...) -> None
# Workaround pending resolution of attrs/mypy interaction.
@@ -96,12 +99,12 @@ def validate_get_arguments(kwargs):
:raises InvalidArgumentError: if banned parameters are found
"""
- for arg in ('AttributesToGet', 'ProjectionExpression'):
+ for arg in ("AttributesToGet", "ProjectionExpression"):
if arg in kwargs:
raise InvalidArgumentError('"{}" is not supported for this operation'.format(arg))
- if kwargs.get('Select', None) in ('SPECIFIC_ATTRIBUTES', 'ALL_PROJECTED_ATTRIBUTES'):
- raise InvalidArgumentError('Scan "Select" value of "{}" is not supported'.format(kwargs['Select']))
+ if kwargs.get("Select", None) in ("SPECIFIC_ATTRIBUTES", "ALL_PROJECTED_ATTRIBUTES"):
+ raise InvalidArgumentError('Scan "Select" value of "{}" is not supported'.format(kwargs["Select"]))
def crypto_config_from_kwargs(fallback, **kwargs):
@@ -111,10 +114,10 @@ def crypto_config_from_kwargs(fallback, **kwargs):
:rtype: dynamodb_encryption_sdk.encrypted.CryptoConfig and dict
"""
try:
- crypto_config = kwargs.pop('crypto_config')
+ crypto_config = kwargs.pop("crypto_config")
except KeyError:
try:
- fallback_kwargs = {'table_name': kwargs['TableName']}
+ fallback_kwargs = {"table_name": kwargs["TableName"]}
except KeyError:
fallback_kwargs = {}
crypto_config = fallback(**fallback_kwargs)
@@ -129,15 +132,14 @@ def crypto_config_from_table_info(materials_provider, attribute_actions, table_i
"""
ec_kwargs = table_info.encryption_context_values
if table_info.primary_index is not None:
- ec_kwargs.update({
- 'partition_key_name': table_info.primary_index.partition,
- 'sort_key_name': table_info.primary_index.sort
- })
+ ec_kwargs.update(
+ {"partition_key_name": table_info.primary_index.partition, "sort_key_name": table_info.primary_index.sort}
+ )
return CryptoConfig(
materials_provider=materials_provider,
encryption_context=EncryptionContext(**ec_kwargs),
- attribute_actions=attribute_actions
+ attribute_actions=attribute_actions,
)
@@ -183,10 +185,10 @@ def decrypt_multi_get(decrypt_method, crypto_config_method, read_method, **kwarg
validate_get_arguments(kwargs)
crypto_config, ddb_kwargs = crypto_config_method(**kwargs)
response = read_method(**ddb_kwargs)
- for pos in range(len(response['Items'])):
- response['Items'][pos] = decrypt_method(
- item=response['Items'][pos],
- crypto_config=crypto_config.with_item(_item_transformer(decrypt_method)(response['Items'][pos]))
+ for pos in range(len(response["Items"])):
+ response["Items"][pos] = decrypt_method(
+ item=response["Items"][pos],
+ crypto_config=crypto_config.with_item(_item_transformer(decrypt_method)(response["Items"][pos])),
)
return response
@@ -206,10 +208,10 @@ def decrypt_get_item(decrypt_method, crypto_config_method, read_method, **kwargs
validate_get_arguments(kwargs)
crypto_config, ddb_kwargs = crypto_config_method(**kwargs)
response = read_method(**ddb_kwargs)
- if 'Item' in response:
- response['Item'] = decrypt_method(
- item=response['Item'],
- crypto_config=crypto_config.with_item(_item_transformer(decrypt_method)(response['Item']))
+ if "Item" in response:
+ response["Item"] = decrypt_method(
+ item=response["Item"],
+ crypto_config=crypto_config.with_item(_item_transformer(decrypt_method)(response["Item"])),
)
return response
@@ -226,13 +228,13 @@ def decrypt_batch_get_item(decrypt_method, crypto_config_method, read_method, **
:return: DynamoDB response
:rtype: dict
"""
- request_crypto_config = kwargs.pop('crypto_config', None)
+ request_crypto_config = kwargs.pop("crypto_config", None)
- for _table_name, table_kwargs in kwargs['RequestItems'].items():
+ for _table_name, table_kwargs in kwargs["RequestItems"].items():
validate_get_arguments(table_kwargs)
response = read_method(**kwargs)
- for table_name, items in response['Responses'].items():
+ for table_name, items in response["Responses"].items():
if request_crypto_config is not None:
crypto_config = request_crypto_config
else:
@@ -240,8 +242,7 @@ def decrypt_batch_get_item(decrypt_method, crypto_config_method, read_method, **
for pos, value in enumerate(items):
items[pos] = decrypt_method(
- item=value,
- crypto_config=crypto_config.with_item(_item_transformer(decrypt_method)(items[pos]))
+ item=value, crypto_config=crypto_config.with_item(_item_transformer(decrypt_method)(items[pos]))
)
return response
@@ -259,9 +260,9 @@ def encrypt_put_item(encrypt_method, crypto_config_method, write_method, **kwarg
:rtype: dict
"""
crypto_config, ddb_kwargs = crypto_config_method(**kwargs)
- ddb_kwargs['Item'] = encrypt_method(
- item=ddb_kwargs['Item'],
- crypto_config=crypto_config.with_item(_item_transformer(encrypt_method)(ddb_kwargs['Item']))
+ ddb_kwargs["Item"] = encrypt_method(
+ item=ddb_kwargs["Item"],
+ crypto_config=crypto_config.with_item(_item_transformer(encrypt_method)(ddb_kwargs["Item"])),
)
return write_method(**ddb_kwargs)
@@ -278,9 +279,9 @@ def encrypt_batch_write_item(encrypt_method, crypto_config_method, write_method,
:return: DynamoDB response
:rtype: dict
"""
- request_crypto_config = kwargs.pop('crypto_config', None)
+ request_crypto_config = kwargs.pop("crypto_config", None)
- for table_name, items in kwargs['RequestItems'].items():
+ for table_name, items in kwargs["RequestItems"].items():
if request_crypto_config is not None:
crypto_config = request_crypto_config
else:
@@ -289,9 +290,9 @@ def encrypt_batch_write_item(encrypt_method, crypto_config_method, write_method,
for pos, value in enumerate(items):
for request_type, item in value.items():
# We don't encrypt primary indexes, so we can ignore DeleteItem requests
- if request_type == 'PutRequest':
- items[pos][request_type]['Item'] = encrypt_method(
- item=item['Item'],
- crypto_config=crypto_config.with_item(_item_transformer(encrypt_method)(item['Item']))
+ if request_type == "PutRequest":
+ items[pos][request_type]["Item"] = encrypt_method(
+ item=item["Item"],
+ crypto_config=crypto_config.with_item(_item_transformer(encrypt_method)(item["Item"])),
)
return write_method(**kwargs)
diff --git a/src/dynamodb_encryption_sdk/internal/validators.py b/src/dynamodb_encryption_sdk/internal/validators.py
index bc33757d..09f1b4f3 100644
--- a/src/dynamodb_encryption_sdk/internal/validators.py
+++ b/src/dynamodb_encryption_sdk/internal/validators.py
@@ -17,7 +17,7 @@
namespace staying consistent. Directly reference at your own risk.
"""
-__all__ = ('dictionary_validator', 'iterable_validator')
+__all__ = ("dictionary_validator", "iterable_validator")
def dictionary_validator(key_type, value_type):
@@ -36,16 +36,14 @@ def _validate_dictionary(instance, attribute, value):
for key, data in value.items():
if not isinstance(key, key_type):
- raise TypeError('"{name}" dictionary keys must be of type "{type}"'.format(
- name=attribute.name,
- type=key_type
- ))
+ raise TypeError(
+ '"{name}" dictionary keys must be of type "{type}"'.format(name=attribute.name, type=key_type)
+ )
if not isinstance(data, value_type):
- raise TypeError('"{name}" dictionary values must be of type "{type}"'.format(
- name=attribute.name,
- type=value_type
- ))
+ raise TypeError(
+ '"{name}" dictionary values must be of type "{type}"'.format(name=attribute.name, type=value_type)
+ )
return _validate_dictionary
@@ -61,17 +59,13 @@ def _validate_tuple(instance, attribute, value):
:raises TypeError: if ``value`` members are not all of ``member_type`` type
"""
if not isinstance(value, iterable_type):
- raise TypeError('"{name}" must be a {type}'.format(
- name=attribute.name,
- type=iterable_type
- ))
+ raise TypeError('"{name}" must be a {type}'.format(name=attribute.name, type=iterable_type))
for member in value:
if not isinstance(member, member_type):
- raise TypeError('"{name}" members must all be of type "{type}"'.format(
- name=attribute.name,
- type=member_type
- ))
+ raise TypeError(
+ '"{name}" members must all be of type "{type}"'.format(name=attribute.name, type=member_type)
+ )
return _validate_tuple
@@ -83,7 +77,4 @@ def callable_validator(instance, attribute, value):
:raises TypeError: if ``value`` is not callable
"""
if not callable(value):
- raise TypeError('"{name}" value "{value}" must be callable'.format(
- name=attribute.name,
- value=value
- ))
+ raise TypeError('"{name}" value "{value}" must be callable'.format(name=attribute.name, value=value))
diff --git a/src/dynamodb_encryption_sdk/material_providers/__init__.py b/src/dynamodb_encryption_sdk/material_providers/__init__.py
index 6be6a41c..e3ddab68 100644
--- a/src/dynamodb_encryption_sdk/material_providers/__init__.py
+++ b/src/dynamodb_encryption_sdk/material_providers/__init__.py
@@ -14,7 +14,7 @@
from dynamodb_encryption_sdk.materials import CryptographicMaterials # noqa pylint: disable=unused-import
from dynamodb_encryption_sdk.structures import EncryptionContext # noqa pylint: disable=unused-import
-__all__ = ('CryptographicMaterialsProvider',)
+__all__ = ("CryptographicMaterialsProvider",)
class CryptographicMaterialsProvider(object):
@@ -28,7 +28,7 @@ def decryption_materials(self, encryption_context):
:param EncryptionContext encryption_context: Encryption context for request
:raises AttributeError: if no decryption materials are available
"""
- raise AttributeError('No decryption materials available')
+ raise AttributeError("No decryption materials available")
def encryption_materials(self, encryption_context):
# type: (EncryptionContext) -> CryptographicMaterials
@@ -38,7 +38,7 @@ def encryption_materials(self, encryption_context):
:param EncryptionContext encryption_context: Encryption context for request
:raises AttributeError: if no encryption materials are available
"""
- raise AttributeError('No encryption materials available')
+ raise AttributeError("No encryption materials available")
def refresh(self):
# type: () -> None
diff --git a/src/dynamodb_encryption_sdk/material_providers/aws_kms.py b/src/dynamodb_encryption_sdk/material_providers/aws_kms.py
index a1ecd486..e5e288d0 100644
--- a/src/dynamodb_encryption_sdk/material_providers/aws_kms.py
+++ b/src/dynamodb_encryption_sdk/material_providers/aws_kms.py
@@ -14,60 +14,62 @@
from __future__ import division
import base64
-from enum import Enum
import logging
+from enum import Enum
import attr
import boto3
import botocore
+import six
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.kdf.hkdf import HKDF
-import six
-
-try: # Python 3.5.0 and 3.5.1 have incompatible typing modules
- from dynamodb_encryption_sdk.internal import dynamodb_types # noqa pylint: disable=unused-import
- from typing import Dict, Optional, Text, Tuple # noqa pylint: disable=unused-import
-except ImportError: # pragma: no cover
- # We only actually need these imports when running the mypy checks
- pass
from dynamodb_encryption_sdk.delegated_keys.jce import JceNameLocalDelegatedKey
from dynamodb_encryption_sdk.exceptions import UnknownRegionError, UnwrappingError, WrappingError
-from dynamodb_encryption_sdk.identifiers import EncryptionKeyType, KeyEncodingType, LOGGER_NAME, USER_AGENT_SUFFIX
-from dynamodb_encryption_sdk.internal.identifiers import MaterialDescriptionKeys, TEXT_ENCODING
+from dynamodb_encryption_sdk.identifiers import LOGGER_NAME, USER_AGENT_SUFFIX, EncryptionKeyType, KeyEncodingType
+from dynamodb_encryption_sdk.internal.identifiers import TEXT_ENCODING, MaterialDescriptionKeys
from dynamodb_encryption_sdk.internal.str_ops import to_bytes, to_str
from dynamodb_encryption_sdk.internal.validators import dictionary_validator, iterable_validator
from dynamodb_encryption_sdk.materials.raw import RawDecryptionMaterials, RawEncryptionMaterials
from dynamodb_encryption_sdk.structures import EncryptionContext # noqa pylint: disable=unused-import
+
from . import CryptographicMaterialsProvider
-__all__ = ('AwsKmsCryptographicMaterialsProvider',)
+try: # Python 3.5.0 and 3.5.1 have incompatible typing modules
+ from dynamodb_encryption_sdk.internal import dynamodb_types # noqa pylint: disable=unused-import
+ from typing import Dict, Optional, Text, Tuple # noqa pylint: disable=unused-import
+except ImportError: # pragma: no cover
+ # We only actually need these imports when running the mypy checks
+ pass
+
+
+__all__ = ("AwsKmsCryptographicMaterialsProvider",)
_LOGGER = logging.getLogger(LOGGER_NAME)
-_COVERED_ATTR_CTX_KEY = 'aws-kms-ec-attr'
-_TABLE_NAME_EC_KEY = '*aws-kms-table*'
-_DEFAULT_CONTENT_ENCRYPTION_ALGORITHM = 'AES/256'
+_COVERED_ATTR_CTX_KEY = "aws-kms-ec-attr"
+_TABLE_NAME_EC_KEY = "*aws-kms-table*"
+_DEFAULT_CONTENT_ENCRYPTION_ALGORITHM = "AES/256"
_DEFAULT_CONTENT_KEY_LENGTH = 256
-_DEFAULT_SIGNING_ALGORITHM = 'HmacSHA256/256'
+_DEFAULT_SIGNING_ALGORITHM = "HmacSHA256/256"
_DEFAULT_SIGNING_KEY_LENGTH = 256
-_KEY_COVERAGE = '*keys*'
-_KDF_ALG = 'HmacSHA256'
+_KEY_COVERAGE = "*keys*"
+_KDF_ALG = "HmacSHA256"
class HkdfInfo(Enum):
"""Info strings used for HKDF calculations."""
- ENCRYPTION = b'Encryption'
- SIGNING = b'Signing'
+ ENCRYPTION = b"Encryption"
+ SIGNING = b"Signing"
class EncryptionContextKeys(Enum):
"""Special keys for use in the AWS KMS encryption context."""
- CONTENT_ENCRYPTION_ALGORITHM = '*' + MaterialDescriptionKeys.CONTENT_ENCRYPTION_ALGORITHM.value + '*'
- SIGNATURE_ALGORITHM = '*' + MaterialDescriptionKeys.ITEM_SIGNATURE_ALGORITHM.value + '*'
- TABLE_NAME = '*aws-kms-table*'
+ CONTENT_ENCRYPTION_ALGORITHM = "*" + MaterialDescriptionKeys.CONTENT_ENCRYPTION_ALGORITHM.value + "*"
+ SIGNATURE_ALGORITHM = "*" + MaterialDescriptionKeys.ITEM_SIGNATURE_ALGORITHM.value + "*"
+ TABLE_NAME = "*aws-kms-table*"
@attr.s(init=False)
@@ -84,12 +86,7 @@ class KeyInfo(object):
algorithm = attr.ib(validator=attr.validators.instance_of(six.string_types))
length = attr.ib(validator=attr.validators.instance_of(six.integer_types))
- def __init__(
- self,
- description, # type: Text
- algorithm, # type: Text
- length # type: int
- ): # noqa=D107
+ def __init__(self, description, algorithm, length): # type: Text # type: Text # type: int # noqa=D107
# type: (...) -> None
# Workaround pending resolution of attrs/mypy interaction.
# https://github.com/python/mypy/issues/2088
@@ -107,7 +104,7 @@ def from_description(cls, description, default_key_length=None):
:param str description: Key info description
:param int default_key_length: Key length to use if not found in description
"""
- description_parts = description.split('/', 1)
+ description_parts = description.split("/", 1)
algorithm = description_parts[0]
try:
key_length = int(description_parts[1])
@@ -159,29 +156,23 @@ class AwsKmsCryptographicMaterialsProvider(CryptographicMaterialsProvider):
_key_id = attr.ib(validator=attr.validators.instance_of(six.string_types))
_botocore_session = attr.ib(
- validator=attr.validators.instance_of(botocore.session.Session),
- default=attr.Factory(botocore.session.Session)
- )
- _grant_tokens = attr.ib(
- validator=iterable_validator(tuple, six.string_types),
- default=attr.Factory(tuple)
+ validator=attr.validators.instance_of(botocore.session.Session), default=attr.Factory(botocore.session.Session)
)
+ _grant_tokens = attr.ib(validator=iterable_validator(tuple, six.string_types), default=attr.Factory(tuple))
_material_description = attr.ib(
- validator=dictionary_validator(six.string_types, six.string_types),
- default=attr.Factory(dict)
+ validator=dictionary_validator(six.string_types, six.string_types), default=attr.Factory(dict)
)
_regional_clients = attr.ib(
- validator=dictionary_validator(six.string_types, botocore.client.BaseClient),
- default=attr.Factory(dict)
+ validator=dictionary_validator(six.string_types, botocore.client.BaseClient), default=attr.Factory(dict)
)
def __init__(
- self,
- key_id, # type: Text
- botocore_session=None, # type: Optional[botocore.session.Session]
- grant_tokens=None, # type: Optional[Tuple[Text]]
- material_description=None, # type: Optional[Dict[Text, Text]]
- regional_clients=None # type: Optional[Dict[Text, botocore.client.BaseClient]]
+ self,
+ key_id, # type: Text
+ botocore_session=None, # type: Optional[botocore.session.Session]
+ grant_tokens=None, # type: Optional[Tuple[Text]]
+ material_description=None, # type: Optional[Dict[Text, Text]]
+ regional_clients=None, # type: Optional[Dict[Text, botocore.client.BaseClient]]
): # noqa=D107
# type: (...) -> None
# Workaround pending resolution of attrs/mypy interaction.
@@ -215,13 +206,13 @@ def __attrs_post_init__(self):
material_description=self._material_description,
description_key=MaterialDescriptionKeys.CONTENT_ENCRYPTION_ALGORITHM.value,
default_algorithm=_DEFAULT_CONTENT_ENCRYPTION_ALGORITHM,
- default_key_length=_DEFAULT_CONTENT_KEY_LENGTH
+ default_key_length=_DEFAULT_CONTENT_KEY_LENGTH,
)
self._signing_key_info = KeyInfo.from_material_description( # pylint: disable=attribute-defined-outside-init
material_description=self._material_description,
description_key=MaterialDescriptionKeys.ITEM_SIGNATURE_ALGORITHM.value,
default_algorithm=_DEFAULT_SIGNING_ALGORITHM,
- default_key_length=_DEFAULT_SIGNING_KEY_LENGTH
+ default_key_length=_DEFAULT_SIGNING_KEY_LENGTH,
)
self._regional_clients = {} # type: Dict[Text, botocore.client.BaseClient] # noqa pylint: disable=attribute-defined-outside-init
@@ -233,9 +224,8 @@ def _add_regional_client(self, region_name):
"""
if region_name not in self._regional_clients:
self._regional_clients[region_name] = boto3.session.Session(
- region_name=region_name,
- botocore_session=self._botocore_session
- ).client('kms', config=self._user_agent_adding_config)
+ region_name=region_name, botocore_session=self._botocore_session
+ ).client("kms", config=self._user_agent_adding_config)
return self._regional_clients[region_name]
def _client(self, key_id):
@@ -246,13 +236,13 @@ def _client(self, key_id):
:rtype: botocore.client.KMS
"""
try:
- key_region = key_id.split(':', 4)[3]
+ key_region = key_id.split(":", 4)[3]
region = key_region
except IndexError:
- session_region = self._botocore_session.get_config_variable('region')
+ session_region = self._botocore_session.get_config_variable("region")
if session_region is None:
raise UnknownRegionError(
- 'No region determinable from key id: {} and no default region found in session'.format(key_id)
+ "No region determinable from key id: {} and no default region found in session".format(key_id)
)
region = session_region
return self._add_regional_client(region)
@@ -297,9 +287,9 @@ def _attribute_to_value(self, attribute):
:rtype: str
"""
attribute_type, attribute_value = list(attribute.items())[0]
- if attribute_type == 'B':
+ if attribute_type == "B":
return base64.b64encode(attribute_value).decode(TEXT_ENCODING)
- if attribute_type in ('S', 'N'):
+ if attribute_type in ("S", "N"):
return attribute_value
raise ValueError('Attribute of type "{}" cannot be used in KMS encryption context.'.format(attribute_type))
@@ -315,7 +305,7 @@ def _kms_encryption_context(self, encryption_context, encryption_description, si
"""
kms_encryption_context = {
EncryptionContextKeys.CONTENT_ENCRYPTION_ALGORITHM.value: encryption_description,
- EncryptionContextKeys.SIGNATURE_ALGORITHM.value: signing_description
+ EncryptionContextKeys.SIGNATURE_ALGORITHM.value: signing_description,
}
if encryption_context.partition_key_name is not None:
@@ -355,21 +345,17 @@ def _generate_initial_material(self, encryption_context):
kms_encryption_context = self._kms_encryption_context(
encryption_context=encryption_context,
encryption_description=self._content_key_info.description,
- signing_description=self._signing_key_info.description
- )
- kms_params = dict(
- KeyId=key_id,
- NumberOfBytes=key_length,
- EncryptionContext=kms_encryption_context
+ signing_description=self._signing_key_info.description,
)
+ kms_params = dict(KeyId=key_id, NumberOfBytes=key_length, EncryptionContext=kms_encryption_context)
if self._grant_tokens:
- kms_params['GrantTokens'] = self._grant_tokens
+ kms_params["GrantTokens"] = self._grant_tokens
# Catch any boto3 errors and normalize to expected WrappingError
try:
response = self._client(key_id).generate_data_key(**kms_params)
- return response['Plaintext'], response['CiphertextBlob']
+ return response["Plaintext"], response["CiphertextBlob"]
except (botocore.exceptions.ClientError, KeyError):
- message = 'Failed to generate materials using AWS KMS'
+ message = "Failed to generate materials using AWS KMS"
_LOGGER.exception(message)
raise WrappingError(message)
@@ -391,23 +377,20 @@ def _decrypt_initial_material(self, encryption_context):
),
signing_description=encryption_context.material_description.get(
MaterialDescriptionKeys.ITEM_SIGNATURE_ALGORITHM.value
- )
+ ),
)
- encrypted_initial_material = base64.b64decode(to_bytes(encryption_context.material_description.get(
- MaterialDescriptionKeys.WRAPPED_DATA_KEY.value
- )))
- kms_params = dict(
- CiphertextBlob=encrypted_initial_material,
- EncryptionContext=kms_encryption_context
+ encrypted_initial_material = base64.b64decode(
+ to_bytes(encryption_context.material_description.get(MaterialDescriptionKeys.WRAPPED_DATA_KEY.value))
)
+ kms_params = dict(CiphertextBlob=encrypted_initial_material, EncryptionContext=kms_encryption_context)
if self._grant_tokens:
- kms_params['GrantTokens'] = self._grant_tokens
+ kms_params["GrantTokens"] = self._grant_tokens
# Catch any boto3 errors and normalize to expected UnwrappingError
try:
response = self._client(key_id).decrypt(**kms_params)
- return response['Plaintext']
+ return response["Plaintext"]
except (botocore.exceptions.ClientError, KeyError):
- message = 'Failed to unwrap AWS KMS protected materials'
+ message = "Failed to unwrap AWS KMS protected materials"
_LOGGER.exception(message)
raise UnwrappingError(message)
@@ -421,13 +404,7 @@ def _hkdf(self, initial_material, key_length, info):
:returns: Derived key material
:rtype: bytes
"""
- hkdf = HKDF(
- algorithm=hashes.SHA256(),
- length=key_length,
- salt=None,
- info=info,
- backend=default_backend()
- )
+ hkdf = HKDF(algorithm=hashes.SHA256(), length=key_length, salt=None, info=info, backend=default_backend())
return hkdf.derive(initial_material)
def _derive_delegated_key(self, initial_material, key_info, hkdf_info):
@@ -445,7 +422,7 @@ def _derive_delegated_key(self, initial_material, key_info, hkdf_info):
key=raw_key,
algorithm=key_info.algorithm,
key_type=EncryptionKeyType.SYMMETRIC,
- key_encoding=KeyEncodingType.RAW
+ key_encoding=KeyEncodingType.RAW,
)
def _encryption_key(self, initial_material, key_info):
@@ -484,18 +461,18 @@ def decryption_materials(self, encryption_context):
material_description=encryption_context.material_description,
description_key=MaterialDescriptionKeys.ITEM_SIGNATURE_ALGORITHM.value,
default_algorithm=_DEFAULT_SIGNING_ALGORITHM,
- default_key_length=_DEFAULT_SIGNING_KEY_LENGTH
+ default_key_length=_DEFAULT_SIGNING_KEY_LENGTH,
)
decryption_key_info = KeyInfo.from_material_description(
material_description=encryption_context.material_description,
description_key=MaterialDescriptionKeys.CONTENT_ENCRYPTION_ALGORITHM.value,
default_algorithm=_DEFAULT_CONTENT_ENCRYPTION_ALGORITHM,
- default_key_length=_DEFAULT_CONTENT_KEY_LENGTH
+ default_key_length=_DEFAULT_CONTENT_KEY_LENGTH,
)
return RawDecryptionMaterials(
verification_key=self._mac_key(initial_material, signing_key_info),
decryption_key=self._encryption_key(initial_material, decryption_key_info),
- material_description=decryption_material_description
+ material_description=decryption_material_description,
)
def encryption_materials(self, encryption_context):
@@ -508,15 +485,17 @@ def encryption_materials(self, encryption_context):
"""
initial_material, encrypted_initial_material = self._generate_initial_material(encryption_context)
encryption_material_description = encryption_context.material_description.copy()
- encryption_material_description.update({
- _COVERED_ATTR_CTX_KEY: _KEY_COVERAGE,
- MaterialDescriptionKeys.CONTENT_KEY_WRAPPING_ALGORITHM.value: 'kms',
- MaterialDescriptionKeys.CONTENT_ENCRYPTION_ALGORITHM.value: self._content_key_info.description,
- MaterialDescriptionKeys.ITEM_SIGNATURE_ALGORITHM.value: self._signing_key_info.description,
- MaterialDescriptionKeys.WRAPPED_DATA_KEY.value: to_str(base64.b64encode(encrypted_initial_material))
- })
+ encryption_material_description.update(
+ {
+ _COVERED_ATTR_CTX_KEY: _KEY_COVERAGE,
+ MaterialDescriptionKeys.CONTENT_KEY_WRAPPING_ALGORITHM.value: "kms",
+ MaterialDescriptionKeys.CONTENT_ENCRYPTION_ALGORITHM.value: self._content_key_info.description,
+ MaterialDescriptionKeys.ITEM_SIGNATURE_ALGORITHM.value: self._signing_key_info.description,
+ MaterialDescriptionKeys.WRAPPED_DATA_KEY.value: to_str(base64.b64encode(encrypted_initial_material)),
+ }
+ )
return RawEncryptionMaterials(
signing_key=self._mac_key(initial_material, self._signing_key_info),
encryption_key=self._encryption_key(initial_material, self._content_key_info),
- material_description=encryption_material_description
+ material_description=encryption_material_description,
)
diff --git a/src/dynamodb_encryption_sdk/material_providers/most_recent.py b/src/dynamodb_encryption_sdk/material_providers/most_recent.py
index e70379dc..ed1d48a4 100644
--- a/src/dynamodb_encryption_sdk/material_providers/most_recent.py
+++ b/src/dynamodb_encryption_sdk/material_providers/most_recent.py
@@ -11,29 +11,31 @@
# ANY KIND, either express or implied. See the License for the specific
# language governing permissions and limitations under the License.
"""Cryptographic materials provider that uses a provider store to obtain cryptographic materials."""
+import logging
+import time
from collections import OrderedDict
from enum import Enum
-import logging
from threading import Lock, RLock
-import time
import attr
import six
-try: # Python 3.5.0 and 3.5.1 have incompatible typing modules
- from typing import Any, Text # noqa pylint: disable=unused-import
-except ImportError: # pragma: no cover
- # We only actually need these imports when running the mypy checks
- pass
-
from dynamodb_encryption_sdk.exceptions import InvalidVersionError, NoKnownVersionError
from dynamodb_encryption_sdk.identifiers import LOGGER_NAME
from dynamodb_encryption_sdk.materials import CryptographicMaterials # noqa pylint: disable=unused-import
from dynamodb_encryption_sdk.structures import EncryptionContext # noqa pylint: disable=unused-import
+
from . import CryptographicMaterialsProvider
from .store import ProviderStore
-__all__ = ('MostRecentProvider',)
+try: # Python 3.5.0 and 3.5.1 have incompatible typing modules
+ from typing import Any, Text # noqa pylint: disable=unused-import
+except ImportError: # pragma: no cover
+ # We only actually need these imports when running the mypy checks
+ pass
+
+
+__all__ = ("MostRecentProvider",)
_LOGGER = logging.getLogger(LOGGER_NAME)
#: Grace period during which we will return the latest local materials. This allows multiple
#: threads to be using this same provider without risking lock contention or many threads
@@ -53,17 +55,14 @@ def _min_capacity_validator(instance, attribute, value):
# pylint: disable=unused-argument
"""Attrs validator to require that value is at least 1."""
if value < 1:
- raise ValueError('Cache capacity must be at least 1')
+ raise ValueError("Cache capacity must be at least 1")
@attr.s(init=False)
class BasicCache(object):
"""Most basic LRU cache."""
- capacity = attr.ib(validator=(
- attr.validators.instance_of(int),
- _min_capacity_validator
- ))
+ capacity = attr.ib(validator=(attr.validators.instance_of(int), _min_capacity_validator))
def __init__(self, capacity): # noqa=D107
# type: (int) -> None
@@ -136,10 +135,7 @@ class MostRecentProvider(CryptographicMaterialsProvider):
_version_ttl = attr.ib(validator=attr.validators.instance_of(float))
def __init__(
- self,
- provider_store, # type: ProviderStore
- material_name, # type: Text
- version_ttl # type: float
+ self, provider_store, material_name, version_ttl # type: ProviderStore # type: Text # type: float
): # noqa=D107
# type: (...) -> None
# Workaround pending resolution of attrs/mypy interaction.
@@ -174,8 +170,8 @@ def decryption_materials(self, encryption_context):
try:
provider = self._provider_store.provider(self._material_name, version)
except InvalidVersionError:
- _LOGGER.exception('Unable to get decryption materials from provider store.')
- raise AttributeError('No decryption materials available')
+ _LOGGER.exception("Unable to get decryption materials from provider store.")
+ raise AttributeError("No decryption materials available")
self._cache.put(version, provider)
@@ -225,8 +221,8 @@ def _get_provider(self, version):
try:
return self._provider_store.get_or_create_provider(self._material_name, version)
except InvalidVersionError:
- _LOGGER.exception('Unable to get encryption materials from provider store.')
- raise AttributeError('No encryption materials available')
+ _LOGGER.exception("Unable to get encryption materials from provider store.")
+ raise AttributeError("No encryption materials available")
def _get_most_recent_version(self, allow_local):
# type: (bool) -> CryptographicMaterialsProvider
diff --git a/src/dynamodb_encryption_sdk/material_providers/static.py b/src/dynamodb_encryption_sdk/material_providers/static.py
index e68ce025..966002cb 100644
--- a/src/dynamodb_encryption_sdk/material_providers/static.py
+++ b/src/dynamodb_encryption_sdk/material_providers/static.py
@@ -13,18 +13,20 @@
"""Cryptographic materials provider for use with pre-configured encryption and decryption materials."""
import attr
+from dynamodb_encryption_sdk.materials import CryptographicMaterials # noqa pylint: disable=unused-import
+from dynamodb_encryption_sdk.materials import DecryptionMaterials, EncryptionMaterials
+from dynamodb_encryption_sdk.structures import EncryptionContext # noqa pylint: disable=unused-import
+
+from . import CryptographicMaterialsProvider
+
try: # Python 3.5.0 and 3.5.1 have incompatible typing modules
from typing import Optional # noqa pylint: disable=unused-import
except ImportError: # pragma: no cover
# We only actually need these imports when running the mypy checks
pass
-from dynamodb_encryption_sdk.materials import CryptographicMaterials # noqa pylint: disable=unused-import
-from dynamodb_encryption_sdk.materials import DecryptionMaterials, EncryptionMaterials
-from dynamodb_encryption_sdk.structures import EncryptionContext # noqa pylint: disable=unused-import
-from . import CryptographicMaterialsProvider
-__all__ = ('StaticCryptographicMaterialsProvider',)
+__all__ = ("StaticCryptographicMaterialsProvider",)
@attr.s(init=False)
@@ -36,18 +38,16 @@ class StaticCryptographicMaterialsProvider(CryptographicMaterialsProvider):
"""
_decryption_materials = attr.ib(
- validator=attr.validators.optional(attr.validators.instance_of(DecryptionMaterials)),
- default=None
+ validator=attr.validators.optional(attr.validators.instance_of(DecryptionMaterials)), default=None
)
_encryption_materials = attr.ib(
- validator=attr.validators.optional(attr.validators.instance_of(EncryptionMaterials)),
- default=None
+ validator=attr.validators.optional(attr.validators.instance_of(EncryptionMaterials)), default=None
)
def __init__(
- self,
- decryption_materials=None, # type: Optional[DecryptionMaterials]
- encryption_materials=None # type: Optional[EncryptionMaterials]
+ self,
+ decryption_materials=None, # type: Optional[DecryptionMaterials]
+ encryption_materials=None, # type: Optional[EncryptionMaterials]
): # noqa=D107
# type: (...) -> None
# Workaround pending resolution of attrs/mypy interaction.
diff --git a/src/dynamodb_encryption_sdk/material_providers/store/__init__.py b/src/dynamodb_encryption_sdk/material_providers/store/__init__.py
index 77b673e4..a40b7c01 100644
--- a/src/dynamodb_encryption_sdk/material_providers/store/__init__.py
+++ b/src/dynamodb_encryption_sdk/material_providers/store/__init__.py
@@ -15,16 +15,19 @@
import six
+from dynamodb_encryption_sdk.exceptions import NoKnownVersionError
+from dynamodb_encryption_sdk.material_providers import ( # noqa pylint: disable=unused-import
+ CryptographicMaterialsProvider
+)
+
try: # Python 3.5.0 and 3.5.1 have incompatible typing modules
from typing import Dict, Text, Optional # noqa pylint: disable=unused-import
except ImportError: # pragma: no cover
# We only actually need these imports when running the mypy checks
pass
-from dynamodb_encryption_sdk.exceptions import NoKnownVersionError
-from dynamodb_encryption_sdk.material_providers import CryptographicMaterialsProvider # noqa pylint: disable=unused-import
-__all__ = ('ProviderStore',)
+__all__ = ("ProviderStore",)
@six.add_metaclass(abc.ABCMeta)
diff --git a/src/dynamodb_encryption_sdk/material_providers/store/meta.py b/src/dynamodb_encryption_sdk/material_providers/store/meta.py
index a0fb02ce..2dbfe227 100644
--- a/src/dynamodb_encryption_sdk/material_providers/store/meta.py
+++ b/src/dynamodb_encryption_sdk/material_providers/store/meta.py
@@ -14,16 +14,10 @@
from enum import Enum
import attr
+import botocore
from boto3.dynamodb.conditions import Attr, Key
from boto3.dynamodb.types import Binary
from boto3.resources.base import ServiceResource
-import botocore
-
-try: # Python 3.5.0 and 3.5.1 have incompatible typing modules
- from typing import Dict, Optional, Text, Tuple # noqa pylint: disable=unused-import
-except ImportError: # pragma: no cover
- # We only actually need these imports when running the mypy checks
- pass
from dynamodb_encryption_sdk.delegated_keys.jce import JceNameLocalDelegatedKey
from dynamodb_encryption_sdk.encrypted.table import EncryptedTable
@@ -31,34 +25,42 @@
from dynamodb_encryption_sdk.identifiers import EncryptionKeyType, KeyEncodingType
from dynamodb_encryption_sdk.material_providers import CryptographicMaterialsProvider
from dynamodb_encryption_sdk.material_providers.wrapped import WrappedCryptographicMaterialsProvider
+
from . import ProviderStore
-__all__ = ('MetaStore',)
+try: # Python 3.5.0 and 3.5.1 have incompatible typing modules
+ from typing import Dict, Optional, Text, Tuple # noqa pylint: disable=unused-import
+except ImportError: # pragma: no cover
+ # We only actually need these imports when running the mypy checks
+ pass
+
+
+__all__ = ("MetaStore",)
class MetaStoreAttributeNames(Enum):
"""Names of attributes in the MetaStore table."""
- PARTITION = 'N'
- SORT = 'V'
- INTEGRITY_ALGORITHM = 'intAlg'
- INTEGRITY_KEY = 'int'
- ENCRYPTION_ALGORITHM = 'encAlg'
- ENCRYPTION_KEY = 'enc'
- MATERIAL_TYPE_VERSION = 't'
+ PARTITION = "N"
+ SORT = "V"
+ INTEGRITY_ALGORITHM = "intAlg"
+ INTEGRITY_KEY = "int"
+ ENCRYPTION_ALGORITHM = "encAlg"
+ ENCRYPTION_KEY = "enc"
+ MATERIAL_TYPE_VERSION = "t"
class MetaStoreValues(Enum):
"""Static values for use by MetaStore."""
- INTEGRITY_ALGORITHM = 'HmacSHA256'
- ENCRYPTION_ALGORITHM = 'AES'
- MATERIAL_TYPE_VERSION = '0'
+ INTEGRITY_ALGORITHM = "HmacSHA256"
+ ENCRYPTION_ALGORITHM = "AES"
+ MATERIAL_TYPE_VERSION = "0"
KEY_BITS = 256
#: Field in material description to use for the MetaStore material name and version.
-_MATERIAL_DESCRIPTION_META_FIELD = 'amzn-ddb-meta-id'
+_MATERIAL_DESCRIPTION_META_FIELD = "amzn-ddb-meta-id"
@attr.s(init=False)
@@ -88,8 +90,7 @@ def __attrs_post_init__(self):
# type: () -> None
"""Prepare the encrypted table resource from the provided table and materials provider."""
self._encrypted_table = EncryptedTable( # attrs confuses pylint: disable=attribute-defined-outside-init
- table=self._table,
- materials_provider=self._materials_provider
+ table=self._table, materials_provider=self._materials_provider
)
@classmethod
@@ -107,32 +108,17 @@ def create_table(cls, client, table_name, read_units, write_units):
client.create_table(
TableName=table_name,
AttributeDefinitions=[
- {
- 'AttributeName': MetaStoreAttributeNames.PARTITION.value,
- 'AttributeType': 'S'
- },
- {
- 'AttributeName': MetaStoreAttributeNames.SORT.value,
- 'AttributeType': 'N'
- }
+ {"AttributeName": MetaStoreAttributeNames.PARTITION.value, "AttributeType": "S"},
+ {"AttributeName": MetaStoreAttributeNames.SORT.value, "AttributeType": "N"},
],
KeySchema=[
- {
- 'AttributeName': MetaStoreAttributeNames.PARTITION.value,
- 'KeyType': 'HASH'
- },
- {
- 'AttributeName': MetaStoreAttributeNames.SORT.value,
- 'KeyType': 'RANGE'
- }
+ {"AttributeName": MetaStoreAttributeNames.PARTITION.value, "KeyType": "HASH"},
+ {"AttributeName": MetaStoreAttributeNames.SORT.value, "KeyType": "RANGE"},
],
- ProvisionedThroughput={
- 'ReadCapacityUnits': read_units,
- 'WriteCapacityUnits': write_units
- }
+ ProvisionedThroughput={"ReadCapacityUnits": read_units, "WriteCapacityUnits": write_units},
)
except botocore.exceptions.ClientError:
- raise Exception('TODO: Could not create table')
+ raise Exception("TODO: Could not create table")
def _load_materials(self, material_name, version):
# type: (Text, int) -> Tuple[JceNameLocalDelegatedKey, JceNameLocalDelegatedKey]
@@ -141,13 +127,10 @@ def _load_materials(self, material_name, version):
:returns: Materials loaded into delegated keys
:rtype: tuple(JceNameLocalDelegatedKey)
"""
- key = {
- MetaStoreAttributeNames.PARTITION.value: material_name,
- MetaStoreAttributeNames.SORT.value: version
- }
+ key = {MetaStoreAttributeNames.PARTITION.value: material_name, MetaStoreAttributeNames.SORT.value: version}
response = self._encrypted_table.get_item(Key=key)
try:
- item = response['Item']
+ item = response["Item"]
except KeyError:
raise InvalidVersionError('Version not found: "{}#{}"'.format(material_name, version))
@@ -156,22 +139,22 @@ def _load_materials(self, material_name, version):
key=item[MetaStoreAttributeNames.ENCRYPTION_KEY.value].value,
algorithm=item[MetaStoreAttributeNames.ENCRYPTION_ALGORITHM.value],
key_type=EncryptionKeyType.SYMMETRIC,
- key_encoding=KeyEncodingType.RAW
+ key_encoding=KeyEncodingType.RAW,
)
signing_key_kwargs = dict(
key=item[MetaStoreAttributeNames.INTEGRITY_KEY.value].value,
algorithm=item[MetaStoreAttributeNames.INTEGRITY_ALGORITHM.value],
key_type=EncryptionKeyType.SYMMETRIC,
- key_encoding=KeyEncodingType.RAW
+ key_encoding=KeyEncodingType.RAW,
)
except KeyError:
- raise Exception('TODO: Invalid record')
+ raise Exception("TODO: Invalid record")
# TODO: handle if the material type version is not in the item
if item[MetaStoreAttributeNames.MATERIAL_TYPE_VERSION.value] != MetaStoreValues.MATERIAL_TYPE_VERSION.value:
- raise InvalidVersionError('Unsupported material type: "{}"'.format(
- item[MetaStoreAttributeNames.MATERIAL_TYPE_VERSION.value]
- ))
+ raise InvalidVersionError(
+ 'Unsupported material type: "{}"'.format(item[MetaStoreAttributeNames.MATERIAL_TYPE_VERSION.value])
+ )
encryption_key = JceNameLocalDelegatedKey(**encryption_key_kwargs)
signing_key = JceNameLocalDelegatedKey(**signing_key_kwargs)
@@ -192,26 +175,26 @@ def _save_materials(self, material_name, version, encryption_key, signing_key):
MetaStoreAttributeNames.ENCRYPTION_ALGORITHM.value: encryption_key.algorithm,
MetaStoreAttributeNames.ENCRYPTION_KEY.value: Binary(encryption_key.key),
MetaStoreAttributeNames.INTEGRITY_ALGORITHM.value: signing_key.algorithm,
- MetaStoreAttributeNames.INTEGRITY_KEY.value: Binary(signing_key.key)
+ MetaStoreAttributeNames.INTEGRITY_KEY.value: Binary(signing_key.key),
}
try:
self._encrypted_table.put_item(
Item=item,
ConditionExpression=(
- Attr(MetaStoreAttributeNames.PARTITION.value).not_exists() &
- Attr(MetaStoreAttributeNames.SORT.value).not_exists()
- )
+ Attr(MetaStoreAttributeNames.PARTITION.value).not_exists()
+ & Attr(MetaStoreAttributeNames.SORT.value).not_exists()
+ ),
)
except botocore.exceptions.ClientError as error:
- if error.response['Error']['Code'] == 'ConditionalCheckFailedException':
+ if error.response["Error"]["Code"] == "ConditionalCheckFailedException":
raise VersionAlreadyExistsError('Version already exists: "{}#{}"'.format(material_name, version))
def _save_or_load_materials(
- self,
- material_name, # type: Text
- version, # type: int
- encryption_key, # type: JceNameLocalDelegatedKey
- signing_key # type: JceNameLocalDelegatedKey
+ self,
+ material_name, # type: Text
+ version, # type: int
+ encryption_key, # type: JceNameLocalDelegatedKey
+ signing_key, # type: JceNameLocalDelegatedKey
):
# type: (...) -> Tuple[JceNameLocalDelegatedKey, JceNameLocalDelegatedKey]
"""Attempt to save the materials to the table.
@@ -238,7 +221,7 @@ def _material_description(material_name, version):
:param str material_name: Material to locate
:param int version: Version of material to locate
"""
- return {_MATERIAL_DESCRIPTION_META_FIELD: '{name}#{version}'.format(name=material_name, version=version)}
+ return {_MATERIAL_DESCRIPTION_META_FIELD: "{name}#{version}".format(name=material_name, version=version)}
def _load_provider_from_table(self, material_name, version):
# type: (Text, int) -> CryptographicMaterialsProvider
@@ -254,7 +237,7 @@ def _load_provider_from_table(self, material_name, version):
signing_key=signing_key,
wrapping_key=encryption_key,
unwrapping_key=encryption_key,
- material_description=self._material_description(material_name, version)
+ material_description=self._material_description(material_name, version),
)
def get_or_create_provider(self, material_name, version):
@@ -270,19 +253,17 @@ def get_or_create_provider(self, material_name, version):
:raises InvalidVersionError: if the requested version is not available and cannot be created
"""
encryption_key = JceNameLocalDelegatedKey.generate(
- MetaStoreValues.ENCRYPTION_ALGORITHM.value,
- MetaStoreValues.KEY_BITS.value
+ MetaStoreValues.ENCRYPTION_ALGORITHM.value, MetaStoreValues.KEY_BITS.value
)
signing_key = JceNameLocalDelegatedKey.generate(
- MetaStoreValues.INTEGRITY_ALGORITHM.value,
- MetaStoreValues.KEY_BITS.value
+ MetaStoreValues.INTEGRITY_ALGORITHM.value, MetaStoreValues.KEY_BITS.value
)
encryption_key, signing_key = self._save_or_load_materials(material_name, version, encryption_key, signing_key)
return WrappedCryptographicMaterialsProvider(
signing_key=signing_key,
wrapping_key=encryption_key,
unwrapping_key=encryption_key,
- material_description=self._material_description(material_name, version)
+ material_description=self._material_description(material_name, version),
)
def provider(self, material_name, version=None):
@@ -315,12 +296,12 @@ def version_from_material_description(self, material_description):
try:
info = material_description[_MATERIAL_DESCRIPTION_META_FIELD]
except KeyError:
- raise Exception('TODO: No info found')
+ raise Exception("TODO: No info found")
try:
- return int(info.split('#', 1)[1])
+ return int(info.split("#", 1)[1])
except (IndexError, ValueError):
- raise Exception('TODO: Malformed info')
+ raise Exception("TODO: Malformed info")
def max_version(self, material_name):
# (Text) -> int
@@ -334,10 +315,10 @@ def max_version(self, material_name):
response = self._encrypted_table.query(
KeyConditionExpression=Key(MetaStoreAttributeNames.PARTITION.value).eq(material_name),
ScanIndexForward=False,
- Limit=1
+ Limit=1,
)
- if not response['Items']:
+ if not response["Items"]:
raise NoKnownVersionError('No known version for name: "{}"'.format(material_name))
- return int(response['Items'][0][MetaStoreAttributeNames.SORT.value])
+ return int(response["Items"][0][MetaStoreAttributeNames.SORT.value])
diff --git a/src/dynamodb_encryption_sdk/material_providers/wrapped.py b/src/dynamodb_encryption_sdk/material_providers/wrapped.py
index 7a6c571d..13f6a346 100644
--- a/src/dynamodb_encryption_sdk/material_providers/wrapped.py
+++ b/src/dynamodb_encryption_sdk/material_providers/wrapped.py
@@ -14,6 +14,14 @@
import attr
import six
+from dynamodb_encryption_sdk.delegated_keys import DelegatedKey
+from dynamodb_encryption_sdk.exceptions import UnwrappingError, WrappingError
+from dynamodb_encryption_sdk.internal.validators import dictionary_validator
+from dynamodb_encryption_sdk.materials.wrapped import WrappedCryptographicMaterials
+from dynamodb_encryption_sdk.structures import EncryptionContext # noqa pylint: disable=unused-import
+
+from . import CryptographicMaterialsProvider
+
try: # Python 3.5.0 and 3.5.1 have incompatible typing modules
from typing import Dict, Optional, Text # noqa pylint: disable=unused-import
except ImportError: # pragma: no cover
@@ -26,14 +34,8 @@
# We only actually need these imports when running the mypy checks
pass
-from dynamodb_encryption_sdk.delegated_keys import DelegatedKey
-from dynamodb_encryption_sdk.exceptions import UnwrappingError, WrappingError
-from dynamodb_encryption_sdk.internal.validators import dictionary_validator
-from dynamodb_encryption_sdk.materials.wrapped import WrappedCryptographicMaterials
-from dynamodb_encryption_sdk.structures import EncryptionContext # noqa pylint: disable=unused-import
-from . import CryptographicMaterialsProvider
-__all__ = ('WrappedCryptographicMaterialsProvider',)
+__all__ = ("WrappedCryptographicMaterialsProvider",)
@attr.s(init=False)
@@ -56,25 +58,21 @@ class WrappedCryptographicMaterialsProvider(CryptographicMaterialsProvider):
"""
_signing_key = attr.ib(validator=attr.validators.instance_of(DelegatedKey))
- _wrapping_key = attr.ib(
- validator=attr.validators.optional(attr.validators.instance_of(DelegatedKey)),
- default=None
- )
+ _wrapping_key = attr.ib(validator=attr.validators.optional(attr.validators.instance_of(DelegatedKey)), default=None)
_unwrapping_key = attr.ib(
- validator=attr.validators.optional(attr.validators.instance_of(DelegatedKey)),
- default=None
+ validator=attr.validators.optional(attr.validators.instance_of(DelegatedKey)), default=None
)
_material_description = attr.ib(
validator=attr.validators.optional(dictionary_validator(six.string_types, six.string_types)),
- default=attr.Factory(dict)
+ default=attr.Factory(dict),
)
def __init__(
- self,
- signing_key, # type: DelegatedKey
- wrapping_key=None, # type: Optional[DelegatedKey]
- unwrapping_key=None, # type: Optional[DelegatedKey]
- material_description=None # type: Optional[Dict[Text, Text]]
+ self,
+ signing_key, # type: DelegatedKey
+ wrapping_key=None, # type: Optional[DelegatedKey]
+ unwrapping_key=None, # type: Optional[DelegatedKey]
+ material_description=None, # type: Optional[Dict[Text, Text]]
): # noqa=D107
# type: (...) -> None
# Workaround pending resolution of attrs/mypy interaction.
@@ -103,7 +101,7 @@ def _build_materials(self, encryption_context):
wrapping_key=self._wrapping_key,
unwrapping_key=self._unwrapping_key,
signing_key=self._signing_key,
- material_description=material_description
+ material_description=material_description,
)
def encryption_materials(self, encryption_context):
@@ -116,7 +114,7 @@ def encryption_materials(self, encryption_context):
:raises WrappingError: if no wrapping key is available
"""
if self._wrapping_key is None:
- raise WrappingError('Encryption materials cannot be provided: no wrapping key')
+ raise WrappingError("Encryption materials cannot be provided: no wrapping key")
return self._build_materials(encryption_context)
@@ -130,6 +128,6 @@ def decryption_materials(self, encryption_context):
:raises UnwrappingError: if no unwrapping key is available
"""
if self._unwrapping_key is None:
- raise UnwrappingError('Decryption materials cannot be provided: no unwrapping key')
+ raise UnwrappingError("Decryption materials cannot be provided: no unwrapping key")
return self._build_materials(encryption_context)
diff --git a/src/dynamodb_encryption_sdk/materials/__init__.py b/src/dynamodb_encryption_sdk/materials/__init__.py
index d95702a0..ba07d0c8 100644
--- a/src/dynamodb_encryption_sdk/materials/__init__.py
+++ b/src/dynamodb_encryption_sdk/materials/__init__.py
@@ -13,6 +13,10 @@
"""Cryptographic materials are containers that provide delegated keys for cryptographic operations."""
import abc
+import six
+
+from dynamodb_encryption_sdk.delegated_keys import DelegatedKey # noqa pylint: disable=unused-import
+
try: # Python 3.5.0 and 3.5.1 have incompatible typing modules
from typing import Dict, Text # noqa pylint: disable=unused-import
from mypy_extensions import NoReturn # noqa pylint: disable=unused-import
@@ -20,11 +24,8 @@
# We only actually need these imports when running the mypy checks
pass
-import six
-
-from dynamodb_encryption_sdk.delegated_keys import DelegatedKey # noqa pylint: disable=unused-import
-__all__ = ('CryptographicMaterials', 'EncryptionMaterials', 'DecryptionMaterials')
+__all__ = ("CryptographicMaterials", "EncryptionMaterials", "DecryptionMaterials")
@six.add_metaclass(abc.ABCMeta)
@@ -87,7 +88,7 @@ def decryption_key(self):
:raises NotImplementedError: because encryption materials do not contain decryption keys
"""
- raise NotImplementedError('Encryption materials do not provide decryption keys.')
+ raise NotImplementedError("Encryption materials do not provide decryption keys.")
@property
def verification_key(self):
@@ -96,7 +97,7 @@ def verification_key(self):
:raises NotImplementedError: because encryption materials do not contain verification keys
"""
- raise NotImplementedError('Encryption materials do not provide verification keys.')
+ raise NotImplementedError("Encryption materials do not provide verification keys.")
class DecryptionMaterials(CryptographicMaterials):
@@ -109,7 +110,7 @@ def encryption_key(self):
:raises NotImplementedError: because decryption materials do not contain encryption keys
"""
- raise NotImplementedError('Decryption materials do not provide encryption keys.')
+ raise NotImplementedError("Decryption materials do not provide encryption keys.")
@property
def signing_key(self):
@@ -118,4 +119,4 @@ def signing_key(self):
:raises NotImplementedError: because decryption materials do not contain signing keys
"""
- raise NotImplementedError('Decryption materials do not provide signing keys.')
+ raise NotImplementedError("Decryption materials do not provide signing keys.")
diff --git a/src/dynamodb_encryption_sdk/materials/raw.py b/src/dynamodb_encryption_sdk/materials/raw.py
index 05bc9eb1..7c2e85e4 100644
--- a/src/dynamodb_encryption_sdk/materials/raw.py
+++ b/src/dynamodb_encryption_sdk/materials/raw.py
@@ -27,17 +27,18 @@
import attr
import six
+from dynamodb_encryption_sdk.delegated_keys import DelegatedKey
+from dynamodb_encryption_sdk.internal.validators import dictionary_validator
+from dynamodb_encryption_sdk.materials import DecryptionMaterials, EncryptionMaterials
+
try: # Python 3.5.0 and 3.5.1 have incompatible typing modules
from typing import Dict, Optional, Text # noqa pylint: disable=unused-import
except ImportError: # pragma: no cover
# We only actually need these imports when running the mypy checks
pass
-from dynamodb_encryption_sdk.delegated_keys import DelegatedKey
-from dynamodb_encryption_sdk.internal.validators import dictionary_validator
-from dynamodb_encryption_sdk.materials import DecryptionMaterials, EncryptionMaterials
-__all__ = ('RawEncryptionMaterials', 'RawDecryptionMaterials')
+__all__ = ("RawEncryptionMaterials", "RawDecryptionMaterials")
@attr.s(init=False)
@@ -56,20 +57,19 @@ class RawEncryptionMaterials(EncryptionMaterials):
_signing_key = attr.ib(validator=attr.validators.instance_of(DelegatedKey))
_encryption_key = attr.ib(
- validator=attr.validators.optional(attr.validators.instance_of(DelegatedKey)),
- default=None
+ validator=attr.validators.optional(attr.validators.instance_of(DelegatedKey)), default=None
)
_material_description = attr.ib(
validator=dictionary_validator(six.string_types, six.string_types),
converter=copy.deepcopy,
- default=attr.Factory(dict)
+ default=attr.Factory(dict),
)
def __init__(
- self,
- signing_key, # type: DelegatedKey
- encryption_key=None, # type: Optional[DelegatedKey]
- material_description=None # type: Optional[Dict[Text, Text]]
+ self,
+ signing_key, # type: DelegatedKey
+ encryption_key=None, # type: Optional[DelegatedKey]
+ material_description=None, # type: Optional[Dict[Text, Text]]
): # noqa=D107
# type: (...) -> None
# Workaround pending resolution of attrs/mypy interaction.
@@ -87,9 +87,11 @@ def __init__(
def __attrs_post_init__(self):
"""Verify that the encryption key is allowed be used for raw materials."""
if self._encryption_key is not None and not self._encryption_key.allowed_for_raw_materials:
- raise ValueError('Encryption key type "{}" does not allow use with RawEncryptionMaterials'.format(
- type(self._encryption_key)
- ))
+ raise ValueError(
+ 'Encryption key type "{}" does not allow use with RawEncryptionMaterials'.format(
+ type(self._encryption_key)
+ )
+ )
@property
def material_description(self):
@@ -120,7 +122,7 @@ def encryption_key(self):
:rtype: DelegatedKey
"""
if self._encryption_key is None:
- raise AttributeError('No encryption key available')
+ raise AttributeError("No encryption key available")
return self._encryption_key
@@ -141,20 +143,19 @@ class RawDecryptionMaterials(DecryptionMaterials):
_verification_key = attr.ib(validator=attr.validators.instance_of(DelegatedKey))
_decryption_key = attr.ib(
- validator=attr.validators.optional(attr.validators.instance_of(DelegatedKey)),
- default=None
+ validator=attr.validators.optional(attr.validators.instance_of(DelegatedKey)), default=None
)
_material_description = attr.ib(
validator=dictionary_validator(six.string_types, six.string_types),
converter=copy.deepcopy,
- default=attr.Factory(dict)
+ default=attr.Factory(dict),
)
def __init__(
- self,
- verification_key, # type: DelegatedKey
- decryption_key=None, # type: Optional[DelegatedKey]
- material_description=None # type: Optional[Dict[Text, Text]]
+ self,
+ verification_key, # type: DelegatedKey
+ decryption_key=None, # type: Optional[DelegatedKey]
+ material_description=None, # type: Optional[Dict[Text, Text]]
): # noqa=D107
# type: (...) -> None
# Workaround pending resolution of attrs/mypy interaction.
@@ -172,9 +173,11 @@ def __init__(
def __attrs_post_init__(self):
"""Verify that the encryption key is allowed be used for raw materials."""
if self._decryption_key is not None and not self._decryption_key.allowed_for_raw_materials:
- raise ValueError('Decryption key type "{}" does not allow use with RawDecryptionMaterials'.format(
- type(self._decryption_key)
- ))
+ raise ValueError(
+ 'Decryption key type "{}" does not allow use with RawDecryptionMaterials'.format(
+ type(self._decryption_key)
+ )
+ )
@property
def material_description(self):
@@ -205,6 +208,6 @@ def decryption_key(self):
:rtype: DelegatedKey
"""
if self._decryption_key is None:
- raise AttributeError('No decryption key available')
+ raise AttributeError("No decryption key available")
return self._decryption_key
diff --git a/src/dynamodb_encryption_sdk/materials/wrapped.py b/src/dynamodb_encryption_sdk/materials/wrapped.py
index c69b2028..daf8638a 100644
--- a/src/dynamodb_encryption_sdk/materials/wrapped.py
+++ b/src/dynamodb_encryption_sdk/materials/wrapped.py
@@ -17,12 +17,6 @@
import attr
import six
-try: # Python 3.5.0 and 3.5.1 have incompatible typing modules
- from typing import Dict, Optional, Text # noqa pylint: disable=unused-import
-except ImportError: # pragma: no cover
- # We only actually need these imports when running the mypy checks
- pass
-
from dynamodb_encryption_sdk.delegated_keys import DelegatedKey
from dynamodb_encryption_sdk.delegated_keys.jce import JceNameLocalDelegatedKey
from dynamodb_encryption_sdk.exceptions import UnwrappingError, WrappingError
@@ -31,12 +25,16 @@
from dynamodb_encryption_sdk.internal.validators import dictionary_validator
from dynamodb_encryption_sdk.materials import CryptographicMaterials
-__all__ = ('WrappedCryptographicMaterials',)
-_DEFAULT_CONTENT_ENCRYPTION_ALGORITHM = 'AES/256'
-_WRAPPING_TRANSFORMATION = {
- 'AES': 'AESWrap',
- 'RSA': 'RSA/ECB/OAEPWithSHA-256AndMGF1Padding'
-}
+try: # Python 3.5.0 and 3.5.1 have incompatible typing modules
+ from typing import Dict, Optional, Text # noqa pylint: disable=unused-import
+except ImportError: # pragma: no cover
+ # We only actually need these imports when running the mypy checks
+ pass
+
+
+__all__ = ("WrappedCryptographicMaterials",)
+_DEFAULT_CONTENT_ENCRYPTION_ALGORITHM = "AES/256"
+_WRAPPING_TRANSFORMATION = {"AES": "AESWrap", "RSA": "RSA/ECB/OAEPWithSHA-256AndMGF1Padding"}
@attr.s(init=False)
@@ -61,26 +59,22 @@ class WrappedCryptographicMaterials(CryptographicMaterials):
"""
_signing_key = attr.ib(validator=attr.validators.instance_of(DelegatedKey))
- _wrapping_key = attr.ib(
- validator=attr.validators.optional(attr.validators.instance_of(DelegatedKey)),
- default=None
- )
+ _wrapping_key = attr.ib(validator=attr.validators.optional(attr.validators.instance_of(DelegatedKey)), default=None)
_unwrapping_key = attr.ib(
- validator=attr.validators.optional(attr.validators.instance_of(DelegatedKey)),
- default=None
+ validator=attr.validators.optional(attr.validators.instance_of(DelegatedKey)), default=None
)
_material_description = attr.ib(
validator=dictionary_validator(six.string_types, six.string_types),
converter=copy.deepcopy,
- default=attr.Factory(dict)
+ default=attr.Factory(dict),
)
def __init__(
- self,
- signing_key, # type: DelegatedKey
- wrapping_key=None, # type: Optional[DelegatedKey]
- unwrapping_key=None, # type: Optional[DelegatedKey]
- material_description=None # type: Optional[Dict[Text, Text]]
+ self,
+ signing_key, # type: DelegatedKey
+ wrapping_key=None, # type: Optional[DelegatedKey]
+ unwrapping_key=None, # type: Optional[DelegatedKey]
+ material_description=None, # type: Optional[Dict[Text, Text]]
): # noqa=D107
# type: (...) -> None
# Workaround pending resolution of attrs/mypy interaction.
@@ -99,14 +93,17 @@ def __init__(
def __attrs_post_init__(self):
"""Prepare the content key."""
self._content_key_algorithm = self.material_description.get( # pylint: disable=attribute-defined-outside-init
- MaterialDescriptionKeys.CONTENT_ENCRYPTION_ALGORITHM.value,
- _DEFAULT_CONTENT_ENCRYPTION_ALGORITHM
+ MaterialDescriptionKeys.CONTENT_ENCRYPTION_ALGORITHM.value, _DEFAULT_CONTENT_ENCRYPTION_ALGORITHM
)
if MaterialDescriptionKeys.WRAPPED_DATA_KEY.value in self.material_description:
- self._content_key = self._content_key_from_material_description() # noqa pylint: disable=attribute-defined-outside-init
+ self._content_key = (
+ self._content_key_from_material_description()
+ ) # noqa pylint: disable=attribute-defined-outside-init
else:
- self._content_key, self._material_description = self._generate_content_key() # noqa pylint: disable=attribute-defined-outside-init
+ self._content_key, self._material_description = (
+ self._generate_content_key()
+ ) # noqa pylint: disable=attribute-defined-outside-init
@staticmethod
def _wrapping_transformation(algorithm):
@@ -126,23 +123,20 @@ def _content_key_from_material_description(self):
"""
if self._unwrapping_key is None:
raise UnwrappingError(
- 'Cryptographic materials cannot be loaded from material description: no unwrapping key'
+ "Cryptographic materials cannot be loaded from material description: no unwrapping key"
)
wrapping_algorithm = self.material_description.get(
- MaterialDescriptionKeys.CONTENT_KEY_WRAPPING_ALGORITHM.value,
- self._unwrapping_key.algorithm
+ MaterialDescriptionKeys.CONTENT_KEY_WRAPPING_ALGORITHM.value, self._unwrapping_key.algorithm
)
- wrapped_key = base64.b64decode(
- self.material_description[MaterialDescriptionKeys.WRAPPED_DATA_KEY.value]
- )
- content_key_algorithm = self._content_key_algorithm.split('/', 1)[0]
+ wrapped_key = base64.b64decode(self.material_description[MaterialDescriptionKeys.WRAPPED_DATA_KEY.value])
+ content_key_algorithm = self._content_key_algorithm.split("/", 1)[0]
return self._unwrapping_key.unwrap(
algorithm=wrapping_algorithm,
wrapped_key=wrapped_key,
wrapped_key_algorithm=content_key_algorithm,
wrapped_key_type=EncryptionKeyType.SYMMETRIC,
- additional_associated_data=None
+ additional_associated_data=None,
)
def _generate_content_key(self):
@@ -153,33 +147,30 @@ def _generate_content_key(self):
:rtype: tuple containing DelegatedKey and dict
"""
if self._wrapping_key is None:
- raise WrappingError('Cryptographic materials cannot be generated: no wrapping key')
+ raise WrappingError("Cryptographic materials cannot be generated: no wrapping key")
wrapping_algorithm = self.material_description.get(
MaterialDescriptionKeys.CONTENT_KEY_WRAPPING_ALGORITHM.value,
- self._wrapping_transformation(self._wrapping_key.algorithm)
+ self._wrapping_transformation(self._wrapping_key.algorithm),
)
- args = self._content_key_algorithm.split('/', 1)
+ args = self._content_key_algorithm.split("/", 1)
content_algorithm = args[0]
try:
content_key_length = int(args[1])
except IndexError:
content_key_length = None
- content_key = JceNameLocalDelegatedKey.generate(
- algorithm=content_algorithm,
- key_length=content_key_length
- )
+ content_key = JceNameLocalDelegatedKey.generate(algorithm=content_algorithm, key_length=content_key_length)
wrapped_key = self._wrapping_key.wrap(
- algorithm=wrapping_algorithm,
- content_key=content_key.key,
- additional_associated_data=None
+ algorithm=wrapping_algorithm, content_key=content_key.key, additional_associated_data=None
)
new_material_description = self.material_description.copy()
- new_material_description.update({
- MaterialDescriptionKeys.WRAPPED_DATA_KEY.value: base64.b64encode(wrapped_key),
- MaterialDescriptionKeys.CONTENT_ENCRYPTION_ALGORITHM.value: self._content_key_algorithm,
- MaterialDescriptionKeys.CONTENT_KEY_WRAPPING_ALGORITHM.value: wrapping_algorithm
- })
+ new_material_description.update(
+ {
+ MaterialDescriptionKeys.WRAPPED_DATA_KEY.value: base64.b64encode(wrapped_key),
+ MaterialDescriptionKeys.CONTENT_ENCRYPTION_ALGORITHM.value: self._content_key_algorithm,
+ MaterialDescriptionKeys.CONTENT_KEY_WRAPPING_ALGORITHM.value: wrapping_algorithm,
+ }
+ )
return content_key, new_material_description
@property
diff --git a/src/dynamodb_encryption_sdk/structures.py b/src/dynamodb_encryption_sdk/structures.py
index 22c38cdf..7d62ac94 100644
--- a/src/dynamodb_encryption_sdk/structures.py
+++ b/src/dynamodb_encryption_sdk/structures.py
@@ -16,18 +16,20 @@
import attr
import six
+from dynamodb_encryption_sdk.exceptions import InvalidArgumentError
+from dynamodb_encryption_sdk.internal.identifiers import ReservedAttributes
+from dynamodb_encryption_sdk.internal.validators import dictionary_validator, iterable_validator
+
+from .identifiers import CryptoAction
+
try: # Python 3.5.0 and 3.5.1 have incompatible typing modules
from typing import Dict, Iterable, List, Optional, Set, Text # noqa pylint: disable=unused-import
except ImportError: # pragma: no cover
# We only actually need these imports when running the mypy checks
pass
-from dynamodb_encryption_sdk.exceptions import InvalidArgumentError
-from dynamodb_encryption_sdk.internal.identifiers import ReservedAttributes
-from dynamodb_encryption_sdk.internal.validators import dictionary_validator, iterable_validator
-from .identifiers import CryptoAction
-__all__ = ('EncryptionContext', 'AttributeActions', 'TableIndex', 'TableInfo')
+__all__ = ("EncryptionContext", "AttributeActions", "TableIndex", "TableInfo")
def _validate_attribute_values_are_ddb_items(instance, attribute, value): # pylint: disable=unused-argument
@@ -57,37 +59,31 @@ class EncryptionContext(object):
"""
table_name = attr.ib(
- validator=attr.validators.optional(attr.validators.instance_of(six.string_types)),
- default=None
+ validator=attr.validators.optional(attr.validators.instance_of(six.string_types)), default=None
)
partition_key_name = attr.ib(
- validator=attr.validators.optional(attr.validators.instance_of(six.string_types)),
- default=None
+ validator=attr.validators.optional(attr.validators.instance_of(six.string_types)), default=None
)
sort_key_name = attr.ib(
- validator=attr.validators.optional(attr.validators.instance_of(six.string_types)),
- default=None
+ validator=attr.validators.optional(attr.validators.instance_of(six.string_types)), default=None
)
attributes = attr.ib(
- validator=(
- dictionary_validator(six.string_types, dict),
- _validate_attribute_values_are_ddb_items
- ),
- default=attr.Factory(dict)
+ validator=(dictionary_validator(six.string_types, dict), _validate_attribute_values_are_ddb_items),
+ default=attr.Factory(dict),
)
material_description = attr.ib(
validator=dictionary_validator(six.string_types, six.string_types),
converter=copy.deepcopy,
- default=attr.Factory(dict)
+ default=attr.Factory(dict),
)
def __init__(
- self,
- table_name=None, # type: Optional[Text]
- partition_key_name=None, # type: Optional[Text]
- sort_key_name=None, # type: Optional[Text]
- attributes=None, # type: Optional[Dict[Text, Dict]]
- material_description=None # type: Optional[Dict[Text, Text]]
+ self,
+ table_name=None, # type: Optional[Text]
+ partition_key_name=None, # type: Optional[Text]
+ sort_key_name=None, # type: Optional[Text]
+ attributes=None, # type: Optional[Dict[Text, Dict]]
+ material_description=None, # type: Optional[Dict[Text, Text]]
): # noqa=D107
# type: (...) -> None
# Workaround pending resolution of attrs/mypy interaction.
@@ -115,19 +111,15 @@ class AttributeActions(object):
:param dict attribute_actions: Dictionary mapping attribute names to specific actions
"""
- default_action = attr.ib(
- validator=attr.validators.instance_of(CryptoAction),
- default=CryptoAction.ENCRYPT_AND_SIGN
- )
+ default_action = attr.ib(validator=attr.validators.instance_of(CryptoAction), default=CryptoAction.ENCRYPT_AND_SIGN)
attribute_actions = attr.ib(
- validator=dictionary_validator(six.string_types, CryptoAction),
- default=attr.Factory(dict)
+ validator=dictionary_validator(six.string_types, CryptoAction), default=attr.Factory(dict)
)
def __init__(
- self,
- default_action=CryptoAction.ENCRYPT_AND_SIGN, # type: Optional[CryptoAction]
- attribute_actions=None # type: Optional[Dict[Text, CryptoAction]]
+ self,
+ default_action=CryptoAction.ENCRYPT_AND_SIGN, # type: Optional[CryptoAction]
+ attribute_actions=None, # type: Optional[Dict[Text, CryptoAction]]
): # noqa=D107
# type: (...) -> None
# Workaround pending resolution of attrs/mypy interaction.
@@ -166,10 +158,7 @@ def action(self, attribute_name):
def copy(self):
# () -> AttributeActions
"""Return a new copy of this object."""
- return AttributeActions(
- default_action=self.default_action,
- attribute_actions=self.attribute_actions.copy()
- )
+ return AttributeActions(default_action=self.default_action, attribute_actions=self.attribute_actions.copy())
def set_index_keys(self, *keys):
"""Set the appropriate action for the specified indexed attribute names.
@@ -218,10 +207,7 @@ def __add__(self, other):
attribute_actions = {}
for attribute in all_attributes:
attribute_actions[attribute] = max(self.action(attribute), other.action(attribute))
- return AttributeActions(
- default_action=default_action,
- attribute_actions=attribute_actions
- )
+ return AttributeActions(default_action=default_action, attribute_actions=attribute_actions)
@attr.s(init=False)
@@ -234,16 +220,9 @@ class TableIndex(object):
"""
partition = attr.ib(validator=attr.validators.instance_of(six.string_types))
- sort = attr.ib(
- validator=attr.validators.optional(attr.validators.instance_of(six.string_types)),
- default=None
- )
+ sort = attr.ib(validator=attr.validators.optional(attr.validators.instance_of(six.string_types)), default=None)
- def __init__(
- self,
- partition, # type: Text
- sort=None # type: Optional[Text]
- ): # noqa=D107
+ def __init__(self, partition, sort=None): # type: Text # type: Optional[Text] # noqa=D107
# type: (...) -> None
# Workaround pending resolution of attrs/mypy interaction.
# https://github.com/python/mypy/issues/2088
@@ -277,14 +256,8 @@ def from_key_schema(cls, key_schema):
:returns: New TableIndex that describes the provided schema
:rtype: TableIndex
"""
- index = {
- key['KeyType']: key['AttributeName']
- for key in key_schema
- }
- return cls(
- partition=index['HASH'],
- sort=index.get('RANGE', None)
- )
+ index = {key["KeyType"]: key["AttributeName"] for key in key_schema}
+ return cls(partition=index["HASH"], sort=index.get("RANGE", None))
@attr.s(init=False)
@@ -299,20 +272,14 @@ class TableInfo(object):
"""
name = attr.ib(validator=attr.validators.instance_of(six.string_types))
- _primary_index = attr.ib(
- validator=attr.validators.optional(attr.validators.instance_of(TableIndex)),
- default=None
- )
- _secondary_indexes = attr.ib(
- validator=attr.validators.optional(iterable_validator(list, TableIndex)),
- default=None
- )
+ _primary_index = attr.ib(validator=attr.validators.optional(attr.validators.instance_of(TableIndex)), default=None)
+ _secondary_indexes = attr.ib(validator=attr.validators.optional(iterable_validator(list, TableIndex)), default=None)
def __init__(
- self,
- name, # type: Text
- primary_index=None, # type: Optional[TableIndex]
- secondary_indexes=None # type: Optional[List[TableIndex]]
+ self,
+ name, # type: Text
+ primary_index=None, # type: Optional[TableIndex]
+ secondary_indexes=None, # type: Optional[List[TableIndex]]
): # noqa=D107
# type: (...) -> None
# Workaround pending resolution of attrs/mypy interaction.
@@ -333,7 +300,7 @@ def primary_index(self):
:raises AttributeError: if primary index is unknown
"""
if self._primary_index is None:
- raise AttributeError('Indexes unknown. Run refresh_indexed_attributes')
+ raise AttributeError("Indexes unknown. Run refresh_indexed_attributes")
return self._primary_index
@property
@@ -346,7 +313,7 @@ def secondary_indexes(self):
:raises AttributeError: if secondary indexes are unknown
"""
if self._secondary_indexes is None:
- raise AttributeError('Indexes unknown. Run refresh_indexed_attributes')
+ raise AttributeError("Indexes unknown. Run refresh_indexed_attributes")
return self._secondary_indexes
def protected_index_keys(self):
@@ -361,12 +328,11 @@ def encryption_context_values(self):
:rtype: dict
"""
- values = {'table_name': self.name}
+ values = {"table_name": self.name}
if self.primary_index is not None:
- values.update({
- 'partition_key_name': self.primary_index.partition,
- 'sort_key_name': self.primary_index.sort
- })
+ values.update(
+ {"partition_key_name": self.primary_index.partition, "sort_key_name": self.primary_index.sort}
+ )
return values
def refresh_indexed_attributes(self, client):
@@ -375,13 +341,13 @@ def refresh_indexed_attributes(self, client):
:param client: Pre-configured boto3 DynamoDB client
:type client: botocore.client.BaseClient
"""
- table = client.describe_table(TableName=self.name)['Table']
- self._primary_index = TableIndex.from_key_schema(table['KeySchema'])
+ table = client.describe_table(TableName=self.name)["Table"]
+ self._primary_index = TableIndex.from_key_schema(table["KeySchema"])
self._secondary_indexes = []
- for group in ('LocalSecondaryIndexes', 'GlobalSecondaryIndexes'):
+ for group in ("LocalSecondaryIndexes", "GlobalSecondaryIndexes"):
try:
for index in table[group]:
- self._secondary_indexes.append(TableIndex.from_key_schema(index['KeySchema']))
+ self._secondary_indexes.append(TableIndex.from_key_schema(index["KeySchema"]))
except KeyError:
pass # Not all tables will have secondary indexes.
diff --git a/src/dynamodb_encryption_sdk/transform.py b/src/dynamodb_encryption_sdk/transform.py
index 8541639a..76b22c6c 100644
--- a/src/dynamodb_encryption_sdk/transform.py
+++ b/src/dynamodb_encryption_sdk/transform.py
@@ -19,7 +19,7 @@
from boto3.dynamodb.types import TypeDeserializer, TypeSerializer
-__all__ = ('dict_to_ddb', 'ddb_to_dict')
+__all__ = ("dict_to_ddb", "ddb_to_dict")
def dict_to_ddb(item):
@@ -32,11 +32,7 @@ def dict_to_ddb(item):
:rtype: dict
"""
serializer = TypeSerializer()
- return {
- key: serializer.serialize(value)
- for key, value
- in item.items()
- }
+ return {key: serializer.serialize(value) for key, value in item.items()}
def ddb_to_dict(item):
@@ -49,8 +45,4 @@ def ddb_to_dict(item):
:rtype: dict
"""
deserializer = TypeDeserializer()
- return {
- key: deserializer.deserialize(value)
- for key, value
- in item.items()
- }
+ return {key: deserializer.deserialize(value) for key, value in item.items()}
diff --git a/src/pylintrc b/src/pylintrc
index c45b647c..81cbacba 100644
--- a/src/pylintrc
+++ b/src/pylintrc
@@ -2,8 +2,11 @@
# Disabling messages that we either don't care about
# for tests or are necessary to break for tests.
#
+# C0330 : bad-continuation (we let black handle this)
+# C0412 : ungrouped-imports (we let isort handle this)
+# R0205 : useless-object-inheritance (we need to support Python 2, so no, not useless)
# R0801 : duplicate-code (causes lots of problems with implementations of common interfaces)
-disable = R0801
+disable = C0330, C0412, R0205, R0801
[BASIC]
# Allow function names up to 50 characters
diff --git a/test/__init__.py b/test/__init__.py
new file mode 100644
index 00000000..2f0470af
--- /dev/null
+++ b/test/__init__.py
@@ -0,0 +1,13 @@
+# Copyright 2018 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.
+"""Stub to allow relative imports between test groups."""
diff --git a/test/acceptance/acceptance_test_utils.py b/test/acceptance/acceptance_test_utils.py
index 8f1c1ee8..5d66bc65 100644
--- a/test/acceptance/acceptance_test_utils.py
+++ b/test/acceptance/acceptance_test_utils.py
@@ -12,11 +12,10 @@
# language governing permissions and limitations under the License.
"""Helper tools for use with acceptance tests."""
import base64
-from collections import defaultdict
-from functools import partial
import json
import os
-import sys
+from collections import defaultdict
+from functools import partial
import boto3
import pytest
@@ -32,30 +31,20 @@
from dynamodb_encryption_sdk.materials.raw import RawDecryptionMaterials
from dynamodb_encryption_sdk.structures import AttributeActions
-sys.path.append(os.path.join(
- os.path.abspath(os.path.dirname(__file__)),
- '..',
- 'functional'
-))
-
-# Convenience imports
-import functional_test_vector_generators # noqa: E402,I100 pylint: disable=import-error,wrong-import-position
+from ..functional import functional_test_vector_generators
_ENCRYPTED_ITEM_VECTORS_DIR = os.path.join(
- os.path.abspath(os.path.dirname(__file__)),
- '..',
- 'vectors',
- 'encrypted_item'
+ os.path.abspath(os.path.dirname(__file__)), "..", "vectors", "encrypted_item"
)
-_SCENARIO_FILE = os.path.join(_ENCRYPTED_ITEM_VECTORS_DIR, 'scenarios.json')
+_SCENARIO_FILE = os.path.join(_ENCRYPTED_ITEM_VECTORS_DIR, "scenarios.json")
def _filename_from_uri(uri):
parsed = urlparse(uri)
- if parsed.scheme != 'file':
+ if parsed.scheme != "file":
raise ValueError('Unsupported URI scheme: "{}"'.format(parsed.scheme))
relative_path = [parsed.netloc]
- for part in parsed.path.split('/'):
+ for part in parsed.path.split("/"):
if part:
relative_path.append(part)
return os.path.join(_ENCRYPTED_ITEM_VECTORS_DIR, *relative_path)
@@ -76,38 +65,28 @@ def _build_plaintext_items(plaintext_file, version):
plaintext_data = json.load(f)
actions = {}
- for name, description in plaintext_data['actions'].items():
- default_action = _action(description['default'])
+ for name, description in plaintext_data["actions"].items():
+ default_action = _action(description["default"])
attribute_actions = {
attribute_name: _action(attribute_action)
- for attribute_name, attribute_action
- in description.get('override', {}).items()
+ for attribute_name, attribute_action in description.get("override", {}).items()
}
- actions[name.lower()] = AttributeActions(
- default_action=default_action,
- attribute_actions=attribute_actions
- )
+ actions[name.lower()] = AttributeActions(default_action=default_action, attribute_actions=attribute_actions)
tables = defaultdict(list)
- for table_name, table_data in plaintext_data['items'].items():
+ for table_name, table_data in plaintext_data["items"].items():
table_items = []
- for item in table_data['items']:
- item_actions = actions[item['action']].copy()
- item_actions.set_index_keys(*table_data['index'].values())
- attributes = item['attributes'].copy()
- if not item.get('exact', False):
- for group in plaintext_data['versions'].get(table_name, {}).get(version, []):
- attributes.update(plaintext_data['attributes'][group])
+ for item in table_data["items"]:
+ item_actions = actions[item["action"]].copy()
+ item_actions.set_index_keys(*table_data["index"].values())
+ attributes = item["attributes"].copy()
+ if not item.get("exact", False):
+ for group in plaintext_data["versions"].get(table_name, {}).get(version, []):
+ attributes.update(plaintext_data["attributes"][group])
_decode_item(attributes)
- table_items.append(dict(
- item=attributes,
- action=item_actions
- ))
-
- tables[table_name] = dict(
- index=table_data['index'],
- items=table_items
- )
+ table_items.append(dict(item=attributes, action=item_actions))
+
+ tables[table_name] = dict(index=table_data["index"], items=table_items)
return tables
@@ -129,55 +108,43 @@ def _load_keys(keys_file):
_KEY_TYPE = {
- 'SYMMETRIC': EncryptionKeyType.SYMMETRIC,
- 'PUBLIC': EncryptionKeyType.PUBLIC,
- 'PRIVATE': EncryptionKeyType.PRIVATE
-}
-_KEY_ENCODING = {
- 'RAW': KeyEncodingType.RAW,
- 'DER': KeyEncodingType.DER
+ "SYMMETRIC": EncryptionKeyType.SYMMETRIC,
+ "PUBLIC": EncryptionKeyType.PUBLIC,
+ "PRIVATE": EncryptionKeyType.PRIVATE,
}
+_KEY_ENCODING = {"RAW": KeyEncodingType.RAW, "DER": KeyEncodingType.DER}
def _load_key(key):
- key_material = base64.b64decode(key['material'])
- key_type = _KEY_TYPE[key['type'].upper()]
- key_encoding = _KEY_ENCODING[key['encoding'].upper()]
+ key_material = base64.b64decode(key["material"])
+ key_type = _KEY_TYPE[key["type"].upper()]
+ key_encoding = _KEY_ENCODING[key["encoding"].upper()]
return JceNameLocalDelegatedKey(
- key=key_material,
- algorithm=key['algorithm'],
- key_type=key_type,
- key_encoding=key_encoding
+ key=key_material, algorithm=key["algorithm"], key_type=key_type, key_encoding=key_encoding
)
def _load_signing_key(key):
- if key['type'].upper() == 'RSA':
- key['type'] = 'RSA'
+ if key["type"].upper() == "RSA":
+ key["type"] = "RSA"
return _load_key(key)
def _build_static_cmp(decrypt_key, verify_key):
decryption_key = _load_key(decrypt_key)
verification_key = _load_signing_key(verify_key)
- decryption_materials = RawDecryptionMaterials(
- decryption_key=decryption_key,
- verification_key=verification_key
- )
+ decryption_materials = RawDecryptionMaterials(decryption_key=decryption_key, verification_key=verification_key)
return StaticCryptographicMaterialsProvider(decryption_materials=decryption_materials)
def _build_wrapped_cmp(decrypt_key, verify_key):
unwrapping_key = _load_key(decrypt_key)
signing_key = _load_signing_key(verify_key)
- return WrappedCryptographicMaterialsProvider(
- signing_key=signing_key,
- unwrapping_key=unwrapping_key
- )
+ return WrappedCryptographicMaterialsProvider(signing_key=signing_key, unwrapping_key=unwrapping_key)
def _build_aws_kms_cmp(decrypt_key, verify_key):
- key_id = decrypt_key['keyId']
+ key_id = decrypt_key["keyId"]
return AwsKmsCryptographicMaterialsProvider(key_id=key_id)
@@ -185,7 +152,7 @@ def _meta_table_prep(table_name, items_filename):
if table_name is None:
return
- client = boto3.client('dynamodb', region_name='us-west-2')
+ client = boto3.client("dynamodb", region_name="us-west-2")
MetaStore.create_table(client, table_name, 100, 100)
with open(_filename_from_uri(items_filename)) as f:
@@ -196,49 +163,47 @@ def _meta_table_prep(table_name, items_filename):
requests = []
for item in items:
_decode_item(item)
- requests.append({'PutRequest': {'Item': item}})
+ requests.append({"PutRequest": {"Item": item}})
request_items[table_name] = requests
client.batch_write_item(RequestItems=request_items)
def _build_most_recent_cmp(scenario, keys):
- table = boto3.resource('dynamodb', region_name='us-west-2').Table(scenario['metastore']['table_name'])
- meta_cmp, _, _ = _build_cmp(scenario['metastore'], keys)
+ table = boto3.resource("dynamodb", region_name="us-west-2").Table(scenario["metastore"]["table_name"])
+ meta_cmp, _, _ = _build_cmp(scenario["metastore"], keys)
metastore = MetaStore(table=table, materials_provider=meta_cmp())
most_recent_cmp = MostRecentProvider(
- provider_store=metastore,
- material_name=scenario['material_name'],
- version_ttl=600.0
+ provider_store=metastore, material_name=scenario["material_name"], version_ttl=600.0
)
return most_recent_cmp
_CMP_TYPE_MAP = {
- 'STATIC': _build_static_cmp,
- 'WRAPPED': _build_wrapped_cmp,
- 'AWSKMS': _build_aws_kms_cmp,
- 'MOST_RECENT': _build_most_recent_cmp
+ "STATIC": _build_static_cmp,
+ "WRAPPED": _build_wrapped_cmp,
+ "AWSKMS": _build_aws_kms_cmp,
+ "MOST_RECENT": _build_most_recent_cmp,
}
def _build_cmp(scenario, keys):
try:
- cmp_builder = _CMP_TYPE_MAP[scenario['provider'].upper()]
+ cmp_builder = _CMP_TYPE_MAP[scenario["provider"].upper()]
except KeyError:
- raise ValueError('Unsupported cryptographic materials provider type: "{}"'.format(scenario['provider']))
+ raise ValueError('Unsupported cryptographic materials provider type: "{}"'.format(scenario["provider"]))
if cmp_builder is _build_most_recent_cmp:
return (
partial(cmp_builder, scenario, keys),
- scenario['metastore']['keys']['decrypt'],
- scenario['metastore']['keys']['verify']
+ scenario["metastore"]["keys"]["decrypt"],
+ scenario["metastore"]["keys"]["verify"],
)
return (
- partial(cmp_builder, keys[scenario['keys']['decrypt']], keys[scenario['keys']['verify']]),
- scenario['keys']['decrypt'],
- scenario['keys']['verify']
+ partial(cmp_builder, keys[scenario["keys"]["decrypt"]], keys[scenario["keys"]["verify"]]),
+ scenario["keys"]["decrypt"],
+ scenario["keys"]["verify"],
)
@@ -248,13 +213,13 @@ def _index(item, keys):
def _expand_items(ciphertext_items, plaintext_items):
for table_name, table_items in ciphertext_items.items():
- table_index = plaintext_items[table_name]['index']
+ table_index = plaintext_items[table_name]["index"]
for ciphertext_item in table_items:
- ct_index = _index(ciphertext_item, plaintext_items[table_name]['index'].values())
+ ct_index = _index(ciphertext_item, plaintext_items[table_name]["index"].values())
pt_items = [
- item for item
- in plaintext_items[table_name]['items']
- if ct_index == _index(item['item'], plaintext_items[table_name]['index'].values())
+ item
+ for item in plaintext_items[table_name]["items"]
+ if ct_index == _index(item["item"], plaintext_items[table_name]["index"].values())
]
if not pt_items:
continue
@@ -263,30 +228,30 @@ def _expand_items(ciphertext_items, plaintext_items):
raise Exception('TODO: Ciphertext matches multiple plaintext items: "{}"'.format(ct_index))
pt_item = pt_items[0]
- yield table_name, table_index, ciphertext_item, pt_item['item'], pt_item['action']
+ yield table_name, table_index, ciphertext_item, pt_item["item"], pt_item["action"]
def load_scenarios(online):
# pylint: disable=too-many-locals
with open(_SCENARIO_FILE) as f:
scenarios = json.load(f)
- keys_file = _filename_from_uri(scenarios['keys'])
+ keys_file = _filename_from_uri(scenarios["keys"])
keys = _load_keys(keys_file)
- for scenario in scenarios['scenarios']:
- if (not online and scenario['network']) or (online and not scenario['network']):
+ for scenario in scenarios["scenarios"]:
+ if (not online and scenario["network"]) or (online and not scenario["network"]):
continue
- plaintext_file = _filename_from_uri(scenario['plaintext'])
- plaintext_items = _build_plaintext_items(plaintext_file, scenario['version'])
+ plaintext_file = _filename_from_uri(scenario["plaintext"])
+ plaintext_items = _build_plaintext_items(plaintext_file, scenario["version"])
- ciphertext_file = _filename_from_uri(scenario['ciphertext'])
+ ciphertext_file = _filename_from_uri(scenario["ciphertext"])
ciphertext_items = _load_ciphertext_items(ciphertext_file)
materials_provider, decrypt_key_name, verify_key_name = _build_cmp(scenario, keys)
items = _expand_items(ciphertext_items, plaintext_items)
- metastore_info = scenario.get('metastore', {'table_name': None, 'ciphertext': None})
+ metastore_info = scenario.get("metastore", {"table_name": None, "ciphertext": None})
for table_name, table_index, ciphertext_item, plaintext_item, attribute_actions in items:
item_index = _index(ciphertext_item, table_index.values())
@@ -297,13 +262,13 @@ def load_scenarios(online):
ciphertext_item,
plaintext_item,
attribute_actions,
- partial(_meta_table_prep, metastore_info['table_name'], metastore_info['ciphertext']),
- id='{version}-{provider}-{decrypt_key}-{verify_key}-{table}-{index}'.format(
- version=scenario['version'],
- provider=scenario['provider'],
+ partial(_meta_table_prep, metastore_info["table_name"], metastore_info["ciphertext"]),
+ id="{version}-{provider}-{decrypt_key}-{verify_key}-{table}-{index}".format(
+ version=scenario["version"],
+ provider=scenario["provider"],
decrypt_key=decrypt_key_name,
verify_key=verify_key_name,
table=table_name,
- index=str(item_index)
- )
+ index=str(item_index),
+ ),
)
diff --git a/test/acceptance/encrypted/test_client.py b/test/acceptance/encrypted/test_client.py
index 46b7ae7b..493740a3 100644
--- a/test/acceptance/encrypted/test_client.py
+++ b/test/acceptance/encrypted/test_client.py
@@ -12,13 +12,14 @@
# language governing permissions and limitations under the License.
"""Acceptance tests for ``dynamodb_encryption_sdk.encrypted.client``."""
import botocore
+import pytest
from mock import MagicMock
from moto import mock_dynamodb2
-import pytest
from dynamodb_encryption_sdk.encrypted.client import EncryptedClient
from dynamodb_encryption_sdk.structures import TableIndex, TableInfo
from dynamodb_encryption_sdk.transform import dict_to_ddb
+
from ..acceptance_test_utils import load_scenarios
pytestmark = [pytest.mark.accept]
@@ -26,150 +27,87 @@
def fake_client(table_name, item):
client = MagicMock(__class__=botocore.client.BaseClient)
- client.get_item.return_value = {'Item': item.copy()}
- client.batch_get_item.return_value = {'Responses': {table_name: [item.copy()]}}
+ client.get_item.return_value = {"Item": item.copy()}
+ client.batch_get_item.return_value = {"Responses": {table_name: [item.copy()]}}
return client
def _compare_item(plaintext_item, decrypted_item):
assert set(decrypted_item.keys()) == set(plaintext_item.keys())
for key in decrypted_item:
- if key == 'version':
+ if key == "version":
continue
assert decrypted_item[key] == plaintext_item[key]
-def _client_setup(
- materials_provider,
- table_name,
- table_index,
- ciphertext_item,
- attribute_actions,
- prep
-):
+def _client_setup(materials_provider, table_name, table_index, ciphertext_item, attribute_actions, prep):
prep() # Test scenario setup that needs to happen inside the test
cmp = materials_provider() # Some of the materials providers need to be constructed inside the test
client = fake_client(table_name, ciphertext_item)
table_info = TableInfo(
name=table_name,
- primary_index=TableIndex(
- partition=table_index['partition'],
- sort=table_index.get('sort', None)
- )
+ primary_index=TableIndex(partition=table_index["partition"], sort=table_index.get("sort", None)),
)
item_key = {table_info.primary_index.partition: ciphertext_item[table_info.primary_index.partition]}
if table_info.primary_index.sort is not None:
item_key[table_info.primary_index.sort] = ciphertext_item[table_info.primary_index.sort]
e_client = EncryptedClient(
- client=client,
- materials_provider=cmp,
- attribute_actions=attribute_actions,
- auto_refresh_table_indexes=False
+ client=client, materials_provider=cmp, attribute_actions=attribute_actions, auto_refresh_table_indexes=False
)
e_client._table_info_cache._all_tables_info[table_name] = table_info
return e_client, dict_to_ddb(item_key)
-def _item_check(
- materials_provider,
- table_name,
- table_index,
- ciphertext_item,
- plaintext_item,
- attribute_actions,
- prep
-):
+def _item_check(materials_provider, table_name, table_index, ciphertext_item, plaintext_item, attribute_actions, prep):
e_client, item_key = _client_setup(
- materials_provider,
- table_name,
- table_index,
- ciphertext_item,
- attribute_actions,
- prep
+ materials_provider, table_name, table_index, ciphertext_item, attribute_actions, prep
)
- decrypted_item = e_client.get_item(TableName=table_name, Key=item_key)['Item']
+ decrypted_item = e_client.get_item(TableName=table_name, Key=item_key)["Item"]
_compare_item(plaintext_item, decrypted_item)
def _batch_items_check(
- materials_provider,
- table_name,
- table_index,
- ciphertext_item,
- plaintext_item,
- attribute_actions,
- prep
+ materials_provider, table_name, table_index, ciphertext_item, plaintext_item, attribute_actions, prep
):
e_client, item_key = _client_setup(
- materials_provider,
- table_name,
- table_index,
- ciphertext_item,
- attribute_actions,
- prep
+ materials_provider, table_name, table_index, ciphertext_item, attribute_actions, prep
)
- response = e_client.batch_get_item(RequestItems={table_name: {'Keys': [item_key]}})
- decrypted_item = response['Responses'][table_name][0]
+ response = e_client.batch_get_item(RequestItems={table_name: {"Keys": [item_key]}})
+ decrypted_item = response["Responses"][table_name][0]
_compare_item(plaintext_item, decrypted_item)
def pytest_generate_tests(metafunc):
- if 'item_checker' in metafunc.fixturenames:
- metafunc.parametrize('item_checker', (
- pytest.param(_item_check, id='single-item'),
- pytest.param(_batch_items_check, id='batch-items')
- ))
+ if "item_checker" in metafunc.fixturenames:
+ metafunc.parametrize(
+ "item_checker",
+ (pytest.param(_item_check, id="single-item"), pytest.param(_batch_items_check, id="batch-items")),
+ )
@mock_dynamodb2
@pytest.mark.local
@pytest.mark.parametrize(
- 'materials_provider, table_name, table_index, ciphertext_item, plaintext_item, attribute_actions, prep',
- load_scenarios(online=False)
+ "materials_provider, table_name, table_index, ciphertext_item, plaintext_item, attribute_actions, prep",
+ load_scenarios(online=False),
)
def test_client_get_offline(
- materials_provider,
- table_name,
- table_index,
- ciphertext_item,
- plaintext_item,
- attribute_actions,
- prep,
- item_checker
+ materials_provider, table_name, table_index, ciphertext_item, plaintext_item, attribute_actions, prep, item_checker
):
return item_checker(
- materials_provider,
- table_name,
- table_index,
- ciphertext_item,
- plaintext_item,
- attribute_actions,
- prep
+ materials_provider, table_name, table_index, ciphertext_item, plaintext_item, attribute_actions, prep
)
@pytest.mark.integ
@pytest.mark.parametrize(
- 'materials_provider, table_name, table_index, ciphertext_item, plaintext_item, attribute_actions, prep',
- load_scenarios(online=True)
+ "materials_provider, table_name, table_index, ciphertext_item, plaintext_item, attribute_actions, prep",
+ load_scenarios(online=True),
)
def test_client_get_online(
- materials_provider,
- table_name,
- table_index,
- ciphertext_item,
- plaintext_item,
- attribute_actions,
- prep,
- item_checker
+ materials_provider, table_name, table_index, ciphertext_item, plaintext_item, attribute_actions, prep, item_checker
):
return item_checker(
- materials_provider,
- table_name,
- table_index,
- ciphertext_item,
- plaintext_item,
- attribute_actions,
- prep
+ materials_provider, table_name, table_index, ciphertext_item, plaintext_item, attribute_actions, prep
)
diff --git a/test/acceptance/encrypted/test_item.py b/test/acceptance/encrypted/test_item.py
index 2fe3a745..b7e1b85e 100644
--- a/test/acceptance/encrypted/test_item.py
+++ b/test/acceptance/encrypted/test_item.py
@@ -11,43 +11,34 @@
# ANY KIND, either express or implied. See the License for the specific
# language governing permissions and limitations under the License.
"""Acceptance tests for ``dynamodb_encryption_sdk.encrypted.item``."""
-from moto import mock_dynamodb2
import pytest
+from moto import mock_dynamodb2
from dynamodb_encryption_sdk.encrypted import CryptoConfig
from dynamodb_encryption_sdk.encrypted.item import decrypt_dynamodb_item
from dynamodb_encryption_sdk.structures import EncryptionContext
+
from ..acceptance_test_utils import load_scenarios
pytestmark = [pytest.mark.accept]
-def _item_check(
- materials_provider,
- table_name,
- table_index,
- ciphertext_item,
- plaintext_item,
- attribute_actions,
- prep
-):
+def _item_check(materials_provider, table_name, table_index, ciphertext_item, plaintext_item, attribute_actions, prep):
prep() # Test scenario setup that needs to happen inside the test
cmp = materials_provider() # Some of the materials providers need to be constructed inside the test
encryption_context = EncryptionContext(
table_name=table_name,
- partition_key_name=table_index['partition'],
- sort_key_name=table_index.get('sort', None),
- attributes=ciphertext_item
+ partition_key_name=table_index["partition"],
+ sort_key_name=table_index.get("sort", None),
+ attributes=ciphertext_item,
)
crypto_config = CryptoConfig(
- materials_provider=cmp,
- encryption_context=encryption_context,
- attribute_actions=attribute_actions
+ materials_provider=cmp, encryption_context=encryption_context, attribute_actions=attribute_actions
)
decrypted_item = decrypt_dynamodb_item(ciphertext_item.copy(), crypto_config)
assert set(decrypted_item.keys()) == set(plaintext_item.keys())
for key in decrypted_item:
- if key == 'version':
+ if key == "version":
continue
assert decrypted_item[key] == plaintext_item[key]
@@ -55,49 +46,25 @@ def _item_check(
@mock_dynamodb2
@pytest.mark.local
@pytest.mark.parametrize(
- 'materials_provider, table_name, table_index, ciphertext_item, plaintext_item, attribute_actions, prep',
- load_scenarios(online=False)
+ "materials_provider, table_name, table_index, ciphertext_item, plaintext_item, attribute_actions, prep",
+ load_scenarios(online=False),
)
def test_item_encryptor_offline(
- materials_provider,
- table_name,
- table_index,
- ciphertext_item,
- plaintext_item,
- attribute_actions,
- prep
+ materials_provider, table_name, table_index, ciphertext_item, plaintext_item, attribute_actions, prep
):
return _item_check(
- materials_provider,
- table_name,
- table_index,
- ciphertext_item,
- plaintext_item,
- attribute_actions,
- prep
+ materials_provider, table_name, table_index, ciphertext_item, plaintext_item, attribute_actions, prep
)
@pytest.mark.integ
@pytest.mark.parametrize(
- 'materials_provider, table_name, table_index, ciphertext_item, plaintext_item, attribute_actions, prep',
- load_scenarios(online=True)
+ "materials_provider, table_name, table_index, ciphertext_item, plaintext_item, attribute_actions, prep",
+ load_scenarios(online=True),
)
def test_item_encryptor_online(
- materials_provider,
- table_name,
- table_index,
- ciphertext_item,
- plaintext_item,
- attribute_actions,
- prep
+ materials_provider, table_name, table_index, ciphertext_item, plaintext_item, attribute_actions, prep
):
return _item_check(
- materials_provider,
- table_name,
- table_index,
- ciphertext_item,
- plaintext_item,
- attribute_actions,
- prep
+ materials_provider, table_name, table_index, ciphertext_item, plaintext_item, attribute_actions, prep
)
diff --git a/test/acceptance/encrypted/test_resource.py b/test/acceptance/encrypted/test_resource.py
index b88c01ea..17da5317 100644
--- a/test/acceptance/encrypted/test_resource.py
+++ b/test/acceptance/encrypted/test_resource.py
@@ -11,16 +11,17 @@
# ANY KIND, either express or implied. See the License for the specific
# language governing permissions and limitations under the License.
"""Acceptance tests for ``dynamodb_encryption_sdk.encrypted.resource``."""
+import botocore
+import pytest
from boto3.resources.base import ServiceResource
from boto3.resources.collection import CollectionManager
-import botocore
from mock import MagicMock
from moto import mock_dynamodb2
-import pytest
from dynamodb_encryption_sdk.encrypted.resource import EncryptedResource
from dynamodb_encryption_sdk.structures import TableIndex, TableInfo
from dynamodb_encryption_sdk.transform import ddb_to_dict
+
from ..acceptance_test_utils import load_scenarios
pytestmark = [pytest.mark.accept]
@@ -28,7 +29,7 @@
def fake_resource(table_name, item):
resource = MagicMock(__class__=ServiceResource)
- resource.batch_get_item.return_value = {'Responses': {table_name: [item.copy()]}}
+ resource.batch_get_item.return_value = {"Responses": {table_name: [item.copy()]}}
resource.meta.client = MagicMock(__class__=botocore.client.BaseClient)
resource.tables = MagicMock(__class__=CollectionManager)
return resource
@@ -37,113 +38,65 @@ def fake_resource(table_name, item):
def _compare_item(plaintext_item, decrypted_item):
assert set(decrypted_item.keys()) == set(plaintext_item.keys())
for key in decrypted_item:
- if key == 'version':
+ if key == "version":
continue
assert decrypted_item[key] == plaintext_item[key]
-def _resource_setup(
- materials_provider,
- table_name,
- table_index,
- ciphertext_item,
- attribute_actions,
- prep
-):
+def _resource_setup(materials_provider, table_name, table_index, ciphertext_item, attribute_actions, prep):
prep() # Test scenario setup that needs to happen inside the test
cmp = materials_provider() # Some of the materials providers need to be constructed inside the test
resource = fake_resource(table_name, ciphertext_item)
table_info = TableInfo(
name=table_name,
- primary_index=TableIndex(
- partition=table_index['partition'],
- sort=table_index.get('sort', None)
- )
+ primary_index=TableIndex(partition=table_index["partition"], sort=table_index.get("sort", None)),
)
item_key = {table_info.primary_index.partition: ciphertext_item[table_info.primary_index.partition]}
if table_info.primary_index.sort is not None:
item_key[table_info.primary_index.sort] = ciphertext_item[table_info.primary_index.sort]
e_resource = EncryptedResource(
- resource=resource,
- materials_provider=cmp,
- attribute_actions=attribute_actions,
- auto_refresh_table_indexes=False
+ resource=resource, materials_provider=cmp, attribute_actions=attribute_actions, auto_refresh_table_indexes=False
)
e_resource._table_info_cache._all_tables_info[table_name] = table_info
return e_resource, item_key
def _batch_items_check(
- materials_provider,
- table_name,
- table_index,
- ciphertext_item,
- plaintext_item,
- attribute_actions,
- prep
+ materials_provider, table_name, table_index, ciphertext_item, plaintext_item, attribute_actions, prep
):
plaintext_item = ddb_to_dict(plaintext_item)
ciphertext_item = ddb_to_dict(ciphertext_item)
e_resource, item_key = _resource_setup(
- materials_provider,
- table_name,
- table_index,
- ciphertext_item,
- attribute_actions,
- prep
+ materials_provider, table_name, table_index, ciphertext_item, attribute_actions, prep
)
- response = e_resource.batch_get_item(RequestItems={table_name: {'Keys': [item_key]}})
- decrypted_item = response['Responses'][table_name][0]
+ response = e_resource.batch_get_item(RequestItems={table_name: {"Keys": [item_key]}})
+ decrypted_item = response["Responses"][table_name][0]
_compare_item(plaintext_item, decrypted_item)
@mock_dynamodb2
@pytest.mark.local
@pytest.mark.parametrize(
- 'materials_provider, table_name, table_index, ciphertext_item, plaintext_item, attribute_actions, prep',
- load_scenarios(online=False)
+ "materials_provider, table_name, table_index, ciphertext_item, plaintext_item, attribute_actions, prep",
+ load_scenarios(online=False),
)
def test_client_get_offline(
- materials_provider,
- table_name,
- table_index,
- ciphertext_item,
- plaintext_item,
- attribute_actions,
- prep
+ materials_provider, table_name, table_index, ciphertext_item, plaintext_item, attribute_actions, prep
):
return _batch_items_check(
- materials_provider,
- table_name,
- table_index,
- ciphertext_item,
- plaintext_item,
- attribute_actions,
- prep
+ materials_provider, table_name, table_index, ciphertext_item, plaintext_item, attribute_actions, prep
)
@pytest.mark.integ
@pytest.mark.parametrize(
- 'materials_provider, table_name, table_index, ciphertext_item, plaintext_item, attribute_actions, prep',
- load_scenarios(online=True)
+ "materials_provider, table_name, table_index, ciphertext_item, plaintext_item, attribute_actions, prep",
+ load_scenarios(online=True),
)
def test_client_get_online(
- materials_provider,
- table_name,
- table_index,
- ciphertext_item,
- plaintext_item,
- attribute_actions,
- prep
+ materials_provider, table_name, table_index, ciphertext_item, plaintext_item, attribute_actions, prep
):
return _batch_items_check(
- materials_provider,
- table_name,
- table_index,
- ciphertext_item,
- plaintext_item,
- attribute_actions,
- prep
+ materials_provider, table_name, table_index, ciphertext_item, plaintext_item, attribute_actions, prep
)
diff --git a/test/acceptance/encrypted/test_table.py b/test/acceptance/encrypted/test_table.py
index 9454cf25..91adc9b5 100644
--- a/test/acceptance/encrypted/test_table.py
+++ b/test/acceptance/encrypted/test_table.py
@@ -11,14 +11,15 @@
# ANY KIND, either express or implied. See the License for the specific
# language governing permissions and limitations under the License.
"""Acceptance tests for ``dynamodb_encryption_sdk.encrypted.table``."""
+import pytest
from boto3.resources.base import ServiceResource
from mock import MagicMock
from moto import mock_dynamodb2
-import pytest
from dynamodb_encryption_sdk.encrypted.table import EncryptedTable
from dynamodb_encryption_sdk.structures import TableIndex, TableInfo
from dynamodb_encryption_sdk.transform import ddb_to_dict
+
from ..acceptance_test_utils import load_scenarios
pytestmark = [pytest.mark.accept]
@@ -26,19 +27,11 @@
def fake_table(item):
table = MagicMock(__class__=ServiceResource)
- table.get_item.return_value = {'Item': item}
+ table.get_item.return_value = {"Item": item}
return table
-def _item_check(
- materials_provider,
- table_name,
- table_index,
- ciphertext_item,
- plaintext_item,
- attribute_actions,
- prep
-):
+def _item_check(materials_provider, table_name, table_index, ciphertext_item, plaintext_item, attribute_actions, prep):
ciphertext_item = ddb_to_dict(ciphertext_item)
plaintext_item = ddb_to_dict(plaintext_item)
prep() # Test scenario setup that needs to happen inside the test
@@ -46,10 +39,7 @@ def _item_check(
table = fake_table(ciphertext_item)
table_info = TableInfo(
name=table_name,
- primary_index=TableIndex(
- partition=table_index['partition'],
- sort=table_index.get('sort', None)
- )
+ primary_index=TableIndex(partition=table_index["partition"], sort=table_index.get("sort", None)),
)
item_key = {table_info.primary_index.partition: ciphertext_item[table_info.primary_index.partition]}
if table_info.primary_index.sort is not None:
@@ -60,12 +50,12 @@ def _item_check(
materials_provider=cmp,
table_info=table_info,
attribute_actions=attribute_actions,
- auto_refresh_table_indexes=False
+ auto_refresh_table_indexes=False,
)
- decrypted_item = e_table.get_item(Key=item_key)['Item']
+ decrypted_item = e_table.get_item(Key=item_key)["Item"]
assert set(decrypted_item.keys()) == set(plaintext_item.keys())
for key in decrypted_item:
- if key == 'version':
+ if key == "version":
continue
assert decrypted_item[key] == plaintext_item[key]
@@ -73,49 +63,25 @@ def _item_check(
@mock_dynamodb2
@pytest.mark.local
@pytest.mark.parametrize(
- 'materials_provider, table_name, table_index, ciphertext_item, plaintext_item, attribute_actions, prep',
- load_scenarios(online=False)
+ "materials_provider, table_name, table_index, ciphertext_item, plaintext_item, attribute_actions, prep",
+ load_scenarios(online=False),
)
def test_table_get_offline(
- materials_provider,
- table_name,
- table_index,
- ciphertext_item,
- plaintext_item,
- attribute_actions,
- prep
+ materials_provider, table_name, table_index, ciphertext_item, plaintext_item, attribute_actions, prep
):
return _item_check(
- materials_provider,
- table_name,
- table_index,
- ciphertext_item,
- plaintext_item,
- attribute_actions,
- prep
+ materials_provider, table_name, table_index, ciphertext_item, plaintext_item, attribute_actions, prep
)
@pytest.mark.integ
@pytest.mark.parametrize(
- 'materials_provider, table_name, table_index, ciphertext_item, plaintext_item, attribute_actions, prep',
- load_scenarios(online=True)
+ "materials_provider, table_name, table_index, ciphertext_item, plaintext_item, attribute_actions, prep",
+ load_scenarios(online=True),
)
def test_table_get_online(
- materials_provider,
- table_name,
- table_index,
- ciphertext_item,
- plaintext_item,
- attribute_actions,
- prep
+ materials_provider, table_name, table_index, ciphertext_item, plaintext_item, attribute_actions, prep
):
return _item_check(
- materials_provider,
- table_name,
- table_index,
- ciphertext_item,
- plaintext_item,
- attribute_actions,
- prep
+ materials_provider, table_name, table_index, ciphertext_item, plaintext_item, attribute_actions, prep
)
diff --git a/test/functional/delegated_keys/test_jce.py b/test/functional/delegated_keys/test_jce.py
index 2c88902e..a1e25d80 100644
--- a/test/functional/delegated_keys/test_jce.py
+++ b/test/functional/delegated_keys/test_jce.py
@@ -11,9 +11,9 @@
# ANY KIND, either express or implied. See the License for the specific
# language governing permissions and limitations under the License.
"""Functional test suite for ``dynamodb_encryption_sdk.delegated_keys.jce``."""
+import pytest
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import serialization
-import pytest
from dynamodb_encryption_sdk.delegated_keys.jce import JceNameLocalDelegatedKey
@@ -29,19 +29,22 @@ def _find_rsa_key_length(key):
return loaded_key._key_size
-@pytest.mark.parametrize('algorithm, requested_bits, expected_bits, length_finder', (
- ('AES', 256, 256, _find_aes_key_length),
- ('AESWrap', 256, 256, _find_aes_key_length),
- ('RSA', 4096, 4096, _find_rsa_key_length),
- ('HmacSHA512', 256, 256, _find_aes_key_length),
- ('HmacSHA256', 256, 256, _find_aes_key_length),
- ('HmacSHA384', 256, 256, _find_aes_key_length),
- ('HmacSHA224', 256, 256, _find_aes_key_length),
- ('SHA512withRSA', 4096, 4096, _find_rsa_key_length),
- ('SHA256withRSA', 4096, 4096, _find_rsa_key_length),
- ('SHA384withRSA', 4096, 4096, _find_rsa_key_length),
- ('SHA224withRSA', 4096, 4096, _find_rsa_key_length)
-))
+@pytest.mark.parametrize(
+ "algorithm, requested_bits, expected_bits, length_finder",
+ (
+ ("AES", 256, 256, _find_aes_key_length),
+ ("AESWrap", 256, 256, _find_aes_key_length),
+ ("RSA", 4096, 4096, _find_rsa_key_length),
+ ("HmacSHA512", 256, 256, _find_aes_key_length),
+ ("HmacSHA256", 256, 256, _find_aes_key_length),
+ ("HmacSHA384", 256, 256, _find_aes_key_length),
+ ("HmacSHA224", 256, 256, _find_aes_key_length),
+ ("SHA512withRSA", 4096, 4096, _find_rsa_key_length),
+ ("SHA256withRSA", 4096, 4096, _find_rsa_key_length),
+ ("SHA384withRSA", 4096, 4096, _find_rsa_key_length),
+ ("SHA224withRSA", 4096, 4096, _find_rsa_key_length),
+ ),
+)
def test_generate_correct_key_length(algorithm, requested_bits, expected_bits, length_finder):
test = JceNameLocalDelegatedKey.generate(algorithm, requested_bits)
diff --git a/test/functional/encrypted/test_client.py b/test/functional/encrypted/test_client.py
index fca79487..f7a76b56 100644
--- a/test/functional/encrypted/test_client.py
+++ b/test/functional/encrypted/test_client.py
@@ -14,13 +14,17 @@
import hypothesis
import pytest
+from ..functional_test_utils import example_table # noqa pylint: disable=unused-import
from ..functional_test_utils import (
- client_cycle_batch_items_check, client_cycle_batch_items_check_paginators, client_cycle_single_item_check,
- set_parametrized_actions, set_parametrized_cmp, set_parametrized_item,
- TEST_TABLE_NAME
+ TEST_TABLE_NAME,
+ client_cycle_batch_items_check,
+ client_cycle_batch_items_check_paginators,
+ client_cycle_single_item_check,
+ set_parametrized_actions,
+ set_parametrized_cmp,
+ set_parametrized_item,
)
-from ..functional_test_utils import example_table # noqa pylint: disable=unused-import
-from ..hypothesis_strategies import ddb_items, SLOW_SETTINGS, VERY_SLOW_SETTINGS
+from ..hypothesis_strategies import SLOW_SETTINGS, VERY_SLOW_SETTINGS, ddb_items
pytestmark = [pytest.mark.functional, pytest.mark.local]
@@ -33,31 +37,19 @@ def pytest_generate_tests(metafunc):
def _client_cycle_single_item_check(materials_provider, initial_actions, initial_item):
return client_cycle_single_item_check(
- materials_provider,
- initial_actions,
- initial_item,
- TEST_TABLE_NAME,
- 'us-west-2'
+ materials_provider, initial_actions, initial_item, TEST_TABLE_NAME, "us-west-2"
)
def _client_cycle_batch_items_check(materials_provider, initial_actions, initial_item):
return client_cycle_batch_items_check(
- materials_provider,
- initial_actions,
- initial_item,
- TEST_TABLE_NAME,
- 'us-west-2'
+ materials_provider, initial_actions, initial_item, TEST_TABLE_NAME, "us-west-2"
)
def _client_cycle_batch_items_check_paginators(materials_provider, initial_actions, initial_item):
return client_cycle_batch_items_check_paginators(
- materials_provider,
- initial_actions,
- initial_item,
- TEST_TABLE_NAME,
- 'us-west-2'
+ materials_provider, initial_actions, initial_item, TEST_TABLE_NAME, "us-west-2"
)
diff --git a/test/functional/encrypted/test_item.py b/test/functional/encrypted/test_item.py
index dd475e11..c51e4851 100644
--- a/test/functional/encrypted/test_item.py
+++ b/test/functional/encrypted/test_item.py
@@ -23,10 +23,15 @@
from dynamodb_encryption_sdk.material_providers.static import StaticCryptographicMaterialsProvider
from dynamodb_encryption_sdk.materials.raw import RawDecryptionMaterials, RawEncryptionMaterials
from dynamodb_encryption_sdk.structures import AttributeActions, EncryptionContext
+
from ..functional_test_utils import (
- build_static_jce_cmp, cycle_item_check, set_parametrized_actions, set_parametrized_cmp, set_parametrized_item
+ build_static_jce_cmp,
+ cycle_item_check,
+ set_parametrized_actions,
+ set_parametrized_cmp,
+ set_parametrized_item,
)
-from ..hypothesis_strategies import ddb_items, SLOW_SETTINGS, VERY_SLOW_SETTINGS
+from ..hypothesis_strategies import SLOW_SETTINGS, VERY_SLOW_SETTINGS, ddb_items
pytestmark = [pytest.mark.functional, pytest.mark.local]
@@ -40,80 +45,81 @@ def pytest_generate_tests(metafunc):
@pytest.fixture
def static_cmp_crypto_config():
return CryptoConfig(
- materials_provider=build_static_jce_cmp('AES', 256, 'HmacSHA256', 256),
+ materials_provider=build_static_jce_cmp("AES", 256, "HmacSHA256", 256),
encryption_context=EncryptionContext(),
- attribute_actions=AttributeActions()
+ attribute_actions=AttributeActions(),
)
def test_unsigned_item(static_cmp_crypto_config):
- item = {'test': 'no signature'}
+ item = {"test": "no signature"}
with pytest.raises(DecryptionError) as exc_info:
decrypt_python_item(item, static_cmp_crypto_config)
- exc_info.match(r'No signature attribute found in item')
+ exc_info.match(r"No signature attribute found in item")
-@pytest.mark.parametrize('item', (
- {reserved.value: 'asdf'}
- for reserved in ReservedAttributes
-))
+@pytest.mark.parametrize("item", ({reserved.value: "asdf"} for reserved in ReservedAttributes))
def test_reserved_attributes_on_encrypt(static_cmp_crypto_config, item):
with pytest.raises(EncryptionError) as exc_info:
encrypt_python_item(item, static_cmp_crypto_config)
- exc_info.match(r'Reserved attribute name *')
+ exc_info.match(r"Reserved attribute name *")
def test_only_sign_item(parametrized_item):
- signing_key = JceNameLocalDelegatedKey.generate('HmacSHA256', 256)
+ signing_key = JceNameLocalDelegatedKey.generate("HmacSHA256", 256)
cmp = StaticCryptographicMaterialsProvider(
encryption_materials=RawEncryptionMaterials(signing_key=signing_key),
- decryption_materials=RawDecryptionMaterials(verification_key=signing_key)
+ decryption_materials=RawDecryptionMaterials(verification_key=signing_key),
)
actions = AttributeActions(default_action=CryptoAction.SIGN_ONLY)
crypto_config = CryptoConfig(
- materials_provider=cmp,
- encryption_context=EncryptionContext(),
- attribute_actions=actions
+ materials_provider=cmp, encryption_context=EncryptionContext(), attribute_actions=actions
)
signed_item = encrypt_python_item(parametrized_item, crypto_config)
material_description = signed_item[ReservedAttributes.MATERIAL_DESCRIPTION.value].value
- assert MaterialDescriptionKeys.ATTRIBUTE_ENCRYPTION_MODE.value.encode('utf-8') not in material_description
+ assert MaterialDescriptionKeys.ATTRIBUTE_ENCRYPTION_MODE.value.encode("utf-8") not in material_description
decrypt_python_item(signed_item, crypto_config)
-@pytest.mark.parametrize('actions', (
- AttributeActions(default_action=CryptoAction.ENCRYPT_AND_SIGN),
- AttributeActions(default_action=CryptoAction.SIGN_ONLY, attribute_actions={'test': CryptoAction.ENCRYPT_AND_SIGN}),
-))
+@pytest.mark.parametrize(
+ "actions",
+ (
+ AttributeActions(default_action=CryptoAction.ENCRYPT_AND_SIGN),
+ AttributeActions(
+ default_action=CryptoAction.SIGN_ONLY, attribute_actions={"test": CryptoAction.ENCRYPT_AND_SIGN}
+ ),
+ ),
+)
def test_no_encryption_key_but_encryption_requested(actions, parametrized_item):
- signing_key = JceNameLocalDelegatedKey.generate('HmacSHA256', 256)
- cmp = StaticCryptographicMaterialsProvider(
- encryption_materials=RawEncryptionMaterials(signing_key=signing_key)
- )
+ signing_key = JceNameLocalDelegatedKey.generate("HmacSHA256", 256)
+ cmp = StaticCryptographicMaterialsProvider(encryption_materials=RawEncryptionMaterials(signing_key=signing_key))
crypto_config = CryptoConfig(
- materials_provider=cmp,
- encryption_context=EncryptionContext(),
- attribute_actions=actions
+ materials_provider=cmp, encryption_context=EncryptionContext(), attribute_actions=actions
)
with pytest.raises(EncryptionError) as excinfo:
encrypt_python_item(parametrized_item, crypto_config)
- excinfo.match('Attribute actions ask for some attributes to be encrypted but no encryption key is available')
+ excinfo.match("Attribute actions ask for some attributes to be encrypted but no encryption key is available")
-@pytest.mark.parametrize('actions', (
- AttributeActions(default_action=CryptoAction.ENCRYPT_AND_SIGN),
- AttributeActions(default_action=CryptoAction.SIGN_ONLY, attribute_actions={'test': CryptoAction.ENCRYPT_AND_SIGN}),
-))
+@pytest.mark.parametrize(
+ "actions",
+ (
+ AttributeActions(default_action=CryptoAction.ENCRYPT_AND_SIGN),
+ AttributeActions(
+ default_action=CryptoAction.SIGN_ONLY, attribute_actions={"test": CryptoAction.ENCRYPT_AND_SIGN}
+ ),
+ ),
+)
def test_no_decryption_key_but_decryption_requested(actions, parametrized_item):
- encryption_key = JceNameLocalDelegatedKey.generate('AES', 256)
- signing_key = JceNameLocalDelegatedKey.generate('HmacSHA256', 256)
+ encryption_key = JceNameLocalDelegatedKey.generate("AES", 256)
+ signing_key = JceNameLocalDelegatedKey.generate("HmacSHA256", 256)
encrypting_cmp = StaticCryptographicMaterialsProvider(
encryption_materials=RawEncryptionMaterials(encryption_key=encryption_key, signing_key=signing_key)
)
@@ -124,30 +130,26 @@ def test_no_decryption_key_but_decryption_requested(actions, parametrized_item):
encrypted_item = encrypt_python_item(
parametrized_item,
CryptoConfig(
- materials_provider=encrypting_cmp,
- encryption_context=EncryptionContext(),
- attribute_actions=actions
- )
+ materials_provider=encrypting_cmp, encryption_context=EncryptionContext(), attribute_actions=actions
+ ),
)
with pytest.raises(DecryptionError) as excinfo:
decrypt_python_item(
encrypted_item,
CryptoConfig(
- materials_provider=decrypting_cmp,
- encryption_context=EncryptionContext(),
- attribute_actions=actions
- )
+ materials_provider=decrypting_cmp, encryption_context=EncryptionContext(), attribute_actions=actions
+ ),
)
- excinfo.match('Attribute actions ask for some attributes to be decrypted but no decryption key is available')
+ excinfo.match("Attribute actions ask for some attributes to be decrypted but no decryption key is available")
def _item_cycle_check(materials_provider, attribute_actions, item):
crypto_config = CryptoConfig(
materials_provider=materials_provider,
encryption_context=EncryptionContext(),
- attribute_actions=attribute_actions
+ attribute_actions=attribute_actions,
)
cycle_item_check(item, crypto_config)
diff --git a/test/functional/encrypted/test_resource.py b/test/functional/encrypted/test_resource.py
index 3b84e933..31e66d7f 100644
--- a/test/functional/encrypted/test_resource.py
+++ b/test/functional/encrypted/test_resource.py
@@ -13,11 +13,14 @@
"""Functional tests for ``dynamodb_encryption_sdk.encrypted.resource``."""
import pytest
+from ..functional_test_utils import example_table # noqa pylint: disable=unused-import
from ..functional_test_utils import (
- resource_cycle_batch_items_check, set_parametrized_actions,
- set_parametrized_cmp, set_parametrized_item, TEST_TABLE_NAME
+ TEST_TABLE_NAME,
+ resource_cycle_batch_items_check,
+ set_parametrized_actions,
+ set_parametrized_cmp,
+ set_parametrized_item,
)
-from ..functional_test_utils import example_table # noqa pylint: disable=unused-import
pytestmark = [pytest.mark.functional, pytest.mark.local]
@@ -29,7 +32,7 @@ def pytest_generate_tests(metafunc):
def _resource_cycle_batch_items_check(materials_provider, initial_actions, initial_item):
- resource_cycle_batch_items_check(materials_provider, initial_actions, initial_item, TEST_TABLE_NAME, 'us-west-2')
+ resource_cycle_batch_items_check(materials_provider, initial_actions, initial_item, TEST_TABLE_NAME, "us-west-2")
def test_ephemeral_batch_item_cycle(example_table, some_cmps, parametrized_actions, parametrized_item):
diff --git a/test/functional/encrypted/test_table.py b/test/functional/encrypted/test_table.py
index e51a30ed..6a0d1d55 100644
--- a/test/functional/encrypted/test_table.py
+++ b/test/functional/encrypted/test_table.py
@@ -14,12 +14,16 @@
import hypothesis
import pytest
+from ..functional_test_utils import example_table # noqa pylint: disable=unused-import
from ..functional_test_utils import (
- set_parametrized_actions, set_parametrized_cmp, set_parametrized_item,
- table_cycle_batch_writer_check, table_cycle_check, TEST_TABLE_NAME
+ TEST_TABLE_NAME,
+ set_parametrized_actions,
+ set_parametrized_cmp,
+ set_parametrized_item,
+ table_cycle_batch_writer_check,
+ table_cycle_check,
)
-from ..functional_test_utils import example_table # noqa pylint: disable=unused-import
-from ..hypothesis_strategies import ddb_items, SLOW_SETTINGS, VERY_SLOW_SETTINGS
+from ..hypothesis_strategies import SLOW_SETTINGS, VERY_SLOW_SETTINGS, ddb_items
pytestmark = [pytest.mark.functional, pytest.mark.local]
@@ -31,7 +35,7 @@ def pytest_generate_tests(metafunc):
def _table_cycle_check(materials_provider, initial_actions, initial_item):
- return table_cycle_check(materials_provider, initial_actions, initial_item, TEST_TABLE_NAME, 'us-west-2')
+ return table_cycle_check(materials_provider, initial_actions, initial_item, TEST_TABLE_NAME, "us-west-2")
def test_ephemeral_item_cycle(example_table, some_cmps, parametrized_actions, parametrized_item):
@@ -41,7 +45,7 @@ def test_ephemeral_item_cycle(example_table, some_cmps, parametrized_actions, pa
def test_ephemeral_item_cycle_batch_writer(example_table, some_cmps, parametrized_actions, parametrized_item):
"""Test a small number of curated CMPs against a small number of curated items."""
- table_cycle_batch_writer_check(some_cmps, parametrized_actions, parametrized_item, TEST_TABLE_NAME, 'us-west-2')
+ table_cycle_batch_writer_check(some_cmps, parametrized_actions, parametrized_item, TEST_TABLE_NAME, "us-west-2")
@pytest.mark.slow
@@ -53,7 +57,7 @@ def test_ephemeral_item_cycle_slow(example_table, all_the_cmps, parametrized_act
@pytest.mark.slow
def test_ephemeral_item_cycle_batch_writer_slow(example_table, all_the_cmps, parametrized_actions, parametrized_item):
"""Test a small number of curated CMPs against a small number of curated items."""
- table_cycle_batch_writer_check(all_the_cmps, parametrized_actions, parametrized_item, TEST_TABLE_NAME, 'us-west-2')
+ table_cycle_batch_writer_check(all_the_cmps, parametrized_actions, parametrized_item, TEST_TABLE_NAME, "us-west-2")
@pytest.mark.slow
diff --git a/test/functional/functional_test_utils.py b/test/functional/functional_test_utils.py
index b7fb3a2f..4f8f2ec6 100644
--- a/test/functional/functional_test_utils.py
+++ b/test/functional/functional_test_utils.py
@@ -13,15 +13,15 @@
"""Helper tools for use in tests."""
from __future__ import division
-from collections import defaultdict
import copy
-from decimal import Decimal
import itertools
+from collections import defaultdict
+from decimal import Decimal
import boto3
+import pytest
from boto3.dynamodb.types import Binary
from moto import mock_dynamodb2
-import pytest
from dynamodb_encryption_sdk.delegated_keys.jce import JceNameLocalDelegatedKey
from dynamodb_encryption_sdk.encrypted.client import EncryptedClient
@@ -37,103 +37,51 @@
from dynamodb_encryption_sdk.transform import ddb_to_dict, dict_to_ddb
_DELEGATED_KEY_CACHE = defaultdict(lambda: defaultdict(dict))
-TEST_TABLE_NAME = 'my_table'
+TEST_TABLE_NAME = "my_table"
TEST_INDEX = {
- 'partition_attribute': {
- 'type': 'S',
- 'value': 'test_value'
- },
- 'sort_attribute': {
- 'type': 'N',
- 'value': Decimal('99.233')
- }
+ "partition_attribute": {"type": "S", "value": "test_value"},
+ "sort_attribute": {"type": "N", "value": Decimal("99.233")},
}
SECONARY_INDEX = {
- 'secondary_index_1': {
- 'type': 'B',
- 'value': Binary(b'\x00\x01\x02')
- },
- 'secondary_index_1': {
- 'type': 'S',
- 'value': 'another_value'
- }
+ "secondary_index_1": {"type": "B", "value": Binary(b"\x00\x01\x02")},
+ "secondary_index_1": {"type": "S", "value": "another_value"},
}
-TEST_KEY = {name: value['value'] for name, value in TEST_INDEX.items()}
+TEST_KEY = {name: value["value"] for name, value in TEST_INDEX.items()}
TEST_BATCH_INDEXES = [
{
- 'partition_attribute': {
- 'type': 'S',
- 'value': 'test_value'
- },
- 'sort_attribute': {
- 'type': 'N',
- 'value': Decimal('99.233')
- }
+ "partition_attribute": {"type": "S", "value": "test_value"},
+ "sort_attribute": {"type": "N", "value": Decimal("99.233")},
},
{
- 'partition_attribute': {
- 'type': 'S',
- 'value': 'test_value'
- },
- 'sort_attribute': {
- 'type': 'N',
- 'value': Decimal('92986745')
- }
+ "partition_attribute": {"type": "S", "value": "test_value"},
+ "sort_attribute": {"type": "N", "value": Decimal("92986745")},
},
{
- 'partition_attribute': {
- 'type': 'S',
- 'value': 'test_value'
- },
- 'sort_attribute': {
- 'type': 'N',
- 'value': Decimal('2231.0001')
- }
+ "partition_attribute": {"type": "S", "value": "test_value"},
+ "sort_attribute": {"type": "N", "value": Decimal("2231.0001")},
},
{
- 'partition_attribute': {
- 'type': 'S',
- 'value': 'another_test_value'
- },
- 'sort_attribute': {
- 'type': 'N',
- 'value': Decimal('732342')
- }
- }
-]
-TEST_BATCH_KEYS = [
- {name: value['value'] for name, value in key.items()}
- for key in TEST_BATCH_INDEXES
+ "partition_attribute": {"type": "S", "value": "another_test_value"},
+ "sort_attribute": {"type": "N", "value": Decimal("732342")},
+ },
]
+TEST_BATCH_KEYS = [{name: value["value"] for name, value in key.items()} for key in TEST_BATCH_INDEXES]
@pytest.fixture
def example_table():
mock_dynamodb2().start()
- ddb = boto3.client('dynamodb', region_name='us-west-2')
+ ddb = boto3.client("dynamodb", region_name="us-west-2")
ddb.create_table(
TableName=TEST_TABLE_NAME,
KeySchema=[
- {
- 'AttributeName': 'partition_attribute',
- 'KeyType': 'HASH'
- },
- {
- 'AttributeName': 'sort_attribute',
- 'KeyType': 'RANGE'
- }
+ {"AttributeName": "partition_attribute", "KeyType": "HASH"},
+ {"AttributeName": "sort_attribute", "KeyType": "RANGE"},
],
AttributeDefinitions=[
- {
- 'AttributeName': name,
- 'AttributeType': value['type']
- }
- for name, value in TEST_INDEX.items()
+ {"AttributeName": name, "AttributeType": value["type"]} for name, value in TEST_INDEX.items()
],
- ProvisionedThroughput={
- 'ReadCapacityUnits': 100,
- 'WriteCapacityUnits': 100
- }
+ ProvisionedThroughput={"ReadCapacityUnits": 100, "WriteCapacityUnits": 100},
)
yield
ddb.delete_table(TableName=TEST_TABLE_NAME)
@@ -143,56 +91,30 @@ def example_table():
@pytest.fixture
def table_with_local_seconary_indexes():
mock_dynamodb2().start()
- ddb = boto3.client('dynamodb', region_name='us-west-2')
+ ddb = boto3.client("dynamodb", region_name="us-west-2")
ddb.create_table(
TableName=TEST_TABLE_NAME,
KeySchema=[
- {
- 'AttributeName': 'partition_attribute',
- 'KeyType': 'HASH'
- },
- {
- 'AttributeName': 'sort_attribute',
- 'KeyType': 'RANGE'
- }
+ {"AttributeName": "partition_attribute", "KeyType": "HASH"},
+ {"AttributeName": "sort_attribute", "KeyType": "RANGE"},
],
LocalSecondaryIndexes=[
{
- 'IndexName': 'lsi-1',
- 'KeySchema': [
- {
- 'AttributeName': 'secondary_index_1',
- 'KeyType': 'HASH'
- }
- ],
- 'Projection': {
- 'ProjectionType': 'ALL'
- }
+ "IndexName": "lsi-1",
+ "KeySchema": [{"AttributeName": "secondary_index_1", "KeyType": "HASH"}],
+ "Projection": {"ProjectionType": "ALL"},
},
{
- 'IndexName': 'lsi-2',
- 'KeySchema': [
- {
- 'AttributeName': 'secondary_index_2',
- 'KeyType': 'HASH'
- }
- ],
- 'Projection': {
- 'ProjectionType': 'ALL'
- }
- }
+ "IndexName": "lsi-2",
+ "KeySchema": [{"AttributeName": "secondary_index_2", "KeyType": "HASH"}],
+ "Projection": {"ProjectionType": "ALL"},
+ },
],
AttributeDefinitions=[
- {
- 'AttributeName': name,
- 'AttributeType': value['type']
- }
+ {"AttributeName": name, "AttributeType": value["type"]}
for name, value in list(TEST_INDEX.items()) + list(SECONARY_INDEX.items())
],
- ProvisionedThroughput={
- 'ReadCapacityUnits': 100,
- 'WriteCapacityUnits': 100
- }
+ ProvisionedThroughput={"ReadCapacityUnits": 100, "WriteCapacityUnits": 100},
)
yield
ddb.delete_table(TableName=TEST_TABLE_NAME)
@@ -202,64 +124,32 @@ def table_with_local_seconary_indexes():
@pytest.fixture
def table_with_global_seconary_indexes():
mock_dynamodb2().start()
- ddb = boto3.client('dynamodb', region_name='us-west-2')
+ ddb = boto3.client("dynamodb", region_name="us-west-2")
ddb.create_table(
TableName=TEST_TABLE_NAME,
KeySchema=[
- {
- 'AttributeName': 'partition_attribute',
- 'KeyType': 'HASH'
- },
- {
- 'AttributeName': 'sort_attribute',
- 'KeyType': 'RANGE'
- }
+ {"AttributeName": "partition_attribute", "KeyType": "HASH"},
+ {"AttributeName": "sort_attribute", "KeyType": "RANGE"},
],
GlobalSecondaryIndexes=[
{
- 'IndexName': 'gsi-1',
- 'KeySchema': [
- {
- 'AttributeName': 'secondary_index_1',
- 'KeyType': 'HASH'
- }
- ],
- 'Projection': {
- 'ProjectionType': 'ALL'
- },
- 'ProvisionedThroughput': {
- 'ReadCapacityUnits': 100,
- 'WriteCapacityUnits': 100
- }
+ "IndexName": "gsi-1",
+ "KeySchema": [{"AttributeName": "secondary_index_1", "KeyType": "HASH"}],
+ "Projection": {"ProjectionType": "ALL"},
+ "ProvisionedThroughput": {"ReadCapacityUnits": 100, "WriteCapacityUnits": 100},
},
{
- 'IndexName': 'gsi-2',
- 'KeySchema': [
- {
- 'AttributeName': 'secondary_index_2',
- 'KeyType': 'HASH'
- }
- ],
- 'Projection': {
- 'ProjectionType': 'ALL'
- },
- 'ProvisionedThroughput': {
- 'ReadCapacityUnits': 100,
- 'WriteCapacityUnits': 100
- }
- }
+ "IndexName": "gsi-2",
+ "KeySchema": [{"AttributeName": "secondary_index_2", "KeyType": "HASH"}],
+ "Projection": {"ProjectionType": "ALL"},
+ "ProvisionedThroughput": {"ReadCapacityUnits": 100, "WriteCapacityUnits": 100},
+ },
],
AttributeDefinitions=[
- {
- 'AttributeName': name,
- 'AttributeType': value['type']
- }
+ {"AttributeName": name, "AttributeType": value["type"]}
for name, value in list(TEST_INDEX.items()) + list(SECONARY_INDEX.items())
],
- ProvisionedThroughput={
- 'ReadCapacityUnits': 100,
- 'WriteCapacityUnits': 100
- }
+ ProvisionedThroughput={"ReadCapacityUnits": 100, "WriteCapacityUnits": 100},
)
yield
ddb.delete_table(TableName=TEST_TABLE_NAME)
@@ -280,17 +170,10 @@ def build_static_jce_cmp(encryption_algorithm, encryption_key_length, signing_al
"""Build a StaticCryptographicMaterialsProvider using ephemeral JceNameLocalDelegatedKeys as specified."""
encryption_key = _get_from_cache(JceNameLocalDelegatedKey, encryption_algorithm, encryption_key_length)
authentication_key = _get_from_cache(JceNameLocalDelegatedKey, signing_algorithm, signing_key_length)
- encryption_materials = RawEncryptionMaterials(
- signing_key=authentication_key,
- encryption_key=encryption_key
- )
- decryption_materials = RawDecryptionMaterials(
- verification_key=authentication_key,
- decryption_key=encryption_key
- )
+ encryption_materials = RawEncryptionMaterials(signing_key=authentication_key, encryption_key=encryption_key)
+ decryption_materials = RawDecryptionMaterials(verification_key=authentication_key, decryption_key=encryption_key)
return StaticCryptographicMaterialsProvider(
- encryption_materials=encryption_materials,
- decryption_materials=decryption_materials
+ encryption_materials=encryption_materials, decryption_materials=decryption_materials
)
@@ -299,31 +182,20 @@ def _build_wrapped_jce_cmp(wrapping_algorithm, wrapping_key_length, signing_algo
wrapping_key = _get_from_cache(JceNameLocalDelegatedKey, wrapping_algorithm, wrapping_key_length)
signing_key = _get_from_cache(JceNameLocalDelegatedKey, signing_algorithm, signing_key_length)
return WrappedCryptographicMaterialsProvider(
- wrapping_key=wrapping_key,
- unwrapping_key=wrapping_key,
- signing_key=signing_key
+ wrapping_key=wrapping_key, unwrapping_key=wrapping_key, signing_key=signing_key
)
def _all_encryption():
"""All encryption configurations to test in slow tests."""
- return itertools.chain(
- itertools.product(('AES',), (128, 256)),
- itertools.product(('RSA',), (1024, 2048, 4096))
- )
+ return itertools.chain(itertools.product(("AES",), (128, 256)), itertools.product(("RSA",), (1024, 2048, 4096)))
def _all_authentication():
"""All authentication configurations to test in slow tests."""
return itertools.chain(
- itertools.product(
- ('HmacSHA224', 'HmacSHA256', 'HmacSHA384', 'HmacSHA512'),
- (128, 256)
- ),
- itertools.product(
- ('SHA224withRSA', 'SHA256withRSA', 'SHA384withRSA', 'SHA512withRSA'),
- (1024, 2048, 4096)
- )
+ itertools.product(("HmacSHA224", "HmacSHA256", "HmacSHA384", "HmacSHA512"), (128, 256)),
+ itertools.product(("SHA224withRSA", "SHA256withRSA", "SHA384withRSA", "SHA512withRSA"), (1024, 2048, 4096)),
)
@@ -335,107 +207,94 @@ def _all_algorithm_pairs():
def _some_algorithm_pairs():
"""Cherry-picked set of algorithm pairs (encryption + authentication) to test in fast tests."""
- return (
- ('AES', 256, 'HmacSHA256', 256),
- ('AES', 256, 'SHA256withRSA', 4096),
- ('RSA', 4096, 'SHA256withRSA', 4096)
- )
+ return (("AES", 256, "HmacSHA256", 256), ("AES", 256, "SHA256withRSA", 4096), ("RSA", 4096, "SHA256withRSA", 4096))
-_cmp_builders = {
- 'static': build_static_jce_cmp,
- 'wrapped': _build_wrapped_jce_cmp
-}
+_cmp_builders = {"static": build_static_jce_cmp, "wrapped": _build_wrapped_jce_cmp}
def _all_possible_cmps(algorithm_generator):
"""Generate all possible cryptographic materials providers based on the supplied generator."""
# The AES combinations do the same thing, but this makes sure that the AESWrap name works as expected.
- yield _build_wrapped_jce_cmp('AESWrap', 256, 'HmacSHA256', 256)
+ yield _build_wrapped_jce_cmp("AESWrap", 256, "HmacSHA256", 256)
for builder_info, args in itertools.product(_cmp_builders.items(), algorithm_generator()):
builder_type, builder_func = builder_info
encryption_algorithm, encryption_key_length, signing_algorithm, signing_key_length = args
- if builder_type == 'static' and encryption_algorithm != 'AES':
+ if builder_type == "static" and encryption_algorithm != "AES":
# Only AES keys are allowed to be used with static materials
continue
- id_string = '{enc_algorithm}/{enc_key_length} {builder_type} {sig_algorithm}/{sig_key_length}'.format(
+ id_string = "{enc_algorithm}/{enc_key_length} {builder_type} {sig_algorithm}/{sig_key_length}".format(
enc_algorithm=encryption_algorithm,
enc_key_length=encryption_key_length,
builder_type=builder_type,
sig_algorithm=signing_algorithm,
- sig_key_length=signing_key_length
+ sig_key_length=signing_key_length,
)
yield pytest.param(
- builder_func(
- encryption_algorithm,
- encryption_key_length,
- signing_algorithm,
- signing_key_length
- ),
- id=id_string
+ builder_func(encryption_algorithm, encryption_key_length, signing_algorithm, signing_key_length),
+ id=id_string,
)
def set_parametrized_cmp(metafunc):
"""Set paramatrized values for cryptographic materials providers."""
- for name, algorithm_generator in (('all_the_cmps', _all_algorithm_pairs), ('some_cmps', _some_algorithm_pairs)):
+ for name, algorithm_generator in (("all_the_cmps", _all_algorithm_pairs), ("some_cmps", _some_algorithm_pairs)):
if name in metafunc.fixturenames:
metafunc.parametrize(name, _all_possible_cmps(algorithm_generator))
_ACTIONS = {
- 'hypothesis_actions': (
- pytest.param(AttributeActions(default_action=CryptoAction.ENCRYPT_AND_SIGN), id='encrypt all'),
- pytest.param(AttributeActions(default_action=CryptoAction.SIGN_ONLY), id='sign only all'),
- pytest.param(AttributeActions(default_action=CryptoAction.DO_NOTHING), id='do nothing'),
+ "hypothesis_actions": (
+ pytest.param(AttributeActions(default_action=CryptoAction.ENCRYPT_AND_SIGN), id="encrypt all"),
+ pytest.param(AttributeActions(default_action=CryptoAction.SIGN_ONLY), id="sign only all"),
+ pytest.param(AttributeActions(default_action=CryptoAction.DO_NOTHING), id="do nothing"),
)
}
-_ACTIONS['parametrized_actions'] = _ACTIONS['hypothesis_actions'] + (
+_ACTIONS["parametrized_actions"] = _ACTIONS["hypothesis_actions"] + (
pytest.param(
AttributeActions(
default_action=CryptoAction.ENCRYPT_AND_SIGN,
attribute_actions={
- 'number_set': CryptoAction.SIGN_ONLY,
- 'string_set': CryptoAction.SIGN_ONLY,
- 'binary_set': CryptoAction.SIGN_ONLY
- }
+ "number_set": CryptoAction.SIGN_ONLY,
+ "string_set": CryptoAction.SIGN_ONLY,
+ "binary_set": CryptoAction.SIGN_ONLY,
+ },
),
- id='sign sets, encrypt everything else'
+ id="sign sets, encrypt everything else",
),
pytest.param(
AttributeActions(
default_action=CryptoAction.ENCRYPT_AND_SIGN,
attribute_actions={
- 'number_set': CryptoAction.DO_NOTHING,
- 'string_set': CryptoAction.DO_NOTHING,
- 'binary_set': CryptoAction.DO_NOTHING
- }
+ "number_set": CryptoAction.DO_NOTHING,
+ "string_set": CryptoAction.DO_NOTHING,
+ "binary_set": CryptoAction.DO_NOTHING,
+ },
),
- id='ignore sets, encrypt everything else'
+ id="ignore sets, encrypt everything else",
),
pytest.param(
AttributeActions(
- default_action=CryptoAction.DO_NOTHING,
- attribute_actions={'map': CryptoAction.ENCRYPT_AND_SIGN}
+ default_action=CryptoAction.DO_NOTHING, attribute_actions={"map": CryptoAction.ENCRYPT_AND_SIGN}
),
- id='encrypt map, ignore everything else'
+ id="encrypt map, ignore everything else",
),
pytest.param(
AttributeActions(
default_action=CryptoAction.SIGN_ONLY,
attribute_actions={
- 'number_set': CryptoAction.DO_NOTHING,
- 'string_set': CryptoAction.DO_NOTHING,
- 'binary_set': CryptoAction.DO_NOTHING,
- 'map': CryptoAction.ENCRYPT_AND_SIGN
- }
+ "number_set": CryptoAction.DO_NOTHING,
+ "string_set": CryptoAction.DO_NOTHING,
+ "binary_set": CryptoAction.DO_NOTHING,
+ "map": CryptoAction.ENCRYPT_AND_SIGN,
+ },
),
- id='ignore sets, encrypt map, sign everything else'
- )
+ id="ignore sets, encrypt map, sign everything else",
+ ),
)
@@ -448,27 +307,22 @@ def set_parametrized_actions(metafunc):
def set_parametrized_item(metafunc):
"""Set parametrized values for items to cycle."""
- if 'parametrized_item' in metafunc.fixturenames:
- metafunc.parametrize(
- 'parametrized_item',
- (
- pytest.param(diverse_item(), id='diverse item'),
- )
- )
+ if "parametrized_item" in metafunc.fixturenames:
+ metafunc.parametrize("parametrized_item", (pytest.param(diverse_item(), id="diverse item"),))
def diverse_item():
base_item = {
- 'int': 5,
- 'decimal': Decimal('123.456'),
- 'string': 'this is a string',
- 'binary': b'this is a bytestring! \x01',
- 'number_set': set([5, 4, 3]),
- 'string_set': set(['abc', 'def', 'geh']),
- 'binary_set': set([b'\x00\x00\x00', b'\x00\x01\x00', b'\x00\x00\x02'])
+ "int": 5,
+ "decimal": Decimal("123.456"),
+ "string": "this is a string",
+ "binary": b"this is a bytestring! \x01",
+ "number_set": set([5, 4, 3]),
+ "string_set": set(["abc", "def", "geh"]),
+ "binary_set": set([b"\x00\x00\x00", b"\x00\x01\x00", b"\x00\x00\x02"]),
}
- base_item['list'] = [copy.copy(i) for i in base_item.values()]
- base_item['map'] = copy.deepcopy(base_item)
+ base_item["list"] = [copy.copy(i) for i in base_item.values()]
+ base_item["map"] = copy.deepcopy(base_item)
return copy.deepcopy(base_item)
@@ -500,9 +354,10 @@ def check_encrypted_item(plaintext_item, ciphertext_item, attribute_actions):
def _matching_key(actual_item, expected):
expected_item = [
- i for i in expected
- if i['partition_attribute'] == actual_item['partition_attribute'] and
- i['sort_attribute'] == actual_item['sort_attribute']
+ i
+ for i in expected
+ if i["partition_attribute"] == actual_item["partition_attribute"]
+ and i["sort_attribute"] == actual_item["sort_attribute"]
]
assert len(expected_item) == 1
return expected_item[0]
@@ -528,7 +383,7 @@ def check_many_encrypted_items(actual, expected, attribute_actions, transformer=
check_encrypted_item(
plaintext_item=transformer(expected_item),
ciphertext_item=transformer(actual_item),
- attribute_actions=attribute_actions
+ attribute_actions=attribute_actions,
)
@@ -544,24 +399,19 @@ def _generate_items(initial_item, write_transformer):
def _cleanup_items(encrypted, write_transformer, table_name=TEST_TABLE_NAME):
ddb_keys = [write_transformer(key) for key in TEST_BATCH_KEYS]
_delete_result = encrypted.batch_write_item( # noqa
- RequestItems={
- table_name: [
- {'DeleteRequest': {'Key': _key}}
- for _key in ddb_keys
- ]
- }
+ RequestItems={table_name: [{"DeleteRequest": {"Key": _key}} for _key in ddb_keys]}
)
def cycle_batch_item_check(
- raw,
- encrypted,
- initial_actions,
- initial_item,
- write_transformer=_nop_transformer,
- read_transformer=_nop_transformer,
- table_name=TEST_TABLE_NAME,
- delete_items=True
+ raw,
+ encrypted,
+ initial_actions,
+ initial_item,
+ write_transformer=_nop_transformer,
+ read_transformer=_nop_transformer,
+ table_name=TEST_TABLE_NAME,
+ delete_items=True,
):
"""Check that cycling (plaintext->encrypted->decrypted) item batch has the expected results."""
check_attribute_actions = initial_actions.copy()
@@ -569,40 +419,21 @@ def cycle_batch_item_check(
items = _generate_items(initial_item, write_transformer)
_put_result = encrypted.batch_write_item( # noqa
- RequestItems={
- table_name: [
- {'PutRequest': {'Item': _item}}
- for _item in items
- ]
- }
+ RequestItems={table_name: [{"PutRequest": {"Item": _item}} for _item in items]}
)
ddb_keys = [write_transformer(key) for key in TEST_BATCH_KEYS]
- encrypted_result = raw.batch_get_item(
- RequestItems={
- table_name: {
- 'Keys': ddb_keys
- }
- }
- )
+ encrypted_result = raw.batch_get_item(RequestItems={table_name: {"Keys": ddb_keys}})
check_many_encrypted_items(
- actual=encrypted_result['Responses'][table_name],
+ actual=encrypted_result["Responses"][table_name],
expected=items,
attribute_actions=check_attribute_actions,
- transformer=read_transformer
+ transformer=read_transformer,
)
- decrypted_result = encrypted.batch_get_item(
- RequestItems={
- table_name: {
- 'Keys': ddb_keys
- }
- }
- )
+ decrypted_result = encrypted.batch_get_item(RequestItems={table_name: {"Keys": ddb_keys}})
assert_equal_lists_of_items(
- actual=decrypted_result['Responses'][table_name],
- expected=items,
- transformer=read_transformer
+ actual=decrypted_result["Responses"][table_name], expected=items, transformer=read_transformer
)
if delete_items:
@@ -625,26 +456,13 @@ def cycle_batch_writer_check(raw_table, encrypted_table, initial_actions, initia
writer.put_item(item)
ddb_keys = [key for key in TEST_BATCH_KEYS]
- encrypted_items = [
- raw_table.get_item(Key=key, ConsistentRead=True)['Item']
- for key in ddb_keys
- ]
+ encrypted_items = [raw_table.get_item(Key=key, ConsistentRead=True)["Item"] for key in ddb_keys]
check_many_encrypted_items(
- actual=encrypted_items,
- expected=items,
- attribute_actions=check_attribute_actions,
- transformer=_nop_transformer
+ actual=encrypted_items, expected=items, attribute_actions=check_attribute_actions, transformer=_nop_transformer
)
- decrypted_result = [
- encrypted_table.get_item(Key=key, ConsistentRead=True)['Item']
- for key in ddb_keys
- ]
- assert_equal_lists_of_items(
- actual=decrypted_result,
- expected=items,
- transformer=_nop_transformer
- )
+ decrypted_result = [encrypted_table.get_item(Key=key, ConsistentRead=True)["Item"] for key in ddb_keys]
+ assert_equal_lists_of_items(actual=decrypted_result, expected=items, transformer=_nop_transformer)
with encrypted_table.batch_writer() as writer:
for key in ddb_keys:
@@ -675,21 +493,17 @@ def table_cycle_check(materials_provider, initial_actions, initial_item, table_n
kwargs = {}
if region_name is not None:
- kwargs['region_name'] = region_name
- table = boto3.resource('dynamodb', **kwargs).Table(table_name)
- e_table = EncryptedTable(
- table=table,
- materials_provider=materials_provider,
- attribute_actions=initial_actions,
- )
+ kwargs["region_name"] = region_name
+ table = boto3.resource("dynamodb", **kwargs).Table(table_name)
+ e_table = EncryptedTable(table=table, materials_provider=materials_provider, attribute_actions=initial_actions)
_put_result = e_table.put_item(Item=item) # noqa
encrypted_result = table.get_item(Key=TEST_KEY, ConsistentRead=True)
- check_encrypted_item(item, encrypted_result['Item'], check_attribute_actions)
+ check_encrypted_item(item, encrypted_result["Item"], check_attribute_actions)
decrypted_result = e_table.get_item(Key=TEST_KEY, ConsistentRead=True)
- assert decrypted_result['Item'] == item
+ assert decrypted_result["Item"] == item
e_table.delete_item(Key=TEST_KEY)
del item
@@ -699,13 +513,9 @@ def table_cycle_check(materials_provider, initial_actions, initial_item, table_n
def table_cycle_batch_writer_check(materials_provider, initial_actions, initial_item, table_name, region_name=None):
kwargs = {}
if region_name is not None:
- kwargs['region_name'] = region_name
- table = boto3.resource('dynamodb', **kwargs).Table(table_name)
- e_table = EncryptedTable(
- table=table,
- materials_provider=materials_provider,
- attribute_actions=initial_actions,
- )
+ kwargs["region_name"] = region_name
+ table = boto3.resource("dynamodb", **kwargs).Table(table_name)
+ e_table = EncryptedTable(table=table, materials_provider=materials_provider, attribute_actions=initial_actions)
cycle_batch_writer_check(table, e_table, initial_actions, initial_item)
@@ -713,12 +523,10 @@ def table_cycle_batch_writer_check(materials_provider, initial_actions, initial_
def resource_cycle_batch_items_check(materials_provider, initial_actions, initial_item, table_name, region_name=None):
kwargs = {}
if region_name is not None:
- kwargs['region_name'] = region_name
- resource = boto3.resource('dynamodb', **kwargs)
+ kwargs["region_name"] = region_name
+ resource = boto3.resource("dynamodb", **kwargs)
e_resource = EncryptedResource(
- resource=resource,
- materials_provider=materials_provider,
- attribute_actions=initial_actions
+ resource=resource, materials_provider=materials_provider, attribute_actions=initial_actions
)
cycle_batch_item_check(
@@ -726,13 +534,13 @@ def resource_cycle_batch_items_check(materials_provider, initial_actions, initia
encrypted=e_resource,
initial_actions=initial_actions,
initial_item=initial_item,
- table_name=table_name
+ table_name=table_name,
)
raw_scan_result = resource.Table(table_name).scan(ConsistentRead=True)
e_scan_result = e_resource.Table(table_name).scan(ConsistentRead=True)
- assert not raw_scan_result['Items']
- assert not e_scan_result['Items']
+ assert not raw_scan_result["Items"]
+ assert not e_scan_result["Items"]
def client_cycle_single_item_check(materials_provider, initial_actions, initial_item, table_name, region_name=None):
@@ -745,37 +553,19 @@ def client_cycle_single_item_check(materials_provider, initial_actions, initial_
kwargs = {}
if region_name is not None:
- kwargs['region_name'] = region_name
- client = boto3.client('dynamodb', **kwargs)
- e_client = EncryptedClient(
- client=client,
- materials_provider=materials_provider,
- attribute_actions=initial_actions
- )
+ kwargs["region_name"] = region_name
+ client = boto3.client("dynamodb", **kwargs)
+ e_client = EncryptedClient(client=client, materials_provider=materials_provider, attribute_actions=initial_actions)
- _put_result = e_client.put_item( # noqa
- TableName=table_name,
- Item=ddb_item
- )
+ _put_result = e_client.put_item(TableName=table_name, Item=ddb_item) # noqa
- encrypted_result = client.get_item(
- TableName=table_name,
- Key=ddb_key,
- ConsistentRead=True
- )
- check_encrypted_item(item, ddb_to_dict(encrypted_result['Item']), check_attribute_actions)
+ encrypted_result = client.get_item(TableName=table_name, Key=ddb_key, ConsistentRead=True)
+ check_encrypted_item(item, ddb_to_dict(encrypted_result["Item"]), check_attribute_actions)
- decrypted_result = e_client.get_item(
- TableName=table_name,
- Key=ddb_key,
- ConsistentRead=True
- )
- assert ddb_to_dict(decrypted_result['Item']) == item
+ decrypted_result = e_client.get_item(TableName=table_name, Key=ddb_key, ConsistentRead=True)
+ assert ddb_to_dict(decrypted_result["Item"]) == item
- e_client.delete_item(
- TableName=table_name,
- Key=ddb_key
- )
+ e_client.delete_item(TableName=table_name, Key=ddb_key)
del item
del check_attribute_actions
@@ -783,13 +573,9 @@ def client_cycle_single_item_check(materials_provider, initial_actions, initial_
def client_cycle_batch_items_check(materials_provider, initial_actions, initial_item, table_name, region_name=None):
kwargs = {}
if region_name is not None:
- kwargs['region_name'] = region_name
- client = boto3.client('dynamodb', **kwargs)
- e_client = EncryptedClient(
- client=client,
- materials_provider=materials_provider,
- attribute_actions=initial_actions
- )
+ kwargs["region_name"] = region_name
+ client = boto3.client("dynamodb", **kwargs)
+ e_client = EncryptedClient(client=client, materials_provider=materials_provider, attribute_actions=initial_actions)
cycle_batch_item_check(
raw=client,
@@ -798,31 +584,23 @@ def client_cycle_batch_items_check(materials_provider, initial_actions, initial_
initial_item=initial_item,
write_transformer=dict_to_ddb,
read_transformer=ddb_to_dict,
- table_name=table_name
+ table_name=table_name,
)
raw_scan_result = client.scan(TableName=table_name, ConsistentRead=True)
e_scan_result = e_client.scan(TableName=table_name, ConsistentRead=True)
- assert not raw_scan_result['Items']
- assert not e_scan_result['Items']
+ assert not raw_scan_result["Items"]
+ assert not e_scan_result["Items"]
def client_cycle_batch_items_check_paginators(
- materials_provider,
- initial_actions,
- initial_item,
- table_name,
- region_name=None
+ materials_provider, initial_actions, initial_item, table_name, region_name=None
):
kwargs = {}
if region_name is not None:
- kwargs['region_name'] = region_name
- client = boto3.client('dynamodb', **kwargs)
- e_client = EncryptedClient(
- client=client,
- materials_provider=materials_provider,
- attribute_actions=initial_actions
- )
+ kwargs["region_name"] = region_name
+ client = boto3.client("dynamodb", **kwargs)
+ e_client = EncryptedClient(client=client, materials_provider=materials_provider, attribute_actions=initial_actions)
cycle_batch_item_check(
raw=client,
@@ -832,18 +610,18 @@ def client_cycle_batch_items_check_paginators(
write_transformer=dict_to_ddb,
read_transformer=ddb_to_dict,
table_name=table_name,
- delete_items=False
+ delete_items=False,
)
encrypted_items = []
- raw_paginator = client.get_paginator('scan')
+ raw_paginator = client.get_paginator("scan")
for page in raw_paginator.paginate(TableName=table_name, ConsistentRead=True):
- encrypted_items.extend(page['Items'])
+ encrypted_items.extend(page["Items"])
decrypted_items = []
- encrypted_paginator = e_client.get_paginator('scan')
+ encrypted_paginator = e_client.get_paginator("scan")
for page in encrypted_paginator.paginate(TableName=table_name, ConsistentRead=True):
- decrypted_items.extend(page['Items'])
+ decrypted_items.extend(page["Items"])
print(encrypted_items)
print(decrypted_items)
@@ -854,16 +632,12 @@ def client_cycle_batch_items_check_paginators(
actual=encrypted_items,
expected=decrypted_items,
attribute_actions=check_attribute_actions,
- transformer=ddb_to_dict
+ transformer=ddb_to_dict,
)
- _cleanup_items(
- encrypted=e_client,
- write_transformer=dict_to_ddb,
- table_name=table_name
- )
+ _cleanup_items(encrypted=e_client, write_transformer=dict_to_ddb, table_name=table_name)
raw_scan_result = client.scan(TableName=table_name, ConsistentRead=True)
e_scan_result = e_client.scan(TableName=table_name, ConsistentRead=True)
- assert not raw_scan_result['Items']
- assert not e_scan_result['Items']
+ assert not raw_scan_result["Items"]
+ assert not e_scan_result["Items"]
diff --git a/test/functional/functional_test_vector_generators.py b/test/functional/functional_test_vector_generators.py
index 88a7fd4e..02906f35 100644
--- a/test/functional/functional_test_vector_generators.py
+++ b/test/functional/functional_test_vector_generators.py
@@ -13,9 +13,9 @@
"""Helper tools for collecting test vectors for use in functional tests."""
import base64
import codecs
-from decimal import Decimal
import json
import os
+from decimal import Decimal
from boto3.dynamodb.types import Binary
@@ -23,22 +23,13 @@
from dynamodb_encryption_sdk.structures import AttributeActions
_ATTRIBUTE_TEST_VECTOR_FILE_TEMPLATE = os.path.join(
- os.path.abspath(os.path.dirname(__file__)),
- '..',
- 'vectors',
- '{mode}_attribute.json'
+ os.path.abspath(os.path.dirname(__file__)), "..", "vectors", "{mode}_attribute.json"
)
_MATERIAL_DESCRIPTION_TEST_VECTORS_FILE = os.path.join(
- os.path.abspath(os.path.dirname(__file__)),
- '..',
- 'vectors',
- 'material_description.json'
+ os.path.abspath(os.path.dirname(__file__)), "..", "vectors", "material_description.json"
)
_STRING_TO_SIGN_TEST_VECTORS_FILE = os.path.join(
- os.path.abspath(os.path.dirname(__file__)),
- '..',
- 'vectors',
- 'string_to_sign.json'
+ os.path.abspath(os.path.dirname(__file__)), "..", "vectors", "string_to_sign.json"
)
@@ -47,7 +38,7 @@ def _decode_string(_value):
return _value
def _decode_number(_value):
- return '{0:f}'.format(Decimal(_value))
+ return "{0:f}".format(Decimal(_value))
def _decode_binary(_value):
raw = base64.b64decode(_value)
@@ -91,14 +82,14 @@ def _decode_map(_value):
return decoded_value
_decode_mapping = {
- 'S': _decode_string,
- 'B': _decode_binary,
- 'SS': _decode_string_set,
- 'BS': _decode_binary_set,
- 'L': _decode_list,
- 'M': _decode_map,
- 'N': _decode_number,
- 'NS': _decode_number_set
+ "S": _decode_string,
+ "B": _decode_binary,
+ "SS": _decode_string_set,
+ "BS": _decode_binary_set,
+ "L": _decode_list,
+ "M": _decode_map,
+ "N": _decode_number,
+ "NS": _decode_number_set,
}
def _decode_complex_value(_value):
@@ -116,26 +107,20 @@ def attribute_test_vectors(mode):
with open(filepath) as f:
vectors = json.load(f)
for vector in vectors:
- yield (
- decode_value(vector['attribute']),
- base64.b64decode(codecs.encode(vector['serialized'], 'utf-8'))
- )
+ yield (decode_value(vector["attribute"]), base64.b64decode(codecs.encode(vector["serialized"], "utf-8")))
def material_description_test_vectors():
with open(_MATERIAL_DESCRIPTION_TEST_VECTORS_FILE) as f:
vectors = json.load(f)
for vector in vectors:
- yield (
- vector['material_description'],
- decode_value({'B': codecs.encode(vector['serialized'], 'utf-8')})
- )
+ yield (vector["material_description"], decode_value({"B": codecs.encode(vector["serialized"], "utf-8")}))
ACTION_MAP = {
- 'encrypt': CryptoAction.ENCRYPT_AND_SIGN,
- 'sign': CryptoAction.SIGN_ONLY,
- 'nothing': CryptoAction.DO_NOTHING
+ "encrypt": CryptoAction.ENCRYPT_AND_SIGN,
+ "sign": CryptoAction.SIGN_ONLY,
+ "nothing": CryptoAction.DO_NOTHING,
}
@@ -143,18 +128,12 @@ def string_to_sign_test_vectors():
with open(_STRING_TO_SIGN_TEST_VECTORS_FILE) as f:
vectors = json.load(f)
for vector in vectors:
- item = {
- key: decode_value(value['value'])
- for key, value in vector['item'].items()
- }
- bare_actions = {key: ACTION_MAP[value['action']] for key, value in vector['item'].items()}
- attribute_actions = AttributeActions(
- default_action=CryptoAction.DO_NOTHING,
- attribute_actions=bare_actions
- )
+ item = {key: decode_value(value["value"]) for key, value in vector["item"].items()}
+ bare_actions = {key: ACTION_MAP[value["action"]] for key, value in vector["item"].items()}
+ attribute_actions = AttributeActions(default_action=CryptoAction.DO_NOTHING, attribute_actions=bare_actions)
yield (
item,
- vector['table'],
+ vector["table"],
attribute_actions,
- base64.b64decode(codecs.encode(vector['string_to_sign'], 'utf-8'))
+ base64.b64decode(codecs.encode(vector["string_to_sign"], "utf-8")),
)
diff --git a/test/functional/hypothesis_strategies.py b/test/functional/hypothesis_strategies.py
index 170b9389..8e230375 100644
--- a/test/functional/hypothesis_strategies.py
+++ b/test/functional/hypothesis_strategies.py
@@ -14,27 +14,21 @@
"""Hypothesis strategies for use in tests."""
from decimal import Decimal
-from boto3.dynamodb.types import Binary
import hypothesis
-from hypothesis.strategies import (
- binary, booleans, deferred, dictionaries, fractions, just, lists, none, sets, text
-)
+from boto3.dynamodb.types import Binary
+from hypothesis.strategies import binary, booleans, deferred, dictionaries, fractions, just, lists, none, sets, text
SLOW_SETTINGS = hypothesis.settings(
suppress_health_check=(
hypothesis.HealthCheck.too_slow,
hypothesis.HealthCheck.data_too_large,
hypothesis.HealthCheck.hung_test,
- hypothesis.HealthCheck.large_base_example
+ hypothesis.HealthCheck.large_base_example,
),
timeout=hypothesis.unlimited,
- deadline=None
-)
-VERY_SLOW_SETTINGS = hypothesis.settings(
- SLOW_SETTINGS,
- max_examples=1000,
- max_iterations=1500
+ deadline=None,
)
+VERY_SLOW_SETTINGS = hypothesis.settings(SLOW_SETTINGS, max_examples=1000, max_iterations=1500)
MAX_ITEM_BYTES = 400 * 1024 * 1024
# _MIN_NUMBER = Decimal('1E-128') # The DDB min is 1E-130, but DYNAMODB_CONTEXT Emin is -128
@@ -42,14 +36,11 @@
# TODO: I would like to test the full range of possible number values, but boto3 does not
# correctly handle conversion of large edge case values at this time. We will work to fix
# that, but in the meantime, we will just use the happy path numbers.
-_MIN_NUMBER = Decimal('1E-38')
-_MAX_NUMBER = Decimal('9.{}E37'.format('9' * 37))
+_MIN_NUMBER = Decimal("1E-38")
+_MAX_NUMBER = Decimal("9.{}E37".format("9" * 37))
-ddb_string = text(
- min_size=1,
- max_size=MAX_ITEM_BYTES
-)
+ddb_string = text(min_size=1, max_size=MAX_ITEM_BYTES)
ddb_string_set = sets(ddb_string, min_size=1)
@@ -59,16 +50,13 @@ def _ddb_fraction_to_decimal(val):
def _negative(val):
- return val * Decimal('-1')
+ return val * Decimal("-1")
-ddb_positive_numbers = fractions(
- min_value=_MIN_NUMBER,
- max_value=_MAX_NUMBER
-).map(_ddb_fraction_to_decimal)
+ddb_positive_numbers = fractions(min_value=_MIN_NUMBER, max_value=_MAX_NUMBER).map(_ddb_fraction_to_decimal)
ddb_negative_numbers = ddb_positive_numbers.map(_negative)
-ddb_number = ddb_negative_numbers | just(Decimal('0')) | ddb_positive_numbers
+ddb_number = ddb_negative_numbers | just(Decimal("0")) | ddb_positive_numbers
ddb_number_set = sets(ddb_number, min_size=1)
ddb_binary = binary(min_size=1, max_size=MAX_ITEM_BYTES).map(Binary)
@@ -77,54 +65,22 @@ def _negative(val):
ddb_boolean = booleans()
ddb_null = none()
-ddb_scalar_types = (
- ddb_string |
- ddb_number |
- ddb_binary |
- ddb_boolean |
- ddb_null
-)
+ddb_scalar_types = ddb_string | ddb_number | ddb_binary | ddb_boolean | ddb_null
-ddb_set_types = (
- ddb_string_set |
- ddb_number_set |
- ddb_binary_set
-)
-ddb_attribute_names = text(
- min_size=1,
- max_size=255
-)
+ddb_set_types = ddb_string_set | ddb_number_set | ddb_binary_set
+ddb_attribute_names = text(min_size=1, max_size=255)
# TODO: List and Map types have a max depth of 32
-ddb_map_type = deferred(lambda: dictionaries(
- keys=ddb_attribute_names,
- values=(
- ddb_scalar_types |
- ddb_set_types |
- ddb_list_type |
- ddb_map_type
- ),
- min_size=1
-))
-ddb_list_type = deferred(lambda: lists(
- ddb_scalar_types |
- ddb_set_types |
- ddb_list_type |
- ddb_map_type,
- min_size=1
-))
+ddb_map_type = deferred(
+ lambda: dictionaries(
+ keys=ddb_attribute_names, values=(ddb_scalar_types | ddb_set_types | ddb_list_type | ddb_map_type), min_size=1
+ )
+)
+ddb_list_type = deferred(lambda: lists(ddb_scalar_types | ddb_set_types | ddb_list_type | ddb_map_type, min_size=1))
ddb_document_types = ddb_map_type | ddb_list_type
ddb_attribute_values = ddb_scalar_types | ddb_set_types | ddb_list_type
-ddb_items = dictionaries(
- keys=ddb_attribute_names,
- values=ddb_attribute_values,
- min_size=1
-)
+ddb_items = dictionaries(keys=ddb_attribute_names, values=ddb_attribute_values, min_size=1)
-material_descriptions = deferred(lambda: dictionaries(
- keys=text(),
- values=text(),
- min_size=1
-))
+material_descriptions = deferred(lambda: dictionaries(keys=text(), values=text(), min_size=1))
diff --git a/test/functional/internal/crypto/test_authentication.py b/test/functional/internal/crypto/test_authentication.py
index c17a078c..ef0abbc3 100644
--- a/test/functional/internal/crypto/test_authentication.py
+++ b/test/functional/internal/crypto/test_authentication.py
@@ -14,12 +14,13 @@
import pytest
from dynamodb_encryption_sdk.internal.crypto.authentication import _string_to_sign
+
from ...functional_test_vector_generators import string_to_sign_test_vectors
pytestmark = [pytest.mark.functional, pytest.mark.local]
-@pytest.mark.parametrize('item, table_name, attribute_actions, expected_result', string_to_sign_test_vectors())
+@pytest.mark.parametrize("item, table_name, attribute_actions, expected_result", string_to_sign_test_vectors())
def test_string_to_sign(item, table_name, attribute_actions, expected_result):
generated_string = _string_to_sign(item, table_name, attribute_actions)
assert generated_string == expected_result
diff --git a/test/functional/internal/formatting/test_attribute.py b/test/functional/internal/formatting/test_attribute.py
index 6b726f46..3cdac26a 100644
--- a/test/functional/internal/formatting/test_attribute.py
+++ b/test/functional/internal/formatting/test_attribute.py
@@ -11,32 +11,36 @@
# ANY KIND, either express or implied. See the License for the specific
# language governing permissions and limitations under the License.
"""Functional tests for attribute de/serialization."""
-from boto3.dynamodb.types import TypeDeserializer, TypeSerializer
import hypothesis
import pytest
+from boto3.dynamodb.types import TypeDeserializer, TypeSerializer
from dynamodb_encryption_sdk.exceptions import DeserializationError, SerializationError
from dynamodb_encryption_sdk.internal.formatting.deserialize.attribute import deserialize_attribute
from dynamodb_encryption_sdk.internal.formatting.serialize.attribute import serialize_attribute
from dynamodb_encryption_sdk.transform import ddb_to_dict, dict_to_ddb
+
from ...functional_test_vector_generators import attribute_test_vectors
-from ...hypothesis_strategies import ddb_attribute_values, ddb_items, SLOW_SETTINGS, VERY_SLOW_SETTINGS
+from ...hypothesis_strategies import SLOW_SETTINGS, VERY_SLOW_SETTINGS, ddb_attribute_values, ddb_items
pytestmark = [pytest.mark.functional, pytest.mark.local]
-@pytest.mark.parametrize('attribute, serialized', attribute_test_vectors('serialize'))
+@pytest.mark.parametrize("attribute, serialized", attribute_test_vectors("serialize"))
def test_serialize_attribute(attribute, serialized):
serialized_attribute = serialize_attribute(attribute)
assert serialized_attribute == serialized
-@pytest.mark.parametrize('attribute, expected_type, expected_message', (
- ({'_': None}, SerializationError, r'Unsupported DynamoDB data type: *'),
- ({}, SerializationError, r'cannot serialize attribute: incorrect number of members *'),
- ({'a': None, 'b': None}, SerializationError, r'cannot serialize attribute: incorrect number of members *'),
- (None, TypeError, r'Invalid attribute type *')
-))
+@pytest.mark.parametrize(
+ "attribute, expected_type, expected_message",
+ (
+ ({"_": None}, SerializationError, r"Unsupported DynamoDB data type: *"),
+ ({}, SerializationError, r"cannot serialize attribute: incorrect number of members *"),
+ ({"a": None, "b": None}, SerializationError, r"cannot serialize attribute: incorrect number of members *"),
+ (None, TypeError, r"Invalid attribute type *"),
+ ),
+)
def test_serialize_attribute_errors(attribute, expected_type, expected_message):
with pytest.raises(expected_type) as excinfo:
serialize_attribute(attribute)
@@ -44,19 +48,22 @@ def test_serialize_attribute_errors(attribute, expected_type, expected_message):
excinfo.match(expected_message)
-@pytest.mark.parametrize('attribute, serialized', attribute_test_vectors('deserialize'))
+@pytest.mark.parametrize("attribute, serialized", attribute_test_vectors("deserialize"))
def test_deserialize_attribute(attribute, serialized):
deserialized_attribute = deserialize_attribute(serialized)
assert deserialized_attribute == attribute
-@pytest.mark.parametrize('data, expected_type, expected_message', (
- (b'', DeserializationError, r'Empty serialized attribute data'),
- (b'_', DeserializationError, r'Malformed serialized data'),
- (b'\x00_', DeserializationError, r'Unsupported tag: *'),
- (b'__', DeserializationError, r'Invalid tag: reserved byte is not null'),
- (b'\x00M\x00\x00\x00\x01\x00\x00', DeserializationError, r'Malformed serialized map: *')
-))
+@pytest.mark.parametrize(
+ "data, expected_type, expected_message",
+ (
+ (b"", DeserializationError, r"Empty serialized attribute data"),
+ (b"_", DeserializationError, r"Malformed serialized data"),
+ (b"\x00_", DeserializationError, r"Unsupported tag: *"),
+ (b"__", DeserializationError, r"Invalid tag: reserved byte is not null"),
+ (b"\x00M\x00\x00\x00\x01\x00\x00", DeserializationError, r"Malformed serialized map: *"),
+ ),
+)
def test_deserialize_attribute_errors(data, expected_type, expected_message):
with pytest.raises(expected_type) as exc_info:
deserialize_attribute(data)
diff --git a/test/functional/internal/formatting/test_material_description.py b/test/functional/internal/formatting/test_material_description.py
index 1fbf219d..a951b518 100644
--- a/test/functional/internal/formatting/test_material_description.py
+++ b/test/functional/internal/formatting/test_material_description.py
@@ -16,24 +16,29 @@
from dynamodb_encryption_sdk.exceptions import InvalidMaterialDescriptionError, InvalidMaterialDescriptionVersionError
from dynamodb_encryption_sdk.internal.formatting.material_description import (
- deserialize as deserialize_material_description, serialize as serialize_material_description
+ deserialize as deserialize_material_description,
+ serialize as serialize_material_description,
)
+
from ...functional_test_vector_generators import material_description_test_vectors
-from ...hypothesis_strategies import material_descriptions, SLOW_SETTINGS, VERY_SLOW_SETTINGS
+from ...hypothesis_strategies import SLOW_SETTINGS, VERY_SLOW_SETTINGS, material_descriptions
pytestmark = [pytest.mark.functional, pytest.mark.local]
-@pytest.mark.parametrize('material_description, serialized', material_description_test_vectors())
+@pytest.mark.parametrize("material_description, serialized", material_description_test_vectors())
def test_serialize_material_description(material_description, serialized):
serialized_material_description = serialize_material_description(material_description)
assert serialized_material_description == serialized
-@pytest.mark.parametrize('data, expected_type, expected_message', (
- ({'test': 5}, InvalidMaterialDescriptionError, 'Invalid name or value in material description: *'),
- ({5: 'test'}, InvalidMaterialDescriptionError, 'Invalid name or value in material description: *'),
-))
+@pytest.mark.parametrize(
+ "data, expected_type, expected_message",
+ (
+ ({"test": 5}, InvalidMaterialDescriptionError, "Invalid name or value in material description: *"),
+ ({5: "test"}, InvalidMaterialDescriptionError, "Invalid name or value in material description: *"),
+ ),
+)
def test_serialize_material_description_errors(data, expected_type, expected_message):
with pytest.raises(expected_type) as exc_info:
serialize_material_description(data)
@@ -41,28 +46,35 @@ def test_serialize_material_description_errors(data, expected_type, expected_mes
exc_info.match(expected_message)
-@pytest.mark.parametrize('material_description, serialized', material_description_test_vectors())
+@pytest.mark.parametrize("material_description, serialized", material_description_test_vectors())
def test_deserialize_material_description(material_description, serialized):
deserialized_material_description = deserialize_material_description(serialized)
assert deserialized_material_description == material_description
-@pytest.mark.parametrize('data, expected_type, expected_message', (
- # Invalid version
- ({'B': b'\x00\x00\x00\x01'}, InvalidMaterialDescriptionVersionError, r'Invalid material description version: *'),
- # Malformed version
- ({'B': b'\x00\x00\x00'}, InvalidMaterialDescriptionError, r'Malformed material description version'),
- # Invalid attribute type
- ({'S': 'not bytes'}, InvalidMaterialDescriptionError, r'Invalid material description'),
- # Invalid data: not a DDB attribute
- (b'bare bytes', InvalidMaterialDescriptionError, r'Invalid material description'),
- # Partial entry
+@pytest.mark.parametrize(
+ "data, expected_type, expected_message",
(
- {'B': b'\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01A\x00\x00\x00\x01'},
- InvalidMaterialDescriptionError,
- r'Invalid material description'
- )
-))
+ # Invalid version
+ (
+ {"B": b"\x00\x00\x00\x01"},
+ InvalidMaterialDescriptionVersionError,
+ r"Invalid material description version: *",
+ ),
+ # Malformed version
+ ({"B": b"\x00\x00\x00"}, InvalidMaterialDescriptionError, r"Malformed material description version"),
+ # Invalid attribute type
+ ({"S": "not bytes"}, InvalidMaterialDescriptionError, r"Invalid material description"),
+ # Invalid data: not a DDB attribute
+ (b"bare bytes", InvalidMaterialDescriptionError, r"Invalid material description"),
+ # Partial entry
+ (
+ {"B": b"\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01A\x00\x00\x00\x01"},
+ InvalidMaterialDescriptionError,
+ r"Invalid material description",
+ ),
+ ),
+)
def test_deserialize_material_description_errors(data, expected_type, expected_message):
with pytest.raises(expected_type) as exc_info:
deserialize_material_description(data)
diff --git a/test/functional/internal/test_str_ops.py b/test/functional/internal/test_str_ops.py
index 785c5b93..704e3e3f 100644
--- a/test/functional/internal/test_str_ops.py
+++ b/test/functional/internal/test_str_ops.py
@@ -21,24 +21,30 @@
pytestmark = [pytest.mark.functional, pytest.mark.local]
-@pytest.mark.parametrize('data, expected_output', (
- ('asdf', 'asdf'),
- (b'asdf', 'asdf'),
- (codecs.encode(u'Предисловие', 'utf-8'), u'Предисловие'),
- (u'Предисловие', u'Предисловие')
-))
+@pytest.mark.parametrize(
+ "data, expected_output",
+ (
+ ("asdf", "asdf"),
+ (b"asdf", "asdf"),
+ (codecs.encode(u"Предисловие", "utf-8"), u"Предисловие"),
+ (u"Предисловие", u"Предисловие"),
+ ),
+)
def test_to_str(data, expected_output):
test = to_str(data)
assert test == expected_output
-@pytest.mark.parametrize('data, expected_output', (
- ('asdf', b'asdf'),
- (b'asdf', b'asdf'),
- (b'\x3a\x00\x99', b'\x3a\x00\x99'),
- (u'Предисловие', codecs.encode(u'Предисловие', 'utf-8')),
- (codecs.encode(u'Предисловие', 'utf-8'), codecs.encode(u'Предисловие', 'utf-8'))
-))
+@pytest.mark.parametrize(
+ "data, expected_output",
+ (
+ ("asdf", b"asdf"),
+ (b"asdf", b"asdf"),
+ (b"\x3a\x00\x99", b"\x3a\x00\x99"),
+ (u"Предисловие", codecs.encode(u"Предисловие", "utf-8")),
+ (codecs.encode(u"Предисловие", "utf-8"), codecs.encode(u"Предисловие", "utf-8")),
+ ),
+)
def test_to_bytes(data, expected_output):
test = to_bytes(data)
assert test == expected_output
diff --git a/test/functional/material_providers/store/test_meta.py b/test/functional/material_providers/store/test_meta.py
index 7d2ea0c1..ac2706d9 100644
--- a/test/functional/material_providers/store/test_meta.py
+++ b/test/functional/material_providers/store/test_meta.py
@@ -15,8 +15,8 @@
import os
import boto3
-from moto import mock_dynamodb2
import pytest
+from moto import mock_dynamodb2
from dynamodb_encryption_sdk.material_providers.store.meta import MetaStore
@@ -25,13 +25,13 @@
@mock_dynamodb2
def test_create_table():
- client = boto3.client('dynamodb', region_name='us-west-2')
- table_name = base64.b64encode(os.urandom(32)).decode('utf-8')
+ client = boto3.client("dynamodb", region_name="us-west-2")
+ table_name = base64.b64encode(os.urandom(32)).decode("utf-8")
MetaStore.create_table(client, table_name, 1, 1)
- waiter = client.get_waiter('table_exists')
+ waiter = client.get_waiter("table_exists")
waiter.wait(TableName=table_name)
client.delete_table(TableName=table_name)
- waiter = client.get_waiter('table_not_exists')
+ waiter = client.get_waiter("table_not_exists")
waiter.wait(TableName=table_name)
diff --git a/test/functional/material_providers/test_most_recent.py b/test/functional/material_providers/test_most_recent.py
index 399a7d11..60b082f5 100644
--- a/test/functional/material_providers/test_most_recent.py
+++ b/test/functional/material_providers/test_most_recent.py
@@ -11,8 +11,8 @@
# ANY KIND, either express or implied. See the License for the specific
# language governing permissions and limitations under the License.
"""Functional tests for ``dynamodb_encryption_sdk.material_providers.most_recent``."""
-from mock import MagicMock, sentinel
import pytest
+from mock import MagicMock, sentinel
from dynamodb_encryption_sdk.material_providers.most_recent import MostRecentProvider
from dynamodb_encryption_sdk.material_providers.store import ProviderStore
@@ -22,11 +22,7 @@
def test_failed_lock_acquisition():
store = MagicMock(__class__=ProviderStore)
- provider = MostRecentProvider(
- provider_store=store,
- material_name='my material',
- version_ttl=10.0
- )
+ provider = MostRecentProvider(provider_store=store, material_name="my material", version_ttl=10.0)
provider._version = 9
provider._cache.put(provider._version, sentinel.nine)
diff --git a/test/functional/materials/test_raw.py b/test/functional/materials/test_raw.py
index 0cc07735..f093f811 100644
--- a/test/functional/materials/test_raw.py
+++ b/test/functional/materials/test_raw.py
@@ -20,20 +20,20 @@
def test_no_encryption_key():
- signing_key = JceNameLocalDelegatedKey.generate('HmacSHA512', 256)
+ signing_key = JceNameLocalDelegatedKey.generate("HmacSHA512", 256)
encryption_materials = RawEncryptionMaterials(signing_key=signing_key)
with pytest.raises(AttributeError) as excinfo:
encryption_materials.encryption_key
- excinfo.match('No encryption key available')
+ excinfo.match("No encryption key available")
def test_no_decryption_key():
- verification_key = JceNameLocalDelegatedKey.generate('HmacSHA512', 256)
+ verification_key = JceNameLocalDelegatedKey.generate("HmacSHA512", 256)
decryption_materials = RawDecryptionMaterials(verification_key=verification_key)
with pytest.raises(AttributeError) as excinfo:
decryption_materials.decryption_key
- excinfo.match('No decryption key available')
+ excinfo.match("No decryption key available")
diff --git a/test/functional/test_hypothesis_strategies.py b/test/functional/test_hypothesis_strategies.py
index d2c7ec2e..3a8d560e 100644
--- a/test/functional/test_hypothesis_strategies.py
+++ b/test/functional/test_hypothesis_strategies.py
@@ -11,14 +11,15 @@
# ANY KIND, either express or implied. See the License for the specific
# language governing permissions and limitations under the License.
"""Tests to verify that our advanced hypothesis strategies are behaving as expected."""
-from boto3.dynamodb.types import DYNAMODB_CONTEXT
import hypothesis
import pytest
+from boto3.dynamodb.types import DYNAMODB_CONTEXT
from dynamodb_encryption_sdk.internal.formatting.deserialize.attribute import deserialize_attribute
from dynamodb_encryption_sdk.internal.formatting.serialize.attribute import serialize_attribute
-from dynamodb_encryption_sdk.transform import dict_to_ddb, ddb_to_dict
-from .hypothesis_strategies import ddb_items, ddb_negative_numbers, ddb_number, ddb_positive_numbers, VERY_SLOW_SETTINGS
+from dynamodb_encryption_sdk.transform import ddb_to_dict, dict_to_ddb
+
+from .hypothesis_strategies import VERY_SLOW_SETTINGS, ddb_items, ddb_negative_numbers, ddb_number, ddb_positive_numbers
pytestmark = [pytest.mark.functional, pytest.mark.slow, pytest.mark.local, pytest.mark.hypothesis_strategy]
diff --git a/test/functional/test_identifiers.py b/test/functional/test_identifiers.py
index 7baa7a59..7693489b 100644
--- a/test/functional/test_identifiers.py
+++ b/test/functional/test_identifiers.py
@@ -20,49 +20,58 @@
pytestmark = [pytest.mark.functional, pytest.mark.local]
-@pytest.mark.parametrize('left, right, expected', (
- (CryptoAction.ENCRYPT_AND_SIGN, CryptoAction.ENCRYPT_AND_SIGN, CryptoAction.ENCRYPT_AND_SIGN),
- (CryptoAction.ENCRYPT_AND_SIGN, CryptoAction.SIGN_ONLY, CryptoAction.ENCRYPT_AND_SIGN),
- (CryptoAction.ENCRYPT_AND_SIGN, CryptoAction.DO_NOTHING, CryptoAction.ENCRYPT_AND_SIGN),
- (CryptoAction.SIGN_ONLY, CryptoAction.ENCRYPT_AND_SIGN, CryptoAction.ENCRYPT_AND_SIGN),
- (CryptoAction.SIGN_ONLY, CryptoAction.SIGN_ONLY, CryptoAction.SIGN_ONLY),
- (CryptoAction.SIGN_ONLY, CryptoAction.DO_NOTHING, CryptoAction.SIGN_ONLY),
- (CryptoAction.DO_NOTHING, CryptoAction.ENCRYPT_AND_SIGN, CryptoAction.ENCRYPT_AND_SIGN),
- (CryptoAction.DO_NOTHING, CryptoAction.SIGN_ONLY, CryptoAction.SIGN_ONLY),
- (CryptoAction.DO_NOTHING, CryptoAction.DO_NOTHING, CryptoAction.DO_NOTHING),
-))
+@pytest.mark.parametrize(
+ "left, right, expected",
+ (
+ (CryptoAction.ENCRYPT_AND_SIGN, CryptoAction.ENCRYPT_AND_SIGN, CryptoAction.ENCRYPT_AND_SIGN),
+ (CryptoAction.ENCRYPT_AND_SIGN, CryptoAction.SIGN_ONLY, CryptoAction.ENCRYPT_AND_SIGN),
+ (CryptoAction.ENCRYPT_AND_SIGN, CryptoAction.DO_NOTHING, CryptoAction.ENCRYPT_AND_SIGN),
+ (CryptoAction.SIGN_ONLY, CryptoAction.ENCRYPT_AND_SIGN, CryptoAction.ENCRYPT_AND_SIGN),
+ (CryptoAction.SIGN_ONLY, CryptoAction.SIGN_ONLY, CryptoAction.SIGN_ONLY),
+ (CryptoAction.SIGN_ONLY, CryptoAction.DO_NOTHING, CryptoAction.SIGN_ONLY),
+ (CryptoAction.DO_NOTHING, CryptoAction.ENCRYPT_AND_SIGN, CryptoAction.ENCRYPT_AND_SIGN),
+ (CryptoAction.DO_NOTHING, CryptoAction.SIGN_ONLY, CryptoAction.SIGN_ONLY),
+ (CryptoAction.DO_NOTHING, CryptoAction.DO_NOTHING, CryptoAction.DO_NOTHING),
+ ),
+)
def test_item_action_max(left, right, expected):
assert max(left, right) == expected
-@pytest.mark.parametrize('left, right, expected', (
- (CryptoAction.ENCRYPT_AND_SIGN, CryptoAction.ENCRYPT_AND_SIGN, CryptoAction.ENCRYPT_AND_SIGN),
- (CryptoAction.ENCRYPT_AND_SIGN, CryptoAction.SIGN_ONLY, CryptoAction.SIGN_ONLY),
- (CryptoAction.ENCRYPT_AND_SIGN, CryptoAction.DO_NOTHING, CryptoAction.DO_NOTHING),
- (CryptoAction.SIGN_ONLY, CryptoAction.ENCRYPT_AND_SIGN, CryptoAction.SIGN_ONLY),
- (CryptoAction.SIGN_ONLY, CryptoAction.SIGN_ONLY, CryptoAction.SIGN_ONLY),
- (CryptoAction.SIGN_ONLY, CryptoAction.DO_NOTHING, CryptoAction.DO_NOTHING),
- (CryptoAction.DO_NOTHING, CryptoAction.ENCRYPT_AND_SIGN, CryptoAction.DO_NOTHING),
- (CryptoAction.DO_NOTHING, CryptoAction.SIGN_ONLY, CryptoAction.DO_NOTHING),
- (CryptoAction.DO_NOTHING, CryptoAction.DO_NOTHING, CryptoAction.DO_NOTHING),
-))
+@pytest.mark.parametrize(
+ "left, right, expected",
+ (
+ (CryptoAction.ENCRYPT_AND_SIGN, CryptoAction.ENCRYPT_AND_SIGN, CryptoAction.ENCRYPT_AND_SIGN),
+ (CryptoAction.ENCRYPT_AND_SIGN, CryptoAction.SIGN_ONLY, CryptoAction.SIGN_ONLY),
+ (CryptoAction.ENCRYPT_AND_SIGN, CryptoAction.DO_NOTHING, CryptoAction.DO_NOTHING),
+ (CryptoAction.SIGN_ONLY, CryptoAction.ENCRYPT_AND_SIGN, CryptoAction.SIGN_ONLY),
+ (CryptoAction.SIGN_ONLY, CryptoAction.SIGN_ONLY, CryptoAction.SIGN_ONLY),
+ (CryptoAction.SIGN_ONLY, CryptoAction.DO_NOTHING, CryptoAction.DO_NOTHING),
+ (CryptoAction.DO_NOTHING, CryptoAction.ENCRYPT_AND_SIGN, CryptoAction.DO_NOTHING),
+ (CryptoAction.DO_NOTHING, CryptoAction.SIGN_ONLY, CryptoAction.DO_NOTHING),
+ (CryptoAction.DO_NOTHING, CryptoAction.DO_NOTHING, CryptoAction.DO_NOTHING),
+ ),
+)
def test_item_action_min(left, right, expected):
assert min(left, right) == expected
-@pytest.mark.parametrize('left, right, expected_comparison', (
- (CryptoAction.ENCRYPT_AND_SIGN, CryptoAction.ENCRYPT_AND_SIGN, operator.eq),
- (CryptoAction.ENCRYPT_AND_SIGN, CryptoAction.SIGN_ONLY, operator.ne),
- (CryptoAction.ENCRYPT_AND_SIGN, CryptoAction.SIGN_ONLY, operator.gt),
- (CryptoAction.ENCRYPT_AND_SIGN, CryptoAction.DO_NOTHING, operator.gt),
- (CryptoAction.SIGN_ONLY, CryptoAction.ENCRYPT_AND_SIGN, operator.lt),
- (CryptoAction.SIGN_ONLY, CryptoAction.SIGN_ONLY, operator.eq),
- (CryptoAction.SIGN_ONLY, CryptoAction.DO_NOTHING, operator.ne),
- (CryptoAction.SIGN_ONLY, CryptoAction.DO_NOTHING, operator.gt),
- (CryptoAction.DO_NOTHING, CryptoAction.ENCRYPT_AND_SIGN, operator.lt),
- (CryptoAction.DO_NOTHING, CryptoAction.SIGN_ONLY, operator.lt),
- (CryptoAction.DO_NOTHING, CryptoAction.DO_NOTHING, operator.eq),
- (CryptoAction.DO_NOTHING, CryptoAction.ENCRYPT_AND_SIGN, operator.ne)
-))
+@pytest.mark.parametrize(
+ "left, right, expected_comparison",
+ (
+ (CryptoAction.ENCRYPT_AND_SIGN, CryptoAction.ENCRYPT_AND_SIGN, operator.eq),
+ (CryptoAction.ENCRYPT_AND_SIGN, CryptoAction.SIGN_ONLY, operator.ne),
+ (CryptoAction.ENCRYPT_AND_SIGN, CryptoAction.SIGN_ONLY, operator.gt),
+ (CryptoAction.ENCRYPT_AND_SIGN, CryptoAction.DO_NOTHING, operator.gt),
+ (CryptoAction.SIGN_ONLY, CryptoAction.ENCRYPT_AND_SIGN, operator.lt),
+ (CryptoAction.SIGN_ONLY, CryptoAction.SIGN_ONLY, operator.eq),
+ (CryptoAction.SIGN_ONLY, CryptoAction.DO_NOTHING, operator.ne),
+ (CryptoAction.SIGN_ONLY, CryptoAction.DO_NOTHING, operator.gt),
+ (CryptoAction.DO_NOTHING, CryptoAction.ENCRYPT_AND_SIGN, operator.lt),
+ (CryptoAction.DO_NOTHING, CryptoAction.SIGN_ONLY, operator.lt),
+ (CryptoAction.DO_NOTHING, CryptoAction.DO_NOTHING, operator.eq),
+ (CryptoAction.DO_NOTHING, CryptoAction.ENCRYPT_AND_SIGN, operator.ne),
+ ),
+)
def test_item_action_comp(left, right, expected_comparison):
assert expected_comparison(left, right)
diff --git a/test/functional/test_structures.py b/test/functional/test_structures.py
index 60810961..afe5c0f2 100644
--- a/test/functional/test_structures.py
+++ b/test/functional/test_structures.py
@@ -17,8 +17,12 @@
from dynamodb_encryption_sdk.exceptions import InvalidArgumentError
from dynamodb_encryption_sdk.identifiers import CryptoAction
from dynamodb_encryption_sdk.structures import AttributeActions, TableIndex, TableInfo
+
from .functional_test_utils import (
- example_table, table_with_global_seconary_indexes, table_with_local_seconary_indexes, TEST_TABLE_NAME
+ TEST_TABLE_NAME,
+ example_table,
+ table_with_global_seconary_indexes,
+ table_with_local_seconary_indexes,
)
pytestmark = [pytest.mark.functional, pytest.mark.local]
@@ -27,59 +31,51 @@
# TODO: There is a way to parameterize fixtures, but the existing docs on that are very unclear.
# This will get us what we need for now, but we should come back to this to clean this up later.
def test_tableinfo_refresh_indexes_no_secondary_indexes(example_table):
- client = boto3.client('dynamodb', region_name='us-west-2')
+ client = boto3.client("dynamodb", region_name="us-west-2")
table = TableInfo(name=TEST_TABLE_NAME)
table.refresh_indexed_attributes(client)
def test_tableinfo_refresh_indexes_with_gsis(table_with_global_seconary_indexes):
- client = boto3.client('dynamodb', region_name='us-west-2')
+ client = boto3.client("dynamodb", region_name="us-west-2")
table = TableInfo(name=TEST_TABLE_NAME)
table.refresh_indexed_attributes(client)
def test_tableinfo_refresh_indexes_with_lsis(table_with_local_seconary_indexes):
- client = boto3.client('dynamodb', region_name='us-west-2')
+ client = boto3.client("dynamodb", region_name="us-west-2")
table = TableInfo(name=TEST_TABLE_NAME)
table.refresh_indexed_attributes(client)
-@pytest.mark.parametrize('kwargs, expected_attributes', (
- (dict(partition='partition_name'), set(['partition_name'])),
- (dict(partition='partition_name', sort='sort_name'), set(['partition_name', 'sort_name']))
-))
+@pytest.mark.parametrize(
+ "kwargs, expected_attributes",
+ (
+ (dict(partition="partition_name"), set(["partition_name"])),
+ (dict(partition="partition_name", sort="sort_name"), set(["partition_name", "sort_name"])),
+ ),
+)
def test_tableindex_attributes(kwargs, expected_attributes):
index = TableIndex(**kwargs)
assert index.attributes == expected_attributes
-@pytest.mark.parametrize('key_schema, expected_kwargs', (
+@pytest.mark.parametrize(
+ "key_schema, expected_kwargs",
(
- [
- {
- 'KeyType': 'HASH',
- 'AttributeName': 'partition_name'
- }
- ],
- dict(partition='partition_name')
+ ([{"KeyType": "HASH", "AttributeName": "partition_name"}], dict(partition="partition_name")),
+ (
+ [
+ {"KeyType": "HASH", "AttributeName": "partition_name"},
+ {"KeyType": "RANGE", "AttributeName": "sort_name"},
+ ],
+ dict(partition="partition_name", sort="sort_name"),
+ ),
),
- (
- [
- {
- 'KeyType': 'HASH',
- 'AttributeName': 'partition_name'
- },
- {
- 'KeyType': 'RANGE',
- 'AttributeName': 'sort_name'
- }
- ],
- dict(partition='partition_name', sort='sort_name')
- )
-))
+)
def test_tableindex_from_key_schema(key_schema, expected_kwargs):
index = TableIndex.from_key_schema(key_schema)
expected_index = TableIndex(**expected_kwargs)
@@ -87,32 +83,34 @@ def test_tableindex_from_key_schema(key_schema, expected_kwargs):
assert index == expected_index
-@pytest.mark.parametrize('default, overrides, expected_result', (
- (CryptoAction.ENCRYPT_AND_SIGN, {}, CryptoAction.SIGN_ONLY),
- (CryptoAction.SIGN_ONLY, {}, CryptoAction.SIGN_ONLY),
- (CryptoAction.DO_NOTHING, {}, CryptoAction.DO_NOTHING),
- (CryptoAction.ENCRYPT_AND_SIGN, {'indexed_attribute': CryptoAction.SIGN_ONLY}, CryptoAction.SIGN_ONLY),
- (CryptoAction.ENCRYPT_AND_SIGN, {'indexed_attribute': CryptoAction.DO_NOTHING}, CryptoAction.DO_NOTHING),
- (CryptoAction.SIGN_ONLY, {'indexed_attribute': CryptoAction.SIGN_ONLY}, CryptoAction.SIGN_ONLY),
- (CryptoAction.SIGN_ONLY, {'indexed_attribute': CryptoAction.DO_NOTHING}, CryptoAction.DO_NOTHING),
- (CryptoAction.DO_NOTHING, {'indexed_attribute': CryptoAction.SIGN_ONLY}, CryptoAction.SIGN_ONLY),
- (CryptoAction.DO_NOTHING, {'indexed_attribute': CryptoAction.DO_NOTHING}, CryptoAction.DO_NOTHING)
-))
+@pytest.mark.parametrize(
+ "default, overrides, expected_result",
+ (
+ (CryptoAction.ENCRYPT_AND_SIGN, {}, CryptoAction.SIGN_ONLY),
+ (CryptoAction.SIGN_ONLY, {}, CryptoAction.SIGN_ONLY),
+ (CryptoAction.DO_NOTHING, {}, CryptoAction.DO_NOTHING),
+ (CryptoAction.ENCRYPT_AND_SIGN, {"indexed_attribute": CryptoAction.SIGN_ONLY}, CryptoAction.SIGN_ONLY),
+ (CryptoAction.ENCRYPT_AND_SIGN, {"indexed_attribute": CryptoAction.DO_NOTHING}, CryptoAction.DO_NOTHING),
+ (CryptoAction.SIGN_ONLY, {"indexed_attribute": CryptoAction.SIGN_ONLY}, CryptoAction.SIGN_ONLY),
+ (CryptoAction.SIGN_ONLY, {"indexed_attribute": CryptoAction.DO_NOTHING}, CryptoAction.DO_NOTHING),
+ (CryptoAction.DO_NOTHING, {"indexed_attribute": CryptoAction.SIGN_ONLY}, CryptoAction.SIGN_ONLY),
+ (CryptoAction.DO_NOTHING, {"indexed_attribute": CryptoAction.DO_NOTHING}, CryptoAction.DO_NOTHING),
+ ),
+)
def test_attribute_actions_index_override(default, overrides, expected_result):
test = AttributeActions(default_action=default, attribute_actions=overrides)
- test.set_index_keys('indexed_attribute')
+ test.set_index_keys("indexed_attribute")
- assert test.action('indexed_attribute') is expected_result
+ assert test.action("indexed_attribute") is expected_result
-@pytest.mark.parametrize('default', CryptoAction)
+@pytest.mark.parametrize("default", CryptoAction)
def test_attribute_actions_index_override_fail(default):
test = AttributeActions(
- default_action=default,
- attribute_actions={'indexed_attribute': CryptoAction.ENCRYPT_AND_SIGN}
+ default_action=default, attribute_actions={"indexed_attribute": CryptoAction.ENCRYPT_AND_SIGN}
)
with pytest.raises(InvalidArgumentError) as excinfo:
- test.set_index_keys('indexed_attribute')
+ test.set_index_keys("indexed_attribute")
- excinfo.match(r'Cannot overwrite a previously requested action on indexed attribute: *')
+ excinfo.match(r"Cannot overwrite a previously requested action on indexed attribute: *")
diff --git a/test/integration/encrypted/test_client.py b/test/integration/encrypted/test_client.py
index 965baa41..4d75d248 100644
--- a/test/integration/encrypted/test_client.py
+++ b/test/integration/encrypted/test_client.py
@@ -13,8 +13,11 @@
"""Integration tests for ``dynamodb_encryption_sdk.encrypted.client``."""
import pytest
-from ..integration_test_utils import aws_kms_cmp, ddb_table_name # noqa pylint: disable=unused-import
-from ..integration_test_utils import functional_test_utils
+from ..integration_test_utils import ( # noqa pylint: disable=unused-import
+ aws_kms_cmp,
+ ddb_table_name,
+ functional_test_utils,
+)
pytestmark = [pytest.mark.integ, pytest.mark.ddb_integ]
@@ -28,38 +31,26 @@ def pytest_generate_tests(metafunc):
def test_ephemeral_item_cycle(ddb_table_name, some_cmps, parametrized_actions, parametrized_item):
"""Test a small number of curated CMPs against a small number of curated items."""
functional_test_utils.client_cycle_single_item_check(
- some_cmps,
- parametrized_actions,
- parametrized_item,
- ddb_table_name
+ some_cmps, parametrized_actions, parametrized_item, ddb_table_name
)
def test_ephemeral_item_cycle_kms(ddb_table_name, aws_kms_cmp, parametrized_actions, parametrized_item):
"""Test the AWS KMS CMP against a small number of curated items."""
functional_test_utils.client_cycle_single_item_check(
- aws_kms_cmp,
- parametrized_actions,
- parametrized_item,
- ddb_table_name
+ aws_kms_cmp, parametrized_actions, parametrized_item, ddb_table_name
)
def test_ephemeral_batch_item_cycle(ddb_table_name, some_cmps, parametrized_actions, parametrized_item):
"""Test a small number of curated CMPs against a small number of curated items."""
functional_test_utils.client_cycle_batch_items_check(
- some_cmps,
- parametrized_actions,
- parametrized_item,
- ddb_table_name
+ some_cmps, parametrized_actions, parametrized_item, ddb_table_name
)
def test_ephemeral_batch_item_cycle_kms(ddb_table_name, aws_kms_cmp, parametrized_actions, parametrized_item):
"""Test the AWS KMS CMP against a small number of curated items."""
functional_test_utils.client_cycle_batch_items_check(
- aws_kms_cmp,
- parametrized_actions,
- parametrized_item,
- ddb_table_name
+ aws_kms_cmp, parametrized_actions, parametrized_item, ddb_table_name
)
diff --git a/test/integration/encrypted/test_resource.py b/test/integration/encrypted/test_resource.py
index 7f712950..a96ef764 100644
--- a/test/integration/encrypted/test_resource.py
+++ b/test/integration/encrypted/test_resource.py
@@ -13,8 +13,11 @@
"""Integration tests for ``dynamodb_encryption_sdk.encrypted.resource``."""
import pytest
-from ..integration_test_utils import aws_kms_cmp, ddb_table_name # noqa pylint: disable=unused-import
-from ..integration_test_utils import functional_test_utils
+from ..integration_test_utils import ( # noqa pylint: disable=unused-import
+ aws_kms_cmp,
+ ddb_table_name,
+ functional_test_utils,
+)
pytestmark = [pytest.mark.integ, pytest.mark.ddb_integ]
@@ -28,18 +31,12 @@ def pytest_generate_tests(metafunc):
def test_ephemeral_batch_item_cycle(ddb_table_name, some_cmps, parametrized_actions, parametrized_item):
"""Test a small number of curated CMPs against a small number of curated items."""
functional_test_utils.resource_cycle_batch_items_check(
- some_cmps,
- parametrized_actions,
- parametrized_item,
- ddb_table_name
+ some_cmps, parametrized_actions, parametrized_item, ddb_table_name
)
def test_ephemeral_batch_item_cycle_kms(ddb_table_name, aws_kms_cmp, parametrized_actions, parametrized_item):
"""Test the AWS KMS CMP against a small number of curated items."""
functional_test_utils.resource_cycle_batch_items_check(
- aws_kms_cmp,
- parametrized_actions,
- parametrized_item,
- ddb_table_name
+ aws_kms_cmp, parametrized_actions, parametrized_item, ddb_table_name
)
diff --git a/test/integration/encrypted/test_table.py b/test/integration/encrypted/test_table.py
index 0881cc9b..5bb17661 100644
--- a/test/integration/encrypted/test_table.py
+++ b/test/integration/encrypted/test_table.py
@@ -13,8 +13,11 @@
"""Integration tests for ``dynamodb_encryption_sdk.encrypted.table``."""
import pytest
-from ..integration_test_utils import aws_kms_cmp, ddb_table_name # noqa pylint: disable=unused-import
-from ..integration_test_utils import functional_test_utils
+from ..integration_test_utils import ( # noqa pylint: disable=unused-import
+ aws_kms_cmp,
+ ddb_table_name,
+ functional_test_utils,
+)
pytestmark = [pytest.mark.integ, pytest.mark.ddb_integ]
@@ -33,10 +36,7 @@ def test_ephemeral_item_cycle(ddb_table_name, some_cmps, parametrized_actions, p
def test_ephemeral_item_cycle_batch_writer(ddb_table_name, some_cmps, parametrized_actions, parametrized_item):
"""Test a small number of curated CMPs against a small number of curated items."""
functional_test_utils.table_cycle_batch_writer_check(
- some_cmps,
- parametrized_actions,
- parametrized_item,
- ddb_table_name
+ some_cmps, parametrized_actions, parametrized_item, ddb_table_name
)
diff --git a/test/integration/integration_test_utils.py b/test/integration/integration_test_utils.py
index edd699f7..f63729e8 100644
--- a/test/integration/integration_test_utils.py
+++ b/test/integration/integration_test_utils.py
@@ -12,24 +12,16 @@
# language governing permissions and limitations under the License.
"""Helper utilities for integration tests."""
import os
-import sys
import pytest
from dynamodb_encryption_sdk.material_providers.aws_kms import AwsKmsCryptographicMaterialsProvider
-sys.path.append(os.path.join(
- os.path.abspath(os.path.dirname(__file__)),
- '..',
- 'functional'
-))
+# convenience imports
+from ..functional import functional_test_utils, hypothesis_strategies
-# Convenience imports
-import functional_test_utils # noqa: E402,F401,I100 pylint: disable=import-error,unused-import,wrong-import-position
-import hypothesis_strategies # noqa: E402,F401,I100 pylint: disable=import-error,unused-import,wrong-import-position
-
-AWS_KMS_KEY_ID = 'AWS_ENCRYPTION_SDK_PYTHON_INTEGRATION_TEST_AWS_KMS_KEY_ID'
-DDB_TABLE_NAME = 'DDB_ENCRYPTION_CLIENT_TEST_TABLE_NAME'
+AWS_KMS_KEY_ID = "AWS_ENCRYPTION_SDK_PYTHON_INTEGRATION_TEST_AWS_KMS_KEY_ID"
+DDB_TABLE_NAME = "DDB_ENCRYPTION_CLIENT_TEST_TABLE_NAME"
@pytest.fixture
@@ -42,9 +34,9 @@ def cmk_arn():
AWS_KMS_KEY_ID
)
)
- if arn.startswith('arn:') and ':alias/' not in arn:
+ if arn.startswith("arn:") and ":alias/" not in arn:
return arn
- raise ValueError('KMS CMK ARN provided for integration tests must be a key not an alias')
+ raise ValueError("KMS CMK ARN provided for integration tests must be a key not an alias")
@pytest.fixture
@@ -61,8 +53,6 @@ def ddb_table_name():
raise ValueError(
(
'Environment variable "{}" must be set to the correct DynamoDB table name'
- ' for integration tests to run'
- ).format(
- AWS_KMS_KEY_ID
- )
+ " for integration tests to run"
+ ).format(AWS_KMS_KEY_ID)
)
diff --git a/test/integration/material_providers/store/test_meta.py b/test/integration/material_providers/store/test_meta.py
index 075f0c38..f2cceb2b 100644
--- a/test/integration/material_providers/store/test_meta.py
+++ b/test/integration/material_providers/store/test_meta.py
@@ -19,5 +19,3 @@
from dynamodb_encryption_sdk.material_providers.store.meta import MetaStore
pytestmark = [pytest.mark.integ]
-
-
diff --git a/test/integration/material_providers/test_aws_kms.py b/test/integration/material_providers/test_aws_kms.py
index dd4b5b5a..0a6e93d9 100644
--- a/test/integration/material_providers/test_aws_kms.py
+++ b/test/integration/material_providers/test_aws_kms.py
@@ -11,23 +11,24 @@
# ANY KIND, either express or implied. See the License for the specific
# language governing permissions and limitations under the License.
"""Integration tests for ``dynamodb_encryption_sdk.material_providers.aws_kms``."""
-import logging
import itertools
+import logging
-from boto3.dynamodb.types import Binary
import hypothesis
import pytest
+from boto3.dynamodb.types import Binary
from dynamodb_encryption_sdk.encrypted import CryptoConfig
-from dynamodb_encryption_sdk.identifiers import CryptoAction, USER_AGENT_SUFFIX
+from dynamodb_encryption_sdk.identifiers import USER_AGENT_SUFFIX, CryptoAction
from dynamodb_encryption_sdk.structures import AttributeActions, EncryptionContext
from dynamodb_encryption_sdk.transform import dict_to_ddb
+
from ..integration_test_utils import aws_kms_cmp # noqa pylint: disable=unused-import
from ..integration_test_utils import functional_test_utils, hypothesis_strategies
pytestmark = pytest.mark.integ
-_primary_key_names = ('partition_key', 'sort_key')
+_primary_key_names = ("partition_key", "sort_key")
def pytest_generate_tests(metafunc):
@@ -44,39 +45,32 @@ def test_verify_user_agent(aws_kms_cmp, caplog):
def _many_items():
- values = ('a string', 1234, Binary(b'binary \x00\x88 value'))
- partition_keys = (('partition_key', value) for value in values)
- sort_keys = (('sort_key', value) for value in values)
+ values = ("a string", 1234, Binary(b"binary \x00\x88 value"))
+ partition_keys = (("partition_key", value) for value in values)
+ sort_keys = (("sort_key", value) for value in values)
for pairs in itertools.product(partition_keys, sort_keys):
item = dict(pairs)
yield pytest.param(item, id=str(item))
-@pytest.mark.parametrize('item', _many_items())
+@pytest.mark.parametrize("item", _many_items())
def test_aws_kms_diverse_indexes(aws_kms_cmp, item):
"""Verify that AWS KMS cycle works for items with all possible combinations for primary index attribute types."""
crypto_config = CryptoConfig(
materials_provider=aws_kms_cmp,
encryption_context=EncryptionContext(
- partition_key_name='partition_key',
- sort_key_name='sort_key',
- attributes=dict_to_ddb(item)
+ partition_key_name="partition_key", sort_key_name="sort_key", attributes=dict_to_ddb(item)
),
attribute_actions=AttributeActions(
- attribute_actions={
- key: CryptoAction.SIGN_ONLY
- for key in _primary_key_names
- }
- )
+ attribute_actions={key: CryptoAction.SIGN_ONLY for key in _primary_key_names}
+ ),
)
functional_test_utils.cycle_item_check(item, crypto_config)
def test_aws_kms_item_cycle(aws_kms_cmp, parametrized_actions, parametrized_item):
crypto_config = CryptoConfig(
- materials_provider=aws_kms_cmp,
- encryption_context=EncryptionContext(),
- attribute_actions=parametrized_actions
+ materials_provider=aws_kms_cmp, encryption_context=EncryptionContext(), attribute_actions=parametrized_actions
)
functional_test_utils.cycle_item_check(parametrized_item, crypto_config)
@@ -86,9 +80,7 @@ def test_aws_kms_item_cycle(aws_kms_cmp, parametrized_actions, parametrized_item
@hypothesis.given(item=hypothesis_strategies.ddb_items)
def test_aws_kms_item_cycle_hypothesis_slow(aws_kms_cmp, hypothesis_actions, item):
crypto_config = CryptoConfig(
- materials_provider=aws_kms_cmp,
- encryption_context=EncryptionContext(),
- attribute_actions=hypothesis_actions
+ materials_provider=aws_kms_cmp, encryption_context=EncryptionContext(), attribute_actions=hypothesis_actions
)
functional_test_utils.cycle_item_check(item, crypto_config)
@@ -98,8 +90,6 @@ def test_aws_kms_item_cycle_hypothesis_slow(aws_kms_cmp, hypothesis_actions, ite
@hypothesis.given(item=hypothesis_strategies.ddb_items)
def test_aws_kms_item_cycle_hypothesis_veryslow(aws_kms_cmp, hypothesis_actions, item):
crypto_config = CryptoConfig(
- materials_provider=aws_kms_cmp,
- encryption_context=EncryptionContext(),
- attribute_actions=hypothesis_actions
+ materials_provider=aws_kms_cmp, encryption_context=EncryptionContext(), attribute_actions=hypothesis_actions
)
functional_test_utils.cycle_item_check(item, crypto_config)
diff --git a/test/pylintrc b/test/pylintrc
index 27d82a9c..bb25d2dc 100644
--- a/test/pylintrc
+++ b/test/pylintrc
@@ -4,12 +4,15 @@
#
# C0103 : invalid-name (we prefer long, descriptive, names for tests)
# C0111 : missing-docstring (we don't write docstrings for tests)
+# C0330 : bad-continuation (we let black handle this)
+# C0412 : ungrouped-imports (we let isort handle this)
# E1101 : no-member (raised on patched objects with mock checks)
+# R0205 : useless-object-inheritance (we need to support Python 2, so no, not useless)
# R0801 : duplicate-code (unit tests for similar things tend to be similar)
# W0212 : protected-access (raised when calling _ methods)
# W0621 : redefined-outer-name (raised when using pytest-mock)
# W0613 : unused-argument (raised when patches and fixtures are needed but not called)
-disable = C0103, C0111, E1101, R0801, W0212, W0621, W0613
+disable = C0103, C0111, C0330, C0412, E1101, R0205, R0801, W0212, W0621, W0613
[DESIGN]
max-args = 10
diff --git a/test/unit/encrypted/test_encrypted.py b/test/unit/encrypted/test_encrypted.py
index ec736f9e..9c2917aa 100644
--- a/test/unit/encrypted/test_encrypted.py
+++ b/test/unit/encrypted/test_encrypted.py
@@ -15,6 +15,7 @@
from dynamodb_encryption_sdk.encrypted import CryptoConfig
from dynamodb_encryption_sdk.structures import AttributeActions, EncryptionContext
+
from ..unit_test_utils import wrapped_cmp # noqa pylint: disable=unused-import
pytestmark = [pytest.mark.unit, pytest.mark.local]
@@ -24,12 +25,9 @@ def test_with_item(wrapped_cmp):
config = CryptoConfig(
materials_provider=wrapped_cmp,
encryption_context=EncryptionContext(attributes={}),
- attribute_actions=AttributeActions()
+ attribute_actions=AttributeActions(),
)
- item = {
- 'test': 'item',
- 'with': 'some data'
- }
+ item = {"test": "item", "with": "some data"}
new_config = config.with_item(item)
assert config.encryption_context.attributes == {}
diff --git a/test/unit/internal/formatting/test_attribute.py b/test/unit/internal/formatting/test_attribute.py
index fae2b415..71235e0c 100644
--- a/test/unit/internal/formatting/test_attribute.py
+++ b/test/unit/internal/formatting/test_attribute.py
@@ -20,25 +20,22 @@
pytestmark = [pytest.mark.unit, pytest.mark.local]
-@pytest.mark.parametrize('initial, expected, transform', (
+@pytest.mark.parametrize(
+ "initial, expected, transform",
(
- {
- 'test': 'value',
- 'zzz': 'another',
- 'aaa': 'qqq',
- '?>?>?': 5,
- b'\x00\x00': None
- },
- [
- (b'\x00\x00', None, b'\x00\x00'),
- (b'?>?>?', 5, '?>?>?'),
- (b'aaa', 'qqq', 'aaa'),
- (b'test', 'value', 'test'),
- (b'zzz', 'another', 'zzz')
- ],
- to_bytes
+ (
+ {"test": "value", "zzz": "another", "aaa": "qqq", "?>?>?": 5, b"\x00\x00": None},
+ [
+ (b"\x00\x00", None, b"\x00\x00"),
+ (b"?>?>?", 5, "?>?>?"),
+ (b"aaa", "qqq", "aaa"),
+ (b"test", "value", "test"),
+ (b"zzz", "another", "zzz"),
+ ],
+ to_bytes,
+ ),
),
-))
+)
def test_sorted_key_map(initial, expected, transform):
actual = _sorted_key_map(initial, transform)
diff --git a/test/unit/material_providers/__init__.py b/test/unit/material_providers/__init__.py
index 5eb0e67b..48f88c23 100644
--- a/test/unit/material_providers/__init__.py
+++ b/test/unit/material_providers/__init__.py
@@ -18,15 +18,15 @@
pytestmark = [pytest.mark.unit, pytest.mark.local]
-@pytest.mark.parametrize('method, message', (
- ('decryption_materials', 'No decryption materials available'),
- ('encryption_materials', 'No encryption materials available')
-))
+@pytest.mark.parametrize(
+ "method, message",
+ (
+ ("decryption_materials", "No decryption materials available"),
+ ("encryption_materials", "No encryption materials available"),
+ ),
+)
def test_no_materials(method, message):
- empty_cmp = CryptographicMaterialsProvider(
- decryption_materials=None,
- encryption_materials=None
- )
+ empty_cmp = CryptographicMaterialsProvider(decryption_materials=None, encryption_materials=None)
with pytest.raises(AttributeError) as excinfo:
getattr(empty_cmp, method)(None)
diff --git a/test/unit/material_providers/test_aws_kms.py b/test/unit/material_providers/test_aws_kms.py
index c8109a4e..a1166dba 100644
--- a/test/unit/material_providers/test_aws_kms.py
+++ b/test/unit/material_providers/test_aws_kms.py
@@ -12,136 +12,131 @@
# language governing permissions and limitations under the License.
"""Unit tests for ``dynamodb_encryption_sdk.material_providers.aws_kms``."""
import base64
-from mock import MagicMock, sentinel
import boto3
import botocore
-from moto import mock_kms
import pytest
+from mock import MagicMock, sentinel
+from moto import mock_kms
from pytest_mock import mocker # noqa pylint: disable=unused-import
+import dynamodb_encryption_sdk.material_providers.aws_kms
from dynamodb_encryption_sdk.delegated_keys.jce import JceNameLocalDelegatedKey
from dynamodb_encryption_sdk.exceptions import UnknownRegionError, UnwrappingError, WrappingError
from dynamodb_encryption_sdk.identifiers import EncryptionKeyType, KeyEncodingType
-import dynamodb_encryption_sdk.material_providers.aws_kms
from dynamodb_encryption_sdk.material_providers.aws_kms import (
- _DEFAULT_CONTENT_ENCRYPTION_ALGORITHM, _DEFAULT_SIGNING_ALGORITHM,
- AwsKmsCryptographicMaterialsProvider, KeyInfo
+ _DEFAULT_CONTENT_ENCRYPTION_ALGORITHM,
+ _DEFAULT_SIGNING_ALGORITHM,
+ AwsKmsCryptographicMaterialsProvider,
+ KeyInfo,
)
from dynamodb_encryption_sdk.structures import EncryptionContext
pytestmark = [pytest.mark.unit, pytest.mark.local]
-_VALID_KEY_INFO_KWARGS = dict(
- description='some string',
- algorithm='algorithm name',
- length=1234
-)
-_REGION = 'fake-region'
-_KEY_ID = 'arn:aws:kms:{}:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab'.format(_REGION)
+_VALID_KEY_INFO_KWARGS = dict(description="some string", algorithm="algorithm name", length=1234)
+_REGION = "fake-region"
+_KEY_ID = "arn:aws:kms:{}:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab".format(_REGION)
_DERIVED_KEYS = {
- 'initial_material': b'\xafx2"\xb5\xd5`\xc6\x8d\xaa\xfe\xc10E3x?D\x18\x93$<\x161\xcb\x99\xef\xc0Z\x1a\x1b]',
- 'encrypted_initial_material': (
+ "initial_material": b'\xafx2"\xb5\xd5`\xc6\x8d\xaa\xfe\xc10E3x?D\x18\x93$<\x161\xcb\x99\xef\xc0Z\x1a\x1b]',
+ "encrypted_initial_material": (
b"\x01\x01\x02\x00x@\xf3\x8c'^1\tt\x16\xc1\x07)QPW\x19d\xad\xa3\xef\x1c!\xe9L\x8b\xa0\xbd\xbc\x9d\x0f\xb4\x14"
b"\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"
b"\x1e\x06\t`\x86H\x01e\x03\x04\x01.0\x11\x04\x0c-\xc0&\x1f\xeb_\xdek\xca/$y\x02\x01\x10\x80;!\x99z\xbek3|\x8b"
b"\x98\x1b\xba\x91H<\xb1X\x8c\xc7vGv\x84*\xe1\xf1B\xd4\xe5&\xa2\xa3)\x04\x1f\xad\t\x07\x90\x14\xbeQo\xa0\xff"
b"\x1a\xc2\xa5(i\x0c4\x10\xe8\xe2\xf3\x17}\t\xd6"
), # encrypted using our public-test CMK in us-west-2
- 'encryption_key': b'\xb3~{,Z\x80\x7f\x82I\xe5=3.1.0
commands =
@@ -241,6 +256,65 @@ commands =
pylint --rcfile=examples/src/pylintrc examples/src/
pylint --rcfile=examples/test/pylintrc examples/test/
+[testenv:blacken-src]
+basepython = python3
+deps =
+ black
+commands =
+ black --line-length 120 \
+ src/dynamodb_encryption_sdk/ \
+ setup.py \
+ doc/conf.py \
+ test/ \
+ examples/ \
+ {posargs}
+
+
+[testenv:blacken]
+basepython = python3
+deps =
+ {[testenv:blacken-src]deps}
+commands =
+ {[testenv:blacken-src]commands}
+
+[testenv:black-check]
+basepython = python3
+deps =
+ {[testenv:blacken]deps}
+commands =
+ {[testenv:blacken-src]commands} --diff
+
+[testenv:isort-seed]
+basepython = python3
+deps = seed-isort-config
+commands = seed-isort-config
+
+[testenv:isort]
+basepython = python3
+deps = isort
+commands = isort -rc \
+ src \
+ test \
+ # We do not include examples/test because of the need to modify sys.path for some imports
+ examples/src/ \
+ doc \
+ setup.py \
+ {posargs}
+
+[testenv:isort-check]
+basepython = python3
+deps = {[testenv:isort]deps}
+commands = {[testenv:isort]commands} -c
+
+[testenv:autoformat]
+basepython = python3
+deps =
+ {[testenv:isort]deps}
+ {[testenv:blacken]deps}
+commands =
+ {[testenv:isort]commands}
+ {[testenv:blacken]commands}
+
# Clear out any generated files from doc/
[testenv:resetdocs]
whitelist_externals =