Document usage for CloudFront Field-Level Encrypted (FLE) decryption
anna-shcherbak opened this issue · 1 comments
I was looking for a Python code example to decrypt CloudFront Field-Level Encrypted (FLE) data and I haven't found any.
In my use case, encrypted data is stored in DynamoDB, and a private key is stored in the SSM parameter.
The only example I found is fle_decrypt_data.py from 2017 that comes with a detailed article How to Enhance the Security of Sensitive Customer Data by Using Amazon CloudFront Field-Level Encryption. This code doesn't work even after changing outdated lib Crypto to Cryptodome.
The official documentation Decrypt data fields at your origin provides an example for Java, but not for Python.
I have already communicated with the AWS Support team, they also checked the GitHub and Python example code reference and were unable to find an example of the code.
They advised me to get in touch with the Encryption SDK Python team.
I attempted to use a Python script generated by ChatGPT, but it does not work. The error message I receive is:
Ciphertext length must be equal to key size.
I understand that CloudFront adds padding with the provider name and private key, but it is unclear how to correctly handle this during decryption.
import json
import boto3
import base64
import os
from cryptography.hazmat.primitives.asymmetric import rsa, padding
from cryptography.hazmat.primitives import serialization, hashes
table_name = os.environ.get('DYNAMODB_TABLE')
dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table(table_name)
ssm = boto3.client('ssm')
def get_private_key_from_ssm(parameter_name):
"""Retrieve and deserialize the private key from SSM Parameter Store."""
response = ssm.get_parameter(Name=parameter_name, WithDecryption=True) # Fetch parameter
private_key_pem = response['Parameter']['Value'] # Extract the value
print(f"Private key PEM: {private_key_pem}")
# Deserialize the PEM-encoded private key
return serialization.load_pem_private_key(
private_key_pem.encode('utf-8'), # Ensure encoding matches
password=None # Provide password if necessary
)
private_key = get_private_key_from_ssm(os.environ.get('PARAMETER_NAME_WITH_PRIVATE_KEY'))
print(f"Private key PEM: {private_key}")
def decrypt_card_number(encrypted_card_number):
"""Decrypt card number using RSA private key"""
try:
encrypted_bytes = base64.b64decode(encrypted_card_number)
print(f"Base64 Decoded Bytes: {encrypted_bytes}")
print(f"Decoded Length: {len(encrypted_bytes)} bytes")
decrypted_bytes = private_key.decrypt(
encrypted_bytes,
padding.OAEP(
mgf=padding.MGF1(algorithm=hashes.SHA256()),
algorithm=hashes.SHA256(),
label=None,
),
)
return decrypted_bytes.decode("utf-8")
except ValueError as e:
print(f"Decryption error: {e}")
return "Decryption Failed"
except Exception as e:
print(f"Unexpected error: {e}")
return "Invalid Data"
def lambda_handler(event, context):
response = table.scan()
records = response.get('Items', [])
for record in records:
if 'encryptedCardNumber' in record:
# Decrypt and add the decrypted card number to the record
print(f"Decrypting card number for {record['customerName']}: {record['encryptedCardNumber']}")
decrypted_card_number = decrypt_card_number(record["encryptedCardNumber"])
record["cardNumber"] = decrypted_card_number # Add decrypted
return {
"statusCode": 200,
"body": json.dumps(records)
}Could you provide a Python code example demonstrating the correct way to decrypt FLE data using the appropriate RSA-OAEP padding and key handling?