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