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