Exemplo n.º 1
0
def test_decrypt_python_item():
    key_id = "key"
    key_store = create_in_memory_key_store()
    key_store.create_main_key(key_id)

    plaintext_item = {
        "example": "data",
        "some numbers": 99,
    }

    encrypted_attributes = set(plaintext_item.keys())

    encrypted_item = encrypt_python_item(
        item=plaintext_item,
        key_id=key_id,
        key_store=key_store,
        encryption_context=EncryptionContext(),
        attribute_actions=AttributeActions(),
    )

    decrypted_item = decrypt_python_item(
        item=encrypted_item,
        key_store=key_store,
        encryption_context=EncryptionContext(),
        attribute_actions=AttributeActions(),
    )

    for name in encrypted_attributes:
        assert encrypted_item[name] != plaintext_item[name]
        assert decrypted_item[name] == plaintext_item[name]
def test_no_decryption_key_but_decryption_requested(actions,
                                                    parametrized_item):
    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))
    decrypting_cmp = StaticCryptographicMaterialsProvider(
        decryption_materials=RawDecryptionMaterials(
            verification_key=signing_key))

    encrypted_item = encrypt_python_item(
        parametrized_item,
        CryptoConfig(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),
        )

    excinfo.match(
        "Attribute actions ask for some attributes to be decrypted but no decryption key is available"
    )
