Skip to content

most recent provider and provider stores #42

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
May 2, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions doc/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,11 @@ Modules
dynamodb_encryption_sdk.encrypted.table
dynamodb_encryption_sdk.material_providers
dynamodb_encryption_sdk.material_providers.aws_kms
dynamodb_encryption_sdk.material_providers.most_recent
dynamodb_encryption_sdk.material_providers.static
dynamodb_encryption_sdk.material_providers.wrapped
dynamodb_encryption_sdk.material_providers.store
dynamodb_encryption_sdk.material_providers.store.meta
dynamodb_encryption_sdk.materials
dynamodb_encryption_sdk.materials.raw
dynamodb_encryption_sdk.materials.wrapped
Expand Down
50 changes: 32 additions & 18 deletions src/dynamodb_encryption_sdk/delegated_keys/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"""Delegated keys."""
import abc
try: # Python 3.5.0 and 3.5.1 have incompatible typing modules
from typing import Dict, Text # noqa pylint: disable=unused-import
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
Expand Down Expand Up @@ -43,17 +43,24 @@ class DelegatedKey(object):
a ``NotImplementedError`` detailing this.
"""

#: Most delegated keys should not be used with RawCryptographicMaterials.
allowed_for_raw_materials = False

@abc.abstractproperty
def algorithm(self):
# type: () -> Text
"""Text description of algorithm used by this delegated key."""

@property
def allowed_for_raw_materials(self):
# type: () -> bool
"""Most delegated keys should not be used with RawCryptographicMaterials.

:returns: False
:rtype: bool
"""
return False

@classmethod
def generate(cls, algorithm, key_length):
# type: (Text, int) -> None
def generate(cls, algorithm, key_length): # type: ignore
# type: (Text, int) -> DelegatedKey
# pylint: disable=unused-argument,no-self-use
"""Generate an instance of this DelegatedKey using the specified algorithm and key length.

Expand All @@ -64,8 +71,8 @@ def generate(cls, algorithm, key_length):
"""
_raise_not_implemented('generate')

def encrypt(self, algorithm, name, plaintext, additional_associated_data=None):
# type: (Text, Text, bytes, Dict[Text, Text]) -> bytes
def encrypt(self, algorithm, name, plaintext, additional_associated_data=None): # type: ignore
# type: (Text, Text, bytes, Optional[Dict[Text, Text]]) -> bytes
# pylint: disable=unused-argument,no-self-use
"""Encrypt data.

Expand All @@ -79,8 +86,8 @@ def encrypt(self, algorithm, name, plaintext, additional_associated_data=None):
"""
_raise_not_implemented('encrypt')

def decrypt(self, algorithm, name, ciphertext, additional_associated_data=None):
# type: (Text, Text, bytes, Dict[Text, Text]) -> bytes
def decrypt(self, algorithm, name, ciphertext, additional_associated_data=None): # type: ignore
# type: (Text, Text, bytes, Optional[Dict[Text, Text]]) -> bytes
# pylint: disable=unused-argument,no-self-use
"""Encrypt data.

Expand All @@ -94,8 +101,8 @@ def decrypt(self, algorithm, name, ciphertext, additional_associated_data=None):
"""
_raise_not_implemented('decrypt')

def wrap(self, algorithm, content_key, additional_associated_data=None):
# type: (Text, bytes, Dict[Text, Text]) -> bytes
def wrap(self, algorithm, content_key, additional_associated_data=None): # type: ignore
# type: (Text, bytes, Optional[Dict[Text, Text]]) -> bytes
# pylint: disable=unused-argument,no-self-use
"""Wrap content key.

Expand All @@ -108,8 +115,15 @@ def wrap(self, algorithm, content_key, additional_associated_data=None):
"""
_raise_not_implemented('wrap')

def unwrap(self, algorithm, wrapped_key, wrapped_key_algorithm, wrapped_key_type, additional_associated_data=None):
# type: (Text, bytes, Text, EncryptionKeyType, Dict[Text, Text]) -> DelegatedKey
def unwrap( # type: ignore
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
"""Wrap content key.

