Skip to content

High level helpers #3

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

Closed
wants to merge 70 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
70 commits
Select commit Hold shift + click to select a range
190dc0e
initial draft of EncryptedTable
mattsb42-aws Mar 7, 2018
b5c82ac
adding encryption_context_values property for TableInfo objects
mattsb42-aws Mar 8, 2018
1496a56
simplifying possible per-item configuration to only accept a CryptoCo…
mattsb42-aws Mar 8, 2018
0ad53cb
adding TableInfoCache helper
mattsb42-aws Mar 8, 2018
4dab1bb
initial draft of EncryptedResource
mattsb42-aws Mar 8, 2018
c236f7c
fixing EncryptedTable encrypted-multi-get response processing and cle…
mattsb42-aws Mar 8, 2018
15c3160
initial draft of EncryptedClient
mattsb42-aws Mar 8, 2018
5ee9201
fixing mismatched get/put code in EncryptedTable
mattsb42-aws Mar 8, 2018
8636629
fixing output of TableInfo.encryption_context_values to use correct n…
mattsb42-aws Mar 8, 2018
ea46688
separating encrypted item check from cycle item check
mattsb42-aws Mar 8, 2018
3ae7eb2
streamlining encrypted item tests
mattsb42-aws Mar 8, 2018
a32304e
adding hypothesis pytest marker
mattsb42-aws Mar 8, 2018
5baf0df
blacklisting quote characters in hypothesis strings until moto bug is…
mattsb42-aws Mar 8, 2018
7aeaaec
adding functional tests for EncryptedTable
mattsb42-aws Mar 8, 2018
cb2efeb
fixing Encrypted Table/Resource/Client to not modify the provided att…
mattsb42-aws Mar 9, 2018
2e03b64
adding single-item tests for EncryptedClient
mattsb42-aws Mar 9, 2018
2de9d97
adding comments and manual mode
mattsb42-aws Mar 14, 2018
63e8a65
fixing batch_write_item handling
mattsb42-aws Mar 19, 2018
6abecd4
clean up after the moto table
mattsb42-aws Mar 19, 2018
043308b
initial draft of batch_write_item and batch_get_item tests for Encryp…
mattsb42-aws Mar 19, 2018
4af5a4f
adding check for reserved attributes in encrypt_dynamodb_item
mattsb42-aws Mar 19, 2018
d84ad45
reorganizing tests to reflect source structure
mattsb42-aws Mar 19, 2018
79f8988
separating out batch check logic and removing irrelevant actions from…
mattsb42-aws Mar 20, 2018
1a102fb
adding type validators for encrypted helpers
mattsb42-aws Mar 20, 2018
ebf7e12
consolidating batch cycle testing logic and adding initial EncryptedR…
mattsb42-aws Mar 20, 2018
0acd275
adding :
mattsb42-aws Mar 20, 2018
3a00752
revamp custom validators to consolidate code and simplify reuse
mattsb42-aws Mar 21, 2018
cc8bd6b
Remove the "hash=False" qualifier in attr.s setup.
mattsb42-aws Mar 21, 2018
e515838
Normalize all encoding to explicit utf-8.
mattsb42-aws Mar 21, 2018
dacae61
Add __all__ definitions where they are missing
mattsb42-aws Mar 21, 2018
1532eb7
explicitly clean up after single-item cycle checks
mattsb42-aws Mar 21, 2018
f56c21e
move to deep validator for TableInfo indexed attributes
mattsb42-aws Mar 21, 2018
7eacfed
tweak some tests to fix errors missed in rebase
mattsb42-aws Mar 23, 2018
f955007
fix material description error names
mattsb42-aws Mar 26, 2018
ccddf1b
* simplify handling of indexes
mattsb42-aws Mar 26, 2018
2ad7818
* fix TableIndex attributes generation to properly include sort attri…
mattsb42-aws Mar 26, 2018
682564c
expand abstraction layer docs and add explanation of how to provide p…
mattsb42-aws Mar 26, 2018
15c36c5
add and use callable_validator
mattsb42-aws Mar 28, 2018
62f7e3f
move test requirements into test/requirements.txt
mattsb42-aws Mar 28, 2018
aa9347b
add nocmk tox testenv to verify that local tests run successfully wit…
mattsb42-aws Mar 28, 2018
ca06b49
flake8 fixes
mattsb42-aws Mar 28, 2018
fe6f480
pylint fixes
mattsb42-aws Mar 29, 2018
fc95bc9
consolidate encrypt/decrypt layers across encrypted Client/Resource/T…
mattsb42-aws Mar 29, 2018
da84f37
consolidate crypto config building logic across encrypted Client/Reso…
mattsb42-aws Mar 29, 2018
ab89eb3
flake8-tests fixes
mattsb42-aws Mar 29, 2018
bc261f2
pylint-tests update and fixes
mattsb42-aws Mar 29, 2018
9a223e5
add wrapped-aes-hmac encrypted item test vectors
mattsb42-aws Mar 30, 2018
ac3673b
* add direct AWS KMS encrypted item test vectors
mattsb42-aws Mar 30, 2018
fd7ebd0
fix hypothesis decimal strategy to fully filter out values that are n…
mattsb42-aws Mar 30, 2018
84f8366
* rename EncryptionKeyTypes to EncryptionKeyType for consistency
mattsb42-aws Apr 2, 2018
09218fc
rename ItemAction to CryptoAction to make the name make more sense: i…
mattsb42-aws Apr 3, 2018
974a58a
add code samples to encrypted helper docstrings
mattsb42-aws Apr 3, 2018
4f50db3
separate logic for table cycle checks to prepare for EncryptedTable i…
mattsb42-aws Apr 3, 2018
b4e55dd
add EncryptedTable integration tests
mattsb42-aws Apr 3, 2018
3aa4b6c
add CloudFormation template to build table used for integration tests
mattsb42-aws Apr 3, 2018
92ae239
separate resource_cycle_batch_items_check logic out to prepare for En…
mattsb42-aws Apr 3, 2018
fbead80
add EncryptedResource integration tests
mattsb42-aws Apr 3, 2018
9b73b00
separate client cycle items checkers to prepare for EncryptedClient i…
mattsb42-aws Apr 3, 2018
ac11e8b
add EncryptedClient integration tests
mattsb42-aws Apr 3, 2018
1e58f30
add pytest acceptance and examples test markers
mattsb42-aws Apr 3, 2018
05a8c24
add examples infrastructure and simple EncryptedTable example with test
mattsb42-aws Apr 3, 2018
81e3276
add more examples using the KMS CMP
mattsb42-aws Apr 3, 2018
7dcc626
update docs index to include all modules
mattsb42-aws Apr 5, 2018
e25908a
update JceNameLocalDelegatedKey docs to explain algorithm names and s…
mattsb42-aws Apr 5, 2018
1bb5b7d
add ability to control item transformer used in EncryptedClient: this…
mattsb42-aws Apr 5, 2018
df0a8f0
add batch_writer to EncryptedTable
mattsb42-aws Apr 5, 2018
9c570de
fix JceNameLocalDelegatedKey.generate to only accept number of bits t…
mattsb42-aws Apr 5, 2018
fbeba88
removing provider stores stub that was accidentally added at some point
mattsb42-aws Apr 6, 2018
4e4d717
move item transformers out of the internal namespace: they are not go…
mattsb42-aws Apr 6, 2018
6bc9e4b
add EncryptedPaginator support to EncryptedClient to enable scan and …
mattsb42-aws Apr 7, 2018
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
13 changes: 7 additions & 6 deletions doc/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ Modules
dynamodb_encryption_sdk.exceptions
dynamodb_encryption_sdk.identifiers
dynamodb_encryption_sdk.structures
dynamodb_encryption_sdk.delegated_keys
dynamodb_encryption_sdk.delegated_keys.jce
dynamodb_encryption_sdk.encrypted
dynamodb_encryption_sdk.encrypted.client
dynamodb_encryption_sdk.encrypted.item
Expand All @@ -21,29 +23,28 @@ Modules
dynamodb_encryption_sdk.material_providers.aws_kms
dynamodb_encryption_sdk.material_providers.static
dynamodb_encryption_sdk.material_providers.wrapped
dynamodb_encryption_sdk.material_providers.store
dynamodb_encryption_sdk.materials
dynamodb_encryption_sdk.materials.raw
dynamodb_encryption_sdk.materials.wrapped
dynamodb_encryption_sdk.internal
dynamodb_encryption_sdk.internal.defaults
dynamodb_encryption_sdk.internal.dynamodb_types
dynamodb_encryption_sdk.internal.identifiers
dynamodb_encryption_sdk.internal.str_ops
dynamodb_encryption_sdk.internal.utils
dynamodb_encryption_sdk.internal.validators
dynamodb_encryption_sdk.internal.crypto
dynamodb_encryption_sdk.internal.crypto.authentication
dynamodb_encryption_sdk.internal.crypto.encryption
dynamodb_encryption_sdk.internal.crypto.jce_bridge
dynamodb_encryption_sdk.internal.crypto.jce_bridge.authentication
dynamodb_encryption_sdk.internal.crypto.jce_bridge.encryption
dynamodb_encryption_sdk.internal.crypto.jce_bridge.primitives
dynamodb_encryption_sdk.internal.crypto.authentication
dynamodb_encryption_sdk.internal.crypto.encryption
dynamodb_encryption_sdk.internal.formatting
dynamodb_encryption_sdk.internal.formatting.material_description
dynamodb_encryption_sdk.internal.formatting.transform
dynamodb_encryption_sdk.internal.formatting.deserialize
dynamodb_encryption_sdk.internal.formatting.deserialize.attribute
dynamodb_encryption_sdk.internal.formatting.serialize
dynamodb_encryption_sdk.internal.formatting.serialize.attribute
dynamodb_encryption_sdk.internal.formatting.material_description
dynamodb_encryption_sdk.internal.formatting.transform