Exemplo n.º 3
0
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
    )
    crypto_config = CryptoConfig(
        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':
            continue
        assert decrypted_item[key] == plaintext_item[key]
Exemplo n.º 4
0
    def _decrypt_dynamodb_response(self, response):
        ec_kwargs = self._table_info.encryption_context_values
        if self._table_info.primary_index is not None:
            ec_kwargs.update({
                "partition_key_name":
                self._table_info.primary_index.partition,
                "sort_key_name":
                self._table_info.primary_index.sort,
            })

        self._attribute_actions.set_index_keys(
            *self._table_info.protected_index_keys())

        encryption_context = EncryptionContext(**ec_kwargs)

        def decrypt(items):
            for item in items:
                try:
                    decrypted_item = decrypt_python_item(
                        item=item,
                        key_store=self._key_store,
                        encryption_context=encryption_context,
                        attribute_actions=self._attribute_actions,
                    )
                    yield decrypted_item
                except Exception:  # TODO
                    pass

        response["Items"] = list(decrypt(response["Items"]))
        response["Count"] = len(response["Items"])

        return response
Exemplo n.º 5
0
def test_no_materials(method, message):
    empty_cmp = StaticCryptographicMaterialsProvider()

    with pytest.raises(AttributeError) as excinfo:
        getattr(empty_cmp, method)(EncryptionContext())

    excinfo.match(message)
Exemplo n.º 6
0
class CryptoItems:
    with open('aws') as v:
        aws_access_key_id = str(v.readline().strip())
        aws_secret_access_key = str(v.readline().strip())

    dbResource = boto3.resource('dynamodb',
                                aws_access_key_id=aws_access_key_id,
                                aws_secret_access_key=aws_secret_access_key,
                                region_name='us-east-1').Table('Users')

    # crypto key and material provider
    aws_cmk_id = 'arn:aws:kms:us-east-1:910140038075:key/353f6f4c-0d0b-47b1-99fc-3aeec929b973'
    aws_kms_cmp = AwsKmsCryptographicMaterialsProvider(key_id=aws_cmk_id)

    # how the crypto is applied to attributes
    crypto_actions = AttributeActions(
        default_action=CryptoAction.DO_NOTHING,
        attribute_actions={'password': CryptoAction.ENCRYPT_AND_SIGN})

    crypto_context = EncryptionContext(table_name='Users')

    custom_crypto_config = CryptoConfig(materials_provider=aws_kms_cmp,
                                        attribute_actions=crypto_actions,
                                        encryption_context=crypto_context)

    encrypted_resource = EncryptedTable(table=dbResource,
                                        materials_provider=aws_kms_cmp,
                                        attribute_actions=crypto_actions)
def _item_cycle_check(materials_provider, attribute_actions, item):
    crypto_config = CryptoConfig(
        materials_provider=materials_provider,
        encryption_context=EncryptionContext(),
        attribute_actions=attribute_actions,
    )
    cycle_item_check(item, crypto_config)
Exemplo n.º 8
0
    def get_main_key(self, key_id: str) -> MainKey:
        index_key = {"key_id": key_id}

        encryption_context = EncryptionContext(
            table_name=self._table_name,
            partition_key_name="key_id",
            attributes=dict_to_ddb(index_key),
        )
        crypto_config = CryptoConfig(
            materials_provider=self._materials_provider,
            encryption_context=encryption_context,
            attribute_actions=self._actions,
        )

        encrypted_item = self._get_item(key_id=key_id)

        if encrypted_item["restricted"]:
            raise Exception("Access restricted.")

        decrypted_item = decrypt_python_item(encrypted_item, crypto_config)

        return MainKey(
            key_id=key_id,
            key_bytes=decrypted_item["key"].value,
        )
Exemplo n.º 9
0
    def create_main_key(self, key_id: str, key_length=256, key_bytes=None) -> MainKey:
        index_key = {"key_id": key_id}

        if key_bytes is None:
            key_bytes = self._key_bytes_generator(key_length)

        plaintext_item = {
            "restricted": False,
            "on_hold": False,
            "key": key_bytes,
        }
        plaintext_item.update(index_key)

        encryption_context = EncryptionContext(
            table_name=self._table_name,
            partition_key_name="key_id",
            attributes=dict_to_ddb(index_key),
        )
        crypto_config = CryptoConfig(
            materials_provider=self._materials_provider,
            encryption_context=encryption_context,
            attribute_actions=self._actions,
        )
        encrypted_item = encrypt_python_item(plaintext_item, crypto_config)

        self._put_item(key_id=key_id, encrypted_item=encrypted_item)

        return MainKey(
            key_id=key_id,
            key_bytes=key_bytes,
        )
Exemplo n.º 10
0
def test_aws_kms_item_cycle(all_aws_kms_cmp_builders, parametrized_actions,
                            parametrized_item):
    crypto_config = CryptoConfig(
        materials_provider=all_aws_kms_cmp_builders(),
        encryption_context=EncryptionContext(),
        attribute_actions=parametrized_actions,
    )
    functional_test_utils.cycle_item_check(parametrized_item, crypto_config)
Exemplo n.º 11
0
def test_no_materials(method, error_type, message):
    empty_cmp = WrappedCryptographicMaterialsProvider(signing_key=MagicMock(
        __class__=DelegatedKey))

    with pytest.raises(error_type) as excinfo:
        getattr(empty_cmp, method)(EncryptionContext())

    excinfo.match(message)
Exemplo n.º 12
0
def test_aws_kms_item_cycle_hypothesis_veryslow(all_aws_kms_cmp_builders,
                                                hypothesis_actions, item):
    crypto_config = CryptoConfig(
        materials_provider=all_aws_kms_cmp_builders(),
        encryption_context=EncryptionContext(),
        attribute_actions=hypothesis_actions,
    )
    functional_test_utils.cycle_item_check(item, crypto_config)
def test_decryption_materials(default_kms_cmp, patch_decrypt_initial_material):
    material_description = {"some": "data"}
    encryption_context = EncryptionContext(material_description=material_description)
    test = default_kms_cmp.decryption_materials(encryption_context)

    assert test.verification_key == _DELEGATED_KEYS["signing"]
    assert test.decryption_key == _DELEGATED_KEYS["encryption"]
    assert test.material_description == material_description
def test_generate_initial_material_fail(default_kms_cmp, patch_kms_client):
    default_kms_cmp._key_id = _KEY_ID
    patch_kms_client.return_value.generate_data_key.side_effect = botocore.exceptions.ClientError({}, "")

    with pytest.raises(WrappingError) as excinfo:
        default_kms_cmp._generate_initial_material(EncryptionContext())

    excinfo.match("Failed to generate materials using AWS KMS")
def test_decrypt_initial_material(default_kms_cmp, patch_kms_client):
    default_kms_cmp._key_id = _KEY_ID

    test = default_kms_cmp._decrypt_initial_material(
        EncryptionContext(material_description=_DEFAULT_ADDITIONAL_MATERIAL_DESCRIPTION)
    )

    assert test == _DERIVED_KEYS["initial_material"]
def test_with_item(wrapped_cmp):
    config = CryptoConfig(materials_provider=wrapped_cmp,
                          encryption_context=EncryptionContext(attributes={}),
                          attribute_actions=AttributeActions())
    item = {'test': 'item', 'with': 'some data'}
    new_config = config.with_item(item)

    assert config.encryption_context.attributes == {}
    assert new_config.encryption_context.attributes == item
def test_decryption_materials(default_kms_cmp, patch_decrypt_initial_material):
    material_description = {'some': 'data'}
    encryption_context = EncryptionContext(
        material_description=material_description)
    test = default_kms_cmp.decryption_materials(encryption_context)

    assert test.verification_key == _DELEGATED_KEYS['signing']
    assert test.decryption_key == _DELEGATED_KEYS['encryption']
    assert test.material_description == material_description
def test_encryption_context_repr(operator):
    value = EncryptionContext(
        attributes={"unique_name": {
            "S": "unique_value"
        }})

    test = operator(value)

    assert "unique_name" not in test
    assert "unique_value" not in test
def test_encryption_materials(default_kms_cmp, patch_generate_initial_material):
    material_description = {"some": "data"}
    encryption_context = EncryptionContext(material_description=material_description)
    test = default_kms_cmp.encryption_materials(encryption_context)

    expected_material_description = material_description.copy()
    expected_material_description.update(_DEFAULT_ADDITIONAL_MATERIAL_DESCRIPTION)
    assert test.signing_key == _DELEGATED_KEYS["signing"]
    assert test.encryption_key == _DELEGATED_KEYS["encryption"]
    assert test.material_description == expected_material_description
def test_decrypt_initial_material_fail(default_kms_cmp, patch_kms_client):
    default_kms_cmp._key_id = _KEY_ID
    patch_kms_client.return_value.decrypt.side_effect = botocore.exceptions.ClientError({}, "")

    with pytest.raises(UnwrappingError) as excinfo:
        default_kms_cmp._decrypt_initial_material(
            EncryptionContext(material_description=_DEFAULT_ADDITIONAL_MATERIAL_DESCRIPTION)
        )

    excinfo.match("Failed to unwrap AWS KMS protected materials")
def test_with_item(wrapped_cmp):
    config = CryptoConfig(
        materials_provider=wrapped_cmp,
        encryption_context=EncryptionContext(attributes={}),
        attribute_actions=AttributeActions(),
    )
    item = {"test": "item", "with": "some data"}
    new_config = config.with_item(item)

    assert config.encryption_context.attributes == {}
    assert new_config.encryption_context.attributes == item
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))
    crypto_config = CryptoConfig(
        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")
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)),
        attribute_actions=AttributeActions(attribute_actions={
            key: CryptoAction.SIGN_ONLY
            for key in _primary_key_names
        }))
    functional_test_utils.cycle_item_check(item, crypto_config)
