AWS Developer Tools Blog

Generating Amazon S3 Pre-signed URLs with SSE-C (Part 4)

In Part 3 of this blog, we demonstrated how you can generate and consume pre-signed URLs using SSE-S3. In this blog, I will provide code examples to show how you can generate and consume pre-signed URLs using one of the more advanced options, namely SSE-C (server-side encryption with customer-provided encryption keys). The code samples assume the version of the AWS SDK for Java to be 1.9.31 or later.

Server-Side Encryption with Customer-Provided Encryption Keys (SSE-C)

Here’s how to generate a pre-signed PUT URL using SSE-C:

AmazonS3Client s3 = ...;
String myExistingBucket = ... // an existing bucket
String myKey = ...    // target S3 key
// Generate a pre-signed PUT URL for use with SSE-C
GeneratePresignedUrlRequest genreq = new GeneratePresignedUrlRequest(
    myExistingBucket, myKey, HttpMethod.PUT);
genreq.setSSECustomerKeyAlgorithm(SSEAlgorithm.getDefault());
URL puturl = s3.generatePresignedUrl(genreq);
System.out.println("Presigned PUT URL with SSE-C: " + puturl);

Here’s how to make use of the generated pre-signed PUT URL via the Apache HttpClient (4.3):

File fileToUpload = ...;
SecretKey customerKey = ...;
HttpPut putreq = new HttpPut(URI.create(puturl.toExternalForm()));
// Note it's necessary to specify the customer-provided encryption key 
// when consuming the pre-signed URL
putreq.addHeader(new BasicHeader(
    Headers.SERVER_SIDE_ENCRYPTION_CUSTOMER_ALGORITHM,
    SSEAlgorithm.AES256.getAlgorithm()));
putreq.addHeader(new BasicHeader(
    Headers.SERVER_SIDE_ENCRYPTION_CUSTOMER_KEY, 
    Base64.encodeAsString(customerKey.getEncoded())));
putreq.addHeader(new BasicHeader(
    Headers.SERVER_SIDE_ENCRYPTION_CUSTOMER_KEY_MD5, 
    Md5Utils.md5AsBase64(customerKey.getEncoded())));
putreq.setEntity(new FileEntity(fileToUpload));
CloseableHttpClient httpclient = HttpClients.createDefault();
httpclient.execute(putreq);

Here’s how to generate a pre-signed GET URL for use with SSE-C:

GeneratePresignedUrlRequest genreq = new GeneratePresignedUrlRequest(
    BUCKET, KEY, HttpMethod.GET);
genreq.setSSECustomerKeyAlgorithm(SSEAlgorithm.getDefault());
URL geturl = s3.generatePresignedUrl(genreq);
System.out.println("Presigned GET URL for SSE-C: " + geturl);

Here’s how to make use of the generated pre-signed GET URL via the Apache HttpClient (4.3):


HttpGet getreq = new HttpGet(URI.create(geturl.toExternalForm()));
// Note it's necessary to specify the customer-provided encryption key
// when consuming the pre-signed URL
getreq.addHeader(new BasicHeader(
    Headers.SERVER_SIDE_ENCRYPTION_CUSTOMER_ALGORITHM,
    SSEAlgorithm.AES256.getAlgorithm()));
getreq.addHeader(new BasicHeader(
    Headers.SERVER_SIDE_ENCRYPTION_CUSTOMER_KEY,
    Base64.encodeAsString(customerKey.getEncoded())));
getreq.addHeader(new BasicHeader(
    Headers.SERVER_SIDE_ENCRYPTION_CUSTOMER_KEY_MD5,
    Md5Utils.md5AsBase64(customerKey.getEncoded())));
CloseableHttpClient httpclient = HttpClients.createDefault();
CloseableHttpResponse res = httpclient.execute(getreq);
InputStream is = res.getEntity().getContent();
String actual = IOUtils.toString(is);

In Part 5, the last blog of this series, I will provide code examples that show how to generate and consume pre-signed URLs using SSE-C, but restricting the URLs to be used only with specific customer-provided encryption keys. 

Stay tuned!