1
votes

I am attempting to upload an object to S3 using the customer provided encryption key. http://docs.aws.amazon.com/AmazonS3/latest/dev/ServerSideEncryptionCustomerKeys.html

My code looks like:

$this->s3->putObject(array(
  'Bucket' => $this->bucket,
  'Key' => "$filename",
  'Body' => $resource,
  'ACL' => 'private',
  'SSECustomerAlgorithm' => 'AES256',
  'SSECustomerKey' => base64_encode('48wk86271sDb23pY23zT5rZJ7q55R7eE'),
  'SSECustomerKeyMD5'=> base64_encode(md5('48wk86271sDb23pY23zT5rZJ7q55R7eE'))
));

The error I am getting says:

AWS Error Message: The calculated MD5 hash of the key did not match the hash that was provided

What am I doing wrong? My key 48wk86271sDb23pY23zT5rZJ7q55R7eE is 256 bits. I've also tried using base64_encode(md5(key, true)).

1
You say you also tried md5(key,true) but did you try base64_encode(md5(key,true)) ...? - Michael - sqlbot
@Michael-sqlbot Yes sir - user1893702
I think my issue is that my key is not actually 256 bit. I will attempt to use openssl_random_pseudo_byte to generate 256 bit, and I suspect that it will output 64 hex string - user1893702
Actually, I suspect that your key is 256 bits until you base_64 encode it, at which point it will be more. I have coded extensively against the REST API but am generally unfamiliar with the PHP SDK... rethinking, now, I suspect your error is base_64 encoding either of those values. The SDK probably handles that for you, in which case, you're double-encoding. Try SSECustomerKey => 'raw key string with 32 chars', SSECustomerKeyMD5 => md5(key,true). The "true" as I understand it returns the binary md5, not hex, which is probably what you need here, since docs mention 128 bits for the md5. - Michael - sqlbot

1 Answers

2
votes

The REST API documentation specifies that both the customer key and customer key MD5 be sent base-64 encoded...

x-amz-server-side​-encryption​-customer-key

Use this header to provide the 256-bit, base64-encoded encryption key for Amazon S3 to use to encrypt or decrypt your data.

x-amz-server-side​-encryption​-customer-key-MD5

Use this header to provide the base64-encoded 128-bit MD5 digest of the encryption key according to RFC 1321. Amazon S3 uses this header for a message integrity check to ensure the encryption key was transmitted without error.

...however, the PHP SDK handles both encoding steps for you, so the arguments should be passed without any encoding.

'SSECustomerAlgorithm' => 'AES256',
'SSECustomerKey'       => 'key_=_string_of_exactly_32_bytes',
'SSECustomerKeyMD5'    => md5('key_=_string_of_exactly_32_bytes',true),

Of course, you'd probably want that 32 byte key string in a variable rather than copypasting the same literal string in the code twice. The second argument "true" to md5() specifies that the binary md5 hash is to be returned, as expected by the SDK, instead of the hex-encoded variant that would be returned by default.

Remember that when using customer-provided encryption keys, if you lose the key, you lose the data. S3 does not store the key, and without the key, fetching the stored object is not possible.