.. include:: ../CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,4 @@
# 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.
""""""

ENCODING = 'utf-8'
LOGGING_NAME = 'dynamodb_encryption_sdk'
MATERIAL_DESCRIPTION_VERSION = b'\00' * 4
"""Stub module indicator to make linter configuration simpler."""
183 changes: 183 additions & 0 deletions examples/src/aws_kms_encrypted_client.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
# 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.
"""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
from dynamodb_encryption_sdk.structures import AttributeActions


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'}
}
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
}
# Collect all of the attributes that will be encrypted (used later).
encrypted_attributes = set(plaintext_item.keys())
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')
# Add the index pairs to the item.
plaintext_item.update(index_key)

# Create a normal client.
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
}
)
# Use these objects to create an encrypted client.
encrypted_table = 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_table.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']

# Get the item using the encrypted client, transparently decyrpting it.
decrypted_item = encrypted_table.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:
assert encrypted_item[name] != plaintext_item[name]
assert decrypted_item[name] == plaintext_item[name]

# Verify that all of the attributes that should not be encrypted were not.
for name in unencrypted_attributes:
assert decrypted_item[name] == encrypted_item[name] == plaintext_item[name]

# Clean up the item
encrypted_table.delete_item(TableName=table_name, Key=index_key)


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'}
}
]
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
}
plaintext_items = []
for key in index_keys:
_attributes = key.copy()
_attributes.update(plaintext_additional_attributes)
plaintext_items.append(_attributes)

# Collect all of the attributes that will be encrypted (used later).
encrypted_attributes = set(plaintext_additional_attributes.keys())
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')

# Create a normal client.
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
}
)
# Use these objects to create an encrypted client.
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]
})

# Get the encrypted item using the standard client.
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]

def _select_index_from_item(item):
"""Find the index keys that match this item."""
for index in index_keys:
if all([item[key] == value for key, value in index.items()]):
return index

def _select_item_from_index(index, all_items):
"""Find the item that matches these index keys."""
for item in all_items:
if all([item[key] == value for key, value in index.items()]):
return item

for encrypted_item in encrypted_items:
key = _select_index_from_item(encrypted_item)
plaintext_item = _select_item_from_index(key, plaintext_items)
decrypted_item = _select_item_from_index(key, decrypted_items)

# Verify that all of the attributes are different in the encrypted item
for name in encrypted_attributes:
assert encrypted_item[name] != plaintext_item[name]
assert decrypted_item[name] == plaintext_item[name]

# Verify that all of the attributes that should not be encrypted were not.
for name in unencrypted_attributes:
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]
})
101 changes: 101 additions & 0 deletions examples/src/aws_kms_encrypted_item.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
# 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.
"""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
from dynamodb_encryption_sdk.material_providers.aws_kms import AwsKmsCryptographicMaterialsProvider
from dynamodb_encryption_sdk.structures import AttributeActions, EncryptionContext, TableInfo
from dynamodb_encryption_sdk.transform import dict_to_ddb


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
}
plaintext_item = {
'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')
# Collect all of the attributes that will not be encrypted (used later).
unencrypted_attributes = set(index_key.keys())
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)

