0

It is a bit strange to me this isn't a commonly discussed topic yet but I am working with an AWS S3 storage server trying to implement server-side encryption using the option of a client provided key (SSE-C).

More Information Here: http://docs.aws.amazon.com/AmazonS3/latest/dev/ServerSideEncryptionCustomerKeys.html

I have the encryption method working great when attempting to use the AWS Key Management Service (KMS). The issue I personally have is I want to hold the keys, thus leading me to want the SSE-C method.

Documentation for PHP (for whatever reason) is scarce under this subject but I have managed to get it working using the seemingly most recent composer build of version3 for S3.

My connection code and put object to the system is as follows. Files are properly uploaded to the system. Code is as follows:

//connect is successful
$client = Aws\S3\S3Client::factory([
    'version' => "2006-03-01",
    'region' => "us-west-1",
    'credentials' => [
        'key'    => "mykey",
        'secret' => "mysecret"
    ]
]);


//upload is successful
$somerandom32bitkey="48wk86271sDb23pY23zT5rZJ7q55R7eE";
$result = $client->putObject([
                'Bucket' => 'mybucketname',
                'Key'    => 'myfilename',
                'Body'   => 'some body of the file',
                'SSECustomerAlgorithm' => 'AES256',               
                'SSECustomerKey'       => $somerandom32bitkey,
                'SSECustomerKeyMD5'    => md5($somerandom32bitkey,true),
            ]);

My issue arises when attempting to get a pre-signed url. I cannot seem to find any documentation on how to actually do this part which is pretty important. The code is as follows:

$somerandom32bitkey="48wk86271sDb23pY23zT5rZJ7q55R7eE";
    $cmd = $client->getCommand('GetObject', array(
                    'Bucket' => 'mybucketname',
                    'Key'    => 'myfilename',
                    'SSECustomerAlgorithm' => 'AES256',               
                    'SSECustomerKey'       => $somerandom32bitkey,
                    'SSECustomerKeyMD5'    => md5($somerandom32bitkey,true),
                ));

    $request = $client->createPresignedRequest($cmd, '+10 minutes');
    $presignedUrl = (string) $request->getUri();

The link generated looks like this:

https://s3-us-west-1.amazonaws.com/mybucketname/test.txt?x-amz-server-side-encryption-customer-algorithm=AES256&x-amz-server-side-encryption-customer-key=NDh3azg2Mjcxc0RiMjNwWTIzelQ1clpKN3E1NVI3ZUU%3D&x-amz-server-side-encryption-customer-key-MD5=sJFeofwx%2FqqLd0B4Gc0TKA%3D%3D&X-Amz-Content-Sha256=e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIQZMPABWF7ZC57ZQ%2F20160120%2Fus-west-1%2Fs3%2Faws4_request&X-Amz-Date=20160120T040211Z&X-Amz-SignedHeaders=Host&X-Amz-Expires=600&X-Amz-Signature=91178da69e049fdc43a2d496f9533e4e1295db89b651010224e6610cf8e4443c

The result response via AWS is:

<Error>
<Code>InvalidArgument</Code>
<Message>
Requests specifying Server Side Encryption with Customer provided keys must provide an appropriate secret key.
</Message>
<ArgumentName>x-amz-server-side-encryption</ArgumentName>
<ArgumentValue>null</ArgumentValue>
<RequestId>933237342E36A1D1</RequestId>
<HostId>
3XmQM+IEGdZUZ5GUnSpTpatksKIN2zb3pCiu8D7Btm09nLxKkfEAkfY8a8T8kcB3lW1p38ic3ZE=
</HostId>
</Error>

The interesting part is it is looking for a parameter of: 'ServerSideEncryption' => 'AES256' but this is only a parameter required when using the AWS managed key system (SSE-KMS) http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingKMSEncryption.html

Any ideas here?

1

As per official documentation there is three request header require for SSE with customer provided key:

  1. x-amz-server-side​-encryption​-customer-algorithm : AES256
  2. x-amz-server-side​-encryption​-customer-key : base64(secretkey)
  3. x-amz-server-side​-encryption​-customer-key-MD5 : base64(md5(secret key))

Please update code as per above

  1. 'SSECustomerAlgorithm' => 'AES256',
  2. 'SSECustomerKey' => base64($somerandom32bitkey)
  3. 'SSECustomerKeyMD5 => md5(base64($somerandom32bitkey))

Hope this will help.

  • The important item is that you have to included these headers when you use the Presigned URL. This also means that you have to provide the encryption key to the user / application that will be using the Presigned URL. – John Hanley May 2 '18 at 19:58
  • samuelabiodun.com/… – Samuel James Sep 18 '18 at 21:44

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.