AWS Developer Blog

Using AmazonS3EncryptionClient to Send Secure Data Between Two Parties

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

Suppose you have a partner who would like to encrypt and upload some confidential data to you via Amazon S3, but doesn’t want anyone other than you to be able to decrypt the data. Is this possible?

Yes! That’s a classical use case of Public-key Cryptography, and AmazonS3EncryptionClient makes it easy to do.

First of all, since you are the only party that can decrypt the data, your partner will need to have a copy of your public key. Your private key is, of course, kept secret, and therefore is not shared with your partner. Armed with your public key, your partner can then construct an AmazonS3EncryptionClient to encrypt and upload data to you via S3. Notice, however, the relevant API of AmazonS3EncryptionClient requires the use of a KeyPair. How can one construct a KeyPair with only the public but not the private key? Can the private key be null? The short answer is yes. This may not seem obvious, so here is a sample code snippet on how this can be done:

// Create an S3 client using only a public key
AmazonS3 s3 = new AmazonS3EncryptionClient(new EncryptionMaterials(getPublicKeyPair()));
PutObjectResult result = s3.putObject("your_bucket", "location");
// ...

public static KeyPair getPublicKeyPair() throws NoSuchAlgorithmException, InvalidKeySpecException {
    byte[] public_key = … // public key in binary
    KeyFactory kf = KeyFactory.getInstance("RSA");
    PublicKey publicKey = kf.generatePublic(new X509EncodedKeySpec(public_key));
    return new KeyPair(publicKey, null);

For obvious reasons, any such key pair with a null private key can only, by definition, be used to encrypt and upload data to S3, but cannot decrypt any data retrieved from S3 using the Amazon S3 encryption client. (Indeed, any such attempt would lead to an exception like "AmazonClientException: Unable to decrypt symmetric key".) On the receiving side, to retrieve and decrypt the Amazon S3 object, you can simply make use of AmazonS3EncryptionClient, but this time instantiated with a KeyPair in the usual way (i.e. by specifying both the public and private keys).

Note that, for performance and security reasons, the encryption material provided to the S3 encryption client is used only as a key-encrypting-key material, and not for content encryption. AmazonS3EncryptionClient always encrypts the content of every S3 object with a randomly generated one-time symmetric key, also known as the "envelope key". The envelope key is therefore globally unique per S3 object. As with most block cipher modes of operation, the security assurance degrades as more data is processed with a single key. The unique envelope key per S3 object therefore enables a maximum level of "key freshness" in terms of security.

For more background information, see Client-Side Data Encryption with the AWS SDK for Java and Amazon S3, and Specifying Client-Side Encryption Using the AWS SDK for Java. Let us know what you think!