AWS SDK for PHP
Developer Guide

Amazon S3 Client-Side Encryption with the AWS SDK for PHP Version 3

The AWS SDK for PHP provides an S3EncryptionClient. With client-side encryption, data is encrypted and decrypted directly in your environment. This means that this data is encrypted before it's transferred to Amazon S3, and you don’t rely on an external service to handle encryption for you.

The AWS SDK for PHP implements envelope encryption and uses OpenSSL for its encrypting and decrypting. The implementation is interoperable with other SDKs that match its feature support. It's also compatible with the SDK’s promise-based asynchronous workflow.

Setup

To get started with client-side encryption, you need the following:

Before running any example code, configure your AWS credentials. See Credentials for the AWS SDK for PHP Version 3.

Encryption

Uploading an encrypted object through the PutObject operation takes a similar interface and requires two new parameters.

use Aws\S3\S3Client; use Aws\S3\Crypto\S3EncryptionClient; use Aws\Kms\KmsClient; use Aws\Crypto\KmsMaterialsProvider; // Let's construct our S3EncryptionClient using an S3Client $encryptionClient = new S3EncryptionClient( new S3Client([ 'profile' => 'default', 'region' => 'us-east-1', 'version' => 'latest', ]) ); $kmsKeyArn = 'arn-to-the-kms-key'; // This materials provider handles generating a cipher key and // initialization vector, as well as encrypting your cipher key via AWS KMS $materialsProvider = new KmsMaterialsProvider( new KmsClient([ 'profile' => 'default', 'region' => 'us-east-1', 'version' => 'latest', ]), $kmsKeyArn ); $bucket = 'the-bucket-name'; $key = 'the-file-name'; $cipherOptions = [ 'Cipher' => 'gcm', 'KeySize' => 256, // Additional configuration options ]; $result = $encryptionClient->putObject([ '@MaterialsProvider' => $materialsProvider, '@CipherOptions' => $cipherOptions, 'Bucket' => $bucket, 'Key' => $key, 'Body' => fopen('file-to-encrypt.txt', 'r'), ]);

Note

In addition to the Amazon S3 and AWS KMS-based service errors, you might receive thrown InvalidArgumentException objects if your '@CipherOptions' are not correctly configured.

Decryption

Downloading and decrypting an object requires only one additional parameter on top of GetObject, and the client will detect the basic cipher options for you. Additional configuration options are passed through for decryption.

$result = $encryptionClient->getObject([ '@MaterialsProvider' => $materialsProvider, '@CipherOptions' => [ // Additional configuration options ], 'Bucket' => $bucket, 'Key' => $key, ]);

Note

In addition to the Amazon S3 and AWS KMS-based service errors, you might receive thrown InvalidArgumentException objects if your '@CipherOptions' are not correctly configured.

Cipher Configuration

'Cipher' (string)

Cipher method that the encryption client uses while encrypting. Only 'gcm' and 'cbc' are supported at this time.

Important

PHP is updated in version 7.1 to include the extra parameters necessary to encrypt and decrypt using OpenSSL for GCM encryption. As a result, using GCM with your Aws\S3\Crypto\S3EncryptionClient is only available on PHP 7.1 or later.

'KeySize' (int)

The length of the content encryption key to generate for encrypting. Defaults to 256 bits. Valid configuration options are 256, 192, and 128.

'Aad' (string)

Optional 'Additional authentication data' to include with your encrypted payload. This information is validated on decryption. Aad is available only when using the 'gcm' cipher.

Metadata Strategies

You also have the option of providing an instance of a class that implements the Aws\Crypto\MetadataStrategyInterface. This simple interface handles saving and loading the Aws\Crypto\MetadataEnvelope that contains your envelope encryption materials. The SDK provides two classes that implement this: Aws\S3\Crypto\HeadersMetadataStrategy and Aws\S3\Crypto\InstructionFileMetadataStrategy. HeadersMetadataStrategy is used by default.

$strategy = new InstructionFileMetadataStrategy( $s3Client, '.instr' ); $result = $encryptionClient->putObject([ '@MaterialsProvider' => $materialsProvider, '@MetadataStrategy' => $strategy, '@CipherOptions' => $cipherOptions, 'Bucket' => $bucket, 'Key' => $key, 'Body' => fopen('file-to-encrypt.txt'), ]);

Class name constants for the HeadersMetadataStrategy and InstructionFileMetadataStrategy can also be supplied by invoking ::class.

$result = $encryptionClient->putObject([ '@MaterialsProvider' => $materialsProvider, '@MetadataStrategy' => HeadersMetadataStrategy::class, '@CipherOptions' => $cipherOptions, 'Bucket' => $bucket, 'Key' => $key, 'Body' => fopen('file-to-encrypt.txt'), ]);

Note

If there is a failure after an instruction file is uploaded, it will not be automatically deleted.

Multipart Uploads

Performing a multipart upload with client-side encryption is also possible. The Aws\S3\Crypto\S3EncryptionMultipartUploader prepares the source stream for for encryption before uploading. Creating one takes on a similar experience to using the Aws\S3\MultipartUploader and the Aws\S3\Crypto\S3EncryptionClient. The S3EncryptionMultipartUploader can handle the same '@MetadataStrategy' option as the S3EncryptionClient, as well as all available '@CipherOptions' configurations.

$kmsKeyArn = 'arn-to-the-kms-key'; // This materials provider handles generating a cipher key and // initialization vector, as well as encrypting your cipher key via AWS KMS $materialsProvider = new KmsMaterialsProvider( new KmsClient([ 'region' => 'us-east-1', 'version' => 'latest', 'profile' => 'default', ]), $kmsKeyArn ); $bucket = 'the-bucket-name'; $key = 'the-upload-key'; $cipherOptions = [ 'Cipher' => 'gcm' 'KeySize' => 256, // Additional configuration options ]; $multipartUploader = new S3EncryptionMultipartUploader( new S3Client([ 'region' => 'us-east-1', 'version' => 'latest', 'profile' => 'default', ]), fopen('large-file-to-encrypt.txt'), [ '@MaterialsProvider' => $materialsProvider, '@CipherOptions' => $cipherOptions, 'bucket' => 'bucket', 'key' => 'key', ] ); $multipartUploader->upload();

Note

In addition to the Amazon S3 and AWS KMS-based service errors, you might receive thrown InvalidArgumentException objects if your '@CipherOptions' are not correctly configured.