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_serialize_material_description(material_description, serialized):
    serialized_material_description = serialize_material_description(
        material_description)
    assert serialized_material_description == serialized
def test_serialize_material_description_errors(data, expected_type,
                                               expected_message):
    with pytest.raises(expected_type) as exc_info:
        serialize_material_description(data)

    exc_info.match(expected_message)
Esempio n. 4
0
def encrypt_dynamodb_item(item, crypto_config):
    # type: (dynamodb_types.ITEM, CryptoConfig) -> dynamodb_types.ITEM
    """Encrypt a DynamoDB item.

    >>> from dynamodb_encryption_sdk.encrypted.item import encrypt_dynamodb_item
    >>> plaintext_item = {
    ...     'some': {'S': 'data'},
    ...     'more': {'N': '5'}
    ... }
    >>> encrypted_item = encrypt_dynamodb_item(
    ...     item=plaintext_item,
    ...     crypto_config=my_crypto_config
    ... )

    .. note::

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

    :param dict item: Plaintext DynamoDB item
    :param CryptoConfig crypto_config: Cryptographic configuration
    :returns: Encrypted and signed DynamoDB item
    :rtype: dict
    """
    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()

    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))

    encryption_materials = crypto_config.encryption_materials()

    inner_material_description = encryption_materials.material_description.copy(
    )
    try:
        encryption_materials.encryption_key
    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"
            )

        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

        algorithm_descriptor = encryption_materials.encryption_key.algorithm + encryption_mode

        encrypted_item = {}
        for name, attribute in item.items():
            if crypto_config.attribute_actions.action(
                    name) is CryptoAction.ENCRYPT_AND_SIGN:
                encrypted_item[name] = encrypt_attribute(
                    attribute_name=name,
                    attribute=attribute,
                    encryption_key=encryption_materials.encryption_key,
                    algorithm=algorithm_descriptor,
                )
            else:
                encrypted_item[name] = attribute.copy()

    signature_attribute = sign_item(encrypted_item,
                                    encryption_materials.signing_key,
                                    crypto_config)
    encrypted_item[ReservedAttributes.SIGNATURE.value] = signature_attribute

    try:
        # Add the signing key algorithm identifier to the inner material description if provided
        inner_material_description[
            MaterialDescriptionKeys.SIGNING_KEY_ALGORITHM.
            value] = encryption_materials.signing_key.signing_algorithm()
    except NotImplementedError:
        # Not all signing keys will provide this value
        pass

    material_description_attribute = serialize_material_description(
        inner_material_description)
    encrypted_item[ReservedAttributes.MATERIAL_DESCRIPTION.
                   value] = material_description_attribute

    return encrypted_item