AWS Developer Tools Blog

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

In the previous blog (Part 4), we demonstrated how you can generate and consume pre-signed URLs using SSE-C. In this last and final blog of the 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.

As indicated in Part 1 of this blog, a prerequisite to this option is that you must use Signature Version 4 (SigV4). You can enable SigV4 in the AWS SDK for Java in various ways, including using S3-specific system properties, or programmatically as demonstrated previously. Here, the code examples will assume you have enabled SigV4.

SSE-C with specific Customer-Provided Encryption Keys

Here’s how to generate a pre-signed PUT URL using SSE-C (with specific customer-provided encryption keys):

String myExistingBucket = ... // an existing bucket
String myKey = ...    // target S3 key
SecretKey customerKey = ...;
GeneratePresignedUrlRequest genreq = new GeneratePresignedUrlRequest(
    myExistingBucket, myKey, HttpMethod.PUT);
// Restrict the pre-signed PUT URL to be used only against
// a specific customer-provided encryption key
genreq.setSSECustomerKey(new SSECustomerKey(customerKey));
// Note s3 must have been configured to use SigV4
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()));
// 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 (with specific customer-provided encryption keys):

GeneratePresignedUrlRequest genreq = new GeneratePresignedUrlRequest(
    BUCKET, KEY, HttpMethod.GET);
// Restrict the pre-signed GET URL to be used only against
// a specific customer-provided encryption key
genreq.setSSECustomerKey(new SSECustomerKey(customerKey));
// Note s3 must have been configured to use SigV4
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()));
// 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 summary, we have shown how you can generate and consume pre-signed URLs using SSE-C with specific customer-provided encryption keys.

We hope you find this blog series on generating pre-signed URLs with SSE useful. We would be very interested to hear about how you make use of this feature in your applications. Please feel free to drop us some comments.

Ciao for now!