Expand All @@ -125,7 +139,7 @@ def unwrap(self, algorithm, wrapped_key, wrapped_key_algorithm, wrapped_key_type
"""
_raise_not_implemented('unwrap')

def sign(self, algorithm, data):
def sign(self, algorithm, data): # type: ignore
# type: (Text, bytes) -> bytes
# pylint: disable=unused-argument,no-self-use
"""Sign data.
Expand All @@ -137,7 +151,7 @@ def sign(self, algorithm, data):
"""
_raise_not_implemented('sign')

def verify(self, algorithm, signature, data):
def verify(self, algorithm, signature, data): # type: ignore
# type: (Text, bytes, bytes) -> None
# pylint: disable=unused-argument,no-self-use
"""Sign data.
Expand All @@ -148,10 +162,10 @@ def verify(self, algorithm, signature, data):
"""
_raise_not_implemented('verify')

def signing_algorithm(self):
def signing_algorithm(self): # type: ignore
# type: () -> Text
# pylint: disable=no-self-use
"""Provides a description that can inform an appropriate cryptographic materials
"""Provide a description that can inform an appropriate cryptographic materials
provider about how to build a DelegatedKey for signature verification. If implemented,
the return value of this method is included in the material description written to
the encrypted item.
Expand Down
38 changes: 32 additions & 6 deletions src/dynamodb_encryption_sdk/delegated_keys/jce.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@
from cryptography.hazmat.primitives.asymmetric import rsa
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.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
Expand Down Expand Up @@ -67,7 +73,7 @@ def _generate_rsa_key(key_length):
}


@attr.s
@attr.s(init=False)
class JceNameLocalDelegatedKey(DelegatedKey):
# pylint: disable=too-many-instance-attributes
"""Delegated key that uses JCE StandardName algorithm values to determine behavior.
Expand Down Expand Up @@ -114,6 +120,25 @@ class JceNameLocalDelegatedKey(DelegatedKey):
_key_type = attr.ib(validator=attr.validators.instance_of(EncryptionKeyType))
_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
):
# type: (...) -> None
"""Workaround pending resolution of attrs/mypy interaction.
https://github.com/python/mypy/issues/2088
https://github.com/python-attrs/attrs/issues/215
"""
self.key = key
self._algorithm = algorithm
self._key_type = key_type
self._key_encoding = key_encoding
attr.validate(self)
self.__attrs_post_init__()

@property
def algorithm(self):
# type: () -> Text
Expand Down Expand Up @@ -203,6 +228,7 @@ def generate(cls, algorithm, key_length=None):

@property
def allowed_for_raw_materials(self):
# type: () -> bool
"""Only ``JceNameLocalDelegatedKey`` backed by AES keys are allowed to be used with
``RawCryptographicMaterials``.

Expand All @@ -212,7 +238,7 @@ def allowed_for_raw_materials(self):
return self.algorithm == 'AES'

def _encrypt(self, algorithm, name, plaintext, additional_associated_data=None):
# type: (Text, Text, bytes, Dict[Text, Text]) -> bytes
# type: (Text, Text, bytes, Optional[Dict[Text, Text]]) -> bytes
# pylint: disable=unused-argument
"""
Encrypt data.
Expand All @@ -230,7 +256,7 @@ def _encrypt(self, algorithm, name, plaintext, additional_associated_data=None):
return encryptor.encrypt(self.__key, plaintext)

def _decrypt(self, algorithm, name, ciphertext, additional_associated_data=None):
# type: (Text, Text, bytes, Dict[Text, Text]) -> bytes
# type: (Text, Text, bytes, Optional[Dict[Text, Text]]) -> bytes
# pylint: disable=unused-argument
"""Encrypt data.

Expand All @@ -246,7 +272,7 @@ def _decrypt(self, algorithm, name, ciphertext, additional_associated_data=None)
return decryptor.decrypt(self.__key, ciphertext)

def _wrap(self, algorithm, content_key, additional_associated_data=None):
# type: (Text, bytes, Dict[Text, Text]) -> bytes
# type: (Text, bytes, Optional[Dict[Text, Text]]) -> bytes
# pylint: disable=unused-argument
"""Wrap content key.

Expand All @@ -263,7 +289,7 @@ def _wrap(self, algorithm, content_key, additional_associated_data=None):
)