# Use the TableInfo helper to collect information about the indexes.
table_info = TableInfo(name=table_name)
table_info.refresh_indexed_attributes(table.meta.client)

# Create a crypto materials provider using the specified AWS KMS key.
aws_kms_cmp = AwsKmsCryptographicMaterialsProvider(key_id=aws_cmk_id)

encryption_context = EncryptionContext(
table_name=table_name,
partition_key_name=table_info.primary_index.partition,
sort_key_name=table_info.primary_index.sort,
# The only attributes that are used by the AWS KMS cryptographic materials providers
# 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)
)

# Create attribute actions that tells the encrypted table to encrypt all attributes
# except the primary index attributes and the one identified attribute to ignore.
actions = AttributeActions(
default_action=CryptoAction.ENCRYPT_AND_SIGN,
attribute_actions={
name: CryptoAction.DO_NOTHING
for name in set(['leave me']).union(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
)

# Encrypt the plaintext item directly
encrypted_item = encrypt_python_item(plaintext_item, crypto_config)

# You could now put the encrypted item to DynamoDB just as you would any other item.
# table.put_item(Item=encrypted_item)
# We will skip this for the purposes of this example.

# Decrypt the encrypted item directly
decrypted_item = decrypt_python_item(encrypted_item, crypto_config)

# Verify that all of the attributes are different in the encrypted item
for name in encrypted_attributes:
assert encrypted_item[name] != plaintext_item[name]
assert decrypted_item[name] == plaintext_item[name]

# Verify that all of the attributes that should not be encrypted were not.
for name in unencrypted_attributes:
assert decrypted_item[name] == encrypted_item[name] == plaintext_item[name]
Loading