Decrypt and decode an s3 object without x-amz-unencrypted-content-length

Viewed 12

I need to decrypt a s3 object without the x-amz-unencrypted-content-length key. Looking at the (javasdk) specs, this key is optional.

I have no problem decrypting the object to bytes using the following function, when x-amz-unencrypted-content-length is set; but when it isn't I don't know the length of the object, I can't trim the trailing, non original characters.

This causes .decode("utf-8") to throw unrecognized character errors, like:

UnicodeDecodeError 'utf-8' codec can't decode byte 0xe2 in position 39259: invalid continuation byte

How can I decode the bytes to string without the x-amz-unencrypted-content-length key?

def decrypt_bucket_object(obj):
    """
    Decrypt an email object from an s3 bucket
    """
    # Inspired by this guide: https://medium.com/@samnco/reading-aws-ses-encrypted-emails-with-boto3-9c177f8ba130
    metadata = obj["Metadata"]
    original_size = int(metadata["x-amz-unencrypted-content-length"])
    envelope_key = base64.b64decode(metadata["x-amz-key-v2"])
    envelope_iv = base64.b64decode(metadata["x-amz-iv"])
    enc_ctx = json.loads(metadata["x-amz-matdesc"])

    # Decrypt the envelope key.
    plain_envelope_key = kms.decrypt(
        CiphertextBlob=envelope_key, EncryptionContext=enc_ctx
    )

    aes = AES.new(plain_envelope_key["Plaintext"], AES.MODE_GCM, nonce=envelope_iv)

    # Decrypt the message to bytes string
    bytes = aes.decrypt(obj["Body"].read())[:original_size]
    # Decode
    return bytes.decode("utf-8")
0 Answers
Related