def _unwrap(self, algorithm, wrapped_key, wrapped_key_algorithm, wrapped_key_type, additional_associated_data=None):
# type: (Text, bytes, Text, EncryptionKeyType, Dict[Text, Text]) -> DelegatedKey
# type: (Text, bytes, Text, EncryptionKeyType, Optional[Dict[Text, Text]]) -> DelegatedKey
# pylint: disable=unused-argument
"""Wrap content key.

Expand Down Expand Up @@ -316,7 +342,7 @@ def _verify(self, algorithm, signature, data):

def _signing_algorithm(self):
# type: () -> Text
"""Provides a description that can inform an appropriate cryptographic materials
"""Provide a description that can inform an appropriate cryptographic materials
provider about how to build a ``JceNameLocalDelegatedKey`` for signature verification.
The return value of this method is included in the material description written to
the encrypted item.
Expand Down
19 changes: 18 additions & 1 deletion src/dynamodb_encryption_sdk/encrypted/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
__all__ = ('CryptoConfig',)


@attr.s
@attr.s(init=False)
class CryptoConfig(object):
"""Container for all configuration needed to encrypt or decrypt an item.

Expand All @@ -46,6 +46,23 @@ class CryptoConfig(object):
encryption_context = attr.ib(validator=attr.validators.instance_of(EncryptionContext))
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
):
# type: (...) -> None
"""Workaround pending resolution of attrs/mypy interaction.
https://github.com/python/mypy/issues/2088
https://github.com/python-attrs/attrs/issues/215
"""
self.materials_provider = materials_provider
self.encryption_context = encryption_context
self.attribute_actions = attribute_actions
attr.validate(self)
self.__attrs_post_init__()

def __attrs_post_init__(self):
# type: () -> None
"""Make sure that primary index attributes are not being encrypted."""
Expand Down
52 changes: 49 additions & 3 deletions src/dynamodb_encryption_sdk/encrypted/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,12 @@
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,
Expand All @@ -30,7 +36,7 @@
__all__ = ('EncryptedClient',)


@attr.s
@attr.s(init=False)
class EncryptedPaginator(object):
"""Paginator that decrypts returned items before returning them.

Expand All @@ -44,6 +50,22 @@ class EncryptedPaginator(object):
_decrypt_method = attr.ib()
_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
):
# type: (...) -> None
"""Workaround pending resolution of attrs/mypy interaction.
https://github.com/python/mypy/issues/2088
https://github.com/python-attrs/attrs/issues/215
"""
self._paginator = paginator
self._decrypt_method = decrypt_method
self._crypto_config_method = crypto_config_method
attr.validate(self)

@_decrypt_method.validator
def validate_decrypt_method(self, attribute, value):
# pylint: disable=unused-argument
Expand All @@ -66,7 +88,7 @@ def __getattr__(self, name):
return getattr(self._paginator, name)

def paginate(self, **kwargs):
# type: (**Any) -> Dict
# type: (**Any) -> Iterator[Dict]
# TODO: narrow this down
"""Create an iterator that will paginate through responses from the underlying paginator,
transparently decrypting any returned items.
Expand All @@ -84,7 +106,7 @@ def paginate(self, **kwargs):
yield page


@attr.s
@attr.s(init=False)
class EncryptedClient(object):
# pylint: disable=too-few-public-methods,too-many-instance-attributes
"""High-level helper class to provide a familiar interface to encrypted tables.
Expand Down Expand Up @@ -143,6 +165,30 @@ class EncryptedClient(object):
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]
):
# type: (...) -> None
"""Workaround pending resolution of attrs/mypy interaction.
https://github.com/python/mypy/issues/2088
https://github.com/python-attrs/attrs/issues/215
"""
if attribute_actions is None:
attribute_actions = AttributeActions()

self._client = client
self._materials_provider = materials_provider
self._attribute_actions = attribute_actions
self._auto_refresh_table_indexes = auto_refresh_table_indexes
self._expect_standard_dictionaries = expect_standard_dictionaries
attr.validate(self)
self.__attrs_post_init__()

def __attrs_post_init__(self):
"""Set up the table info cache and translation methods."""
if self._expect_standard_dictionaries:
Expand Down
Loading