AWS Developer Blog

Amazon S3 Encryption with AWS Key Management Service

by Hanson Char | on | in Java | Permalink | Comments |  Share

With version 1.9.5 of the AWS SDK for Java, we are excited to announce the full support of S3 object encryption using AWS Key Management Service (KMS). Why KMS, you may ask? In a nutshell, AWS Key Management Service provides many security and administrative benefits, including centralized key management, better security in protecting your master keys, and it leads to simpler code!

In this blog, we will provide two quick examples of how you can make use of AWS KMS for client-side encryption via Amazon S3 Encryption Client, and compare it with the use of AWS KMS for server-side encryption via Amazon S3 Client.

The first example demonstrates how you can make use of KMS for client-side encryption in the Amazon S3 Encryption Client. As you see, it can be as simple as configuring a KMSEncryptionMaterialsProvider with a KMS Customer Master Key ID (generated a-priori, for example, via the AWS management console). Every object put to Amazon S3 would then result in a data key generated by AWS KMS for use in client-side encryption before sending the data (along with other metadata such as the KMS "wrapped" data key) to S3 for storage. During retrieval, KMS would automatically "unwrap" the encrypted data key, and the Amazon S3 Encryption Client would then use it to decrypt the ciphertext locally on the client side.

S3 client-side encryption using AWS KMS

String customerMasterKeyId = ...;
AmazonS3EncryptionClient s3 = new AmazonS3EncryptionClient(
            new ProfileCredentialsProvider(),
            new KMSEncryptionMaterialsProvider(customerMasterKeyId))
        .withRegion(Region.getRegion(Regions.US_EAST_1));

String bucket = ...;
byte[] plaintext = "Hello S3/KMS Client-side Encryption!"
            .getBytes(Charset.forName("UTF-8"));
ObjectMetadata metadata = new ObjectMetadata();
metadata.setContentLength(plaintext.length);

PutObjectResult putResult = s3.putObject(bucket, "hello_s3_kms.txt",
        new ByteArrayInputStream(plaintext), metadata);
System.out.println(putResult);

S3Object s3object = s3.getObject(bucket, "hello_s3_kms.txt");
System.out.println(IOUtils.toString(s3object.getObjectContent()));
s3.shutdown();

The second example demonstrates how you can delegate the crypto operations entirely to the Amazon S3 server side, yet using fully managed data keys generated by AWS KMS (instead of having the data key locally generated on the client side). This has the obvious benefit of offloading the computationally expensive operations to the server side, and potentially improving the client-side performance. Similar to what you did in the first example, all you need to do is to specify your KMS Customer Master Key ID (generated a-priori, for example, via the AWS management console) in the S3 put request.

S3 server-side encryption using AWS KMS

String customerMasterKeyId = ...;
AmazonS3Client s3 = new AmazonS3Client(new ProfileCredentialsProvider())
        .withRegion(Region.getRegion(Regions.US_EAST_1));

String bucket = ...;
byte[] plaintext = "Hello S3/KMS SSE Encryption!"
            .getBytes(Charset.forName("UTF-8"));
ObjectMetadata metadata = new ObjectMetadata();
metadata.setContentLength(plaintext.length);

PutObjectRequest req = new PutObjectRequest(bucket, "hello_s3_sse_kms.txt",
        new ByteArrayInputStream(plaintext), metadata)
        .withSSEAwsKeyManagementParams(
            new SSEAwsKeyManagementParams(customerMasterKeyId));
PutObjectResult putResult = s3.putObject(req);
System.out.println(putResult);

S3Object s3object = s3.getObject(bucket, "hello_s3_sse_kms.txt");
System.out.println(IOUtils.toString(s3object.getObjectContent()));
s3.shutdown();

For more information about AWS KMS, check out the AWS Key Management Service whitepaper, or the blog New AWS Key Management Service (KMS). Don’t forget to download the latest AWS SDK for Java and give it a spin!