def test_valid_materials(mocker, method):
    mocker.patch.object(WrappedCryptographicMaterialsProvider,
                        '_build_materials')

    cmp = WrappedCryptographicMaterialsProvider(
        signing_key=MagicMock(__class__=DelegatedKey),
        wrapping_key=MagicMock(__class__=DelegatedKey),
        unwrapping_key=MagicMock(__class__=DelegatedKey))

    context = EncryptionContext()
    test = getattr(cmp, method)(context)

    WrappedCryptographicMaterialsProvider._build_materials.assert_called_once_with(
        context)
    assert test is WrappedCryptographicMaterialsProvider._build_materials.return_value
def test_only_sign_item(parametrized_item):
    signing_key = JceNameLocalDelegatedKey.generate("HmacSHA256", 256)
    cmp = StaticCryptographicMaterialsProvider(
        encryption_materials=RawEncryptionMaterials(signing_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
    )

    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

    decrypt_python_item(signed_item, crypto_config)
def _item_check(materials_provider, table_name, table_index, ciphertext_item, plaintext_item, attribute_actions):
    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,
    )
    crypto_config = CryptoConfig(
        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":
            continue
        assert decrypted_item[key] == plaintext_item[key]
Exemplo n.º 27
0
def crypto_config_from_table_info(materials_provider, attribute_actions,
                                  table_info):
    """Build a crypto config from the provided values and table info.

    :returns: crypto config and updated kwargs
    :rtype: tuple(CryptoConfig, dict)
    """
    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
        })

    return CryptoConfig(materials_provider=materials_provider,
                        encryption_context=EncryptionContext(**ec_kwargs),
                        attribute_actions=attribute_actions)
def test_build_materials(mocker):
    mocker.patch.object(dynamodb_encryption_sdk.material_providers.wrapped,
                        'WrappedCryptographicMaterials')

    cmp = WrappedCryptographicMaterialsProvider(
        signing_key=MagicMock(__class__=DelegatedKey),
        wrapping_key=MagicMock(__class__=DelegatedKey),
        unwrapping_key=MagicMock(__class__=DelegatedKey))

    material_description = {'some': 'data'}
    context = EncryptionContext(material_description=material_description)
    test = cmp._build_materials(context)

    dynamodb_encryption_sdk.material_providers.wrapped.WrappedCryptographicMaterials.assert_called_once_with(
        wrapping_key=cmp._wrapping_key,
        unwrapping_key=cmp._unwrapping_key,
        signing_key=cmp._signing_key,
        material_description=material_description)
    assert test is dynamodb_encryption_sdk.material_providers.wrapped.WrappedCryptographicMaterials.return_value
def static_cmp_crypto_config():
    return CryptoConfig(
        materials_provider=build_static_jce_cmp("AES", 256, "HmacSHA256", 256),
        encryption_context=EncryptionContext(),
        attribute_actions=AttributeActions(),
    )
def test_generate_initial_material(default_kms_cmp, patch_kms_client):
    default_kms_cmp._key_id = _KEY_ID

    test = default_kms_cmp._generate_initial_material(EncryptionContext())
    assert test == (_DERIVED_KEYS["initial_material"], _DERIVED_KEYS["encrypted_initial_material"])