def _serialize_deserialize_cycle(material_description):
    serialized_material_description = serialize_material_description(
        material_description)
    deserialized_material_description = deserialize_material_description(
        serialized_material_description)
    assert deserialized_material_description == material_description
def test_deserialize_material_description(material_description, serialized):
    deserialized_material_description = deserialize_material_description(
        serialized)
    assert deserialized_material_description == 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)

    exc_info.match(expected_message)
Example #4
0
def decrypt_dynamodb_item(item, crypto_config):
    # type: (dynamodb_types.ITEM, CryptoConfig) -> dynamodb_types.ITEM
    """Decrypt a DynamoDB item.

    >>> from dynamodb_encryption_sdk.encrypted.item import decrypt_python_item
    >>> encrypted_item = {
    ...     'some': {'B': b'ENCRYPTED_DATA'},
    ...     'more': {'B': b'ENCRYPTED_DATA'}
    ... }
    >>> decrypted_item = decrypt_python_item(
    ...     item=encrypted_item,
    ...     crypto_config=my_crypto_config
    ... )

    .. note::

        This handles DynamoDB-formatted items and is for use with the boto3 DynamoDB client.

    :param dict item: Encrypted and signed DynamoDB item
    :param CryptoConfig crypto_config: Cryptographic configuration
    :returns: Plaintext DynamoDB item
    :rtype: dict
    """
    unique_actions = set([crypto_config.attribute_actions.default_action.name])
    unique_actions.update(
        set([
            action.name for action in
            crypto_config.attribute_actions.attribute_actions.values()
        ]))

    if crypto_config.attribute_actions.take_no_actions:
        # If we explicitly have been told not to do anything to this item, just copy it.
        return item.copy()

    try:
        signature_attribute = item.pop(ReservedAttributes.SIGNATURE.value)
    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")

    inner_crypto_config = crypto_config.copy()
    # Retrieve the material description from the item if found.
    try:
        material_description_attribute = item.pop(
            ReservedAttributes.MATERIAL_DESCRIPTION.value)
    except KeyError:
        # If no material description is found, we use inner_crypto_config as-is.
        pass
    else:
        # If material description is found, override the material description in inner_crypto_config.
        material_description = deserialize_material_description(
            material_description_attribute)
        inner_crypto_config.encryption_context.material_description = material_description

    decryption_materials = inner_crypto_config.decryption_materials()

    verify_item_signature(signature_attribute, item,
                          decryption_materials.verification_key,
                          inner_crypto_config)

    try:
        decryption_key = decryption_materials.decryption_key
    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"
            )

        return item.copy()

    decryption_mode = inner_crypto_config.encryption_context.material_description.get(
        MaterialDescriptionKeys.ATTRIBUTE_ENCRYPTION_MODE.value)
    algorithm_descriptor = decryption_key.algorithm + decryption_mode

    # Once the signature has been verified, actually decrypt the item attributes.
    decrypted_item = {}
    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)
        else:
            decrypted_item[name] = attribute.copy()

    return decrypted_item