AWS Developer Blog

Amazon S3 Client-Side Authenticated Encryption

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

Encrypting data using the Amazon S3 encryption client is one way you can provide an additional layer of protection for sensitive information you store in Amazon S3. Now the Amazon S3 encryption client provides you with the ability to use authenticated encryption for your stored data via the new CryptoMode.AuthenticatedEncryption option. The Developer Preview of this client-side encryption option utilizes AES-GCM – a standard authenticated encryption algorithm recommended by NIST.

When CryptoMode.AuthenticatedEncryption is in use, an improved key wrapping algorithm will be applied to the envelope key, which is a one-time key randomly generated per S3 object. One of two key wrapping algorithms is used, depending on the encryption material you use. "AESWrap" is applied if the client-supplied encryption material contains a symmetric key; "RSA/ECB/OAEPWithSHA-256AndMGF1Padding" is used if the encryption material contains a key pair. Both key wrapping algorithms improve the level of protection of the envelope key with integrity check in addition to using encryption alone.

Enabling Authenticated Encryption

This new mode of authenticated encryption is disabled by default. This means the Amazon S3 encryption client will continue to function as before unless explicitly configured otherwise.

To enable the use of client-side authenticated encryption, two steps are required:

  1. Include the latest Bouncy Castle jar in the classpath; and
  2. Explicitly specify the cryptographic mode of authenticated encryption when instantiating an S3 encryption client
new AmazonS3EncryptionClient(...,
  new CryptoConfiguration(CryptoMode.AuthenticatedEncryption));

Once enabled, all new S3 objects will be encrypted using AES-GCM before being stored in S3. Otherwise, everything remains the same as described in the Getting Started guide at Client-Side Data Encryption with the AWS SDK for Java and Amazon S3. In other words, all APIs of the S3 encryption client including Range-Get and Multipart Upload will work the same way regardless of the selected cryptographic mode.

How CryptoMode.AuthenticatedEncryption Works

Storage

If CryptoMode.AuthenticatedEncryption is not enabled, the default behavior of the S3 encryption client will persist S3 objects using the same cryptographic algorithm as before, which is encryption-only.

However, if CryptoMode.AuthenticatedEncryption has been enabled, new S3 objects will be encrypted using the standard authenticated encryption algorithm, AES-GCM. Furthermore, the generated one-time envelope key will be protected using a new key-wrapping algorithm.

Retrieval

Existing S3 objects that have been encrypted using the default encryption-only scheme, CryptoMode.EncryptionOnly, will continue to work as before with no behavior changes regardless of whether CryptoMode.AuthenticatedEncryption is enabled or not.

However, if an S3 object that has been encrypted under CryptoMode.AuthenticatedEncryption is retrieved in its entirety, not only is the object automatically decrypted when retrieved, the integrity of the object is also verified (via AES-GCM). If for any reason the object failed the integrity check, a SecurityException would be thrown. A sample exception message:

java.lang.SecurityException: javax.crypto.BadPaddingException: mac check in GCM failed

Note, however, if only part of an object is retrieved from S3 via the Range-Get operation, then only decryption will apply and not authentication since the entire object is required for authentication.

Two Modes of Authenticated Encryption Available

There are actually two authenticated encryption modes available: CryptoMode.AuthenticatedEncryption and CryptoMode.StrictAuthenticatedEncryption.

CryptoMode.StrictAuthenticatedEncryption is a variant of CryptoMode.AuthenticatedEncryption, but it enforces a strict use of authenticated encryption. Specifically, the S3 encryption client running in CryptoMode.StrictAuthenticatedEncryption will only accept retrieval of S3 objects protected via authentication encryption. Retrieving S3 objects in plaintext or encrypted using encryption-only mode will cause a SecurityException to be thrown under the strict mode. A sample exception message:

java.lang.SecurityException: S3 object [bucket: mybucket, key: mykey] not encrypted using authenticated encryption

Furthermore, attempts to perform a Range-get operation in strict authenticated encryption mode will also cause SecurityException to be thrown, since Range-get has no authentication on the data retrieved. A sample exception message:

java.lang.SecurityException: Range get is not allowed in strict crypto mode

The purpose of CryptoMode.StrictAuthenticatedEncryption is to eliminate the possibility of an attacker hypothetically forcing a downgrade to bypass authentication. In other words, running in CryptoMode.StrictAuthenticatedEncryption would provide the highest level of security but potentially at the cost of restricted operations. This strict use of authenticated encryption is meant only for highly security-sensitive applications where there is no need to retrieve S3 objects that have not been previously encrypted using authenticated encryption.

Migrating to Authenticated Encryption

It’s worth pointing out that older versions of the AWS SDK for Java are not equipped with authenticated encryption and therefore will not be able to decrypt objects encrypted with authenticated encryption. Therefore, before enabling CryptoMode.AuthenticatedEncryption, you should upgrade all instances of the AWS SDK for Java in your application to the latest version. With no configuration necessary, the latest version of Java SDK is able to retrieve and decrypt S3 objects that are originally encrypted either in encryption-only mode (AES-CBC) or authenticated encryption mode (AES-GCM). Once all instances of the SDK are upgraded, you can then safely enable CryptoMode.AuthenticatedEncryption to start writing new S3 objects using authenticated encryption. Here is a summary table.

Java SDK CryptoMode Encrypt Decrypt Range Get Multipart Upload Max Size (bytes)
1.7.8.1+ AuthenticatedEncryption AES‑GCM AES‑GCM AES-CBC Yes Yes ~64GB
1.7.8.1+ StrictAuthenticatedEncryption AES‑GCM AES‑GCM No Yes ~64GB
1.7.8.1+ EncryptionOnly AES‑CBC AES‑GCM AES‑CBC Yes Yes 5TB
pre-1.7.8 (Not Applicable) AES‑CBC AES‑CBC Yes Yes 5TB

New Runtime Dependency on Bouncy Castle Library

You may wonder why we do not statically include the Bouncy Castle crypto library jar as a direct dependency. First, by not having a static dependency on the Bouncy Castle Crypto APIs, we believe users can take advantage of the latest releases from Bouncy Castle in a more timely and flexible manner. This is especially relevant should there be security fixes to the library. The other reason is that only users who decide to make use of authenticated encryption would need to depend on the Bouncy Castle library. We therefore do not want to force everyone else to pull in a copy of Bouncy Castle unless they need to.

Authenticated Encryption or Not?

If the protection of S3 objects in your application requires not only confidentiality but also integrity and authenticity, and the size of each object is less than 64 GB, then CryptoMode.AuthenticatedEncryption may be just the option you have been looking for. Why 64GB? It is a limiting factor of the standard AES-GCM. More details can be found in the NIST GCM spec.

Does your application require storing S3 objects with authenticated encryption? Let us know what you think!