Darwesh Darwesh - 4 months ago 32x
Python Question

What is the right way to create a SSECustomerKey for boto3 file encryption in python?

I am using boto3 with my django application to upload media to S3. But I am having trouble encrypting the files on server using "Server Side Encryption using Customer Provided Encryption Keys"

I'm using boto3's object.put() api to upload files and specify the encryption keys. But I am getting the following error.

"The calculated MD5 hash of the key did not match the hash that was

I am not sure on how to create the md5 of the key that will match on the server side. here is my code.

password = "32characterslongpassphraseneeded".encode('utf-8')
encryption_key = hashlib.md5(password).hexdigest()
encryption_key_md5 = hashlib.md5(encryption_key.encode('utf-8')).hexdigest()
import boto3
s3 = boto3.resource('s3')
key = s3.Object(bucket_name, key_name)
kwargs = {
'SSECustomerAlgorithm': 'AES256',
'SSECustomerKey': encryption_key,
'SSECustomerKeyMD5': encryption_key_md5,
'ContentType': file_obj.content_type,
'Body': file_obj,


I am utilizing the same s3 api through a php client and it works fine.

$customerKey = md5($name);
'Bucket' => S3_BUCKET,
'Key' => "scope/{$name}",
'Body' => fopen($tmp_file_path, 'rb'),
'ACL' => S3_ACL,
'SSECustomerAlgorithm' => 'AES256',
'SSECustomerKey' => $customerKey,
'SSECustomerKeyMD5' => md5($customerKey ,true),

The only difference I see here is that php's md5 method can take second argument which, if true, returns and 16 character long digest as compared to normal 32 character long digest. Now I don't know how to create a 16 character long digest using hashlib.md5.


The right way to do is to use os.urandom

import os
secret_key = os.urandom(32) # The key needs to be 32 character long.

and one doesn't need to provide SSECustomerKeyMD5 as boto3 calculates it for you.

and also SSE-C doesn't work right in key.put, as for now, I don't know for what reasons. One has to do it this way.

s3 = boto3.client('s3')