Amazon S3 Encryption Client Migration (V2 to V3) in the Amazon SDK for PHP Version 3 - Amazon SDK for PHP
Services or capabilities described in Amazon Web Services documentation might vary by Region. To see the differences applicable to the China Regions, see Getting Started with Amazon Web Services in China (PDF).

Amazon S3 Encryption Client Migration (V2 to V3) in the Amazon SDK for PHP Version 3

Note

If you are using Version 1 (V1) of the Amazon S3 encryption client, you must first migrate to Version 2 (V2) before migrating to Version 3 (V3). See Amazon S3 Encryption Client Migration (V1 to V2) in the Amazon SDK for PHP Version 3.

This topic shows how to migrate your applications from Version 2 (V2) of the Amazon Simple Storage Service (Amazon S3) encryption client to Version 3 (V3), and ensure application availability throughout the migration process. Version 3 introduces AES GCM with Key Commitment and Commitment Policies to enhance security and protect against data key tampering.

Migration overview

This migration happens in two phases:

1. Update existing clients to read new formats. First, deploy an updated version of the Amazon SDK for PHP to your application. This allows existing V2 encryption clients to decrypt objects written by the new V3 clients. If your application uses multiple Amazon SDKs, you must upgrade each SDK separately.

2. Migrate encryption and decryption clients to V3. Once all of your V2 encryption clients can read new formats, you can migrate your existing encryption and decryption clients to their respective V3 versions.

Understanding V3 concepts

Version 3 of the Amazon S3 encryption client introduces two key security enhancements: Commitment Policies and the AES GCM with Key Commitment algorithm. Understanding these concepts is essential for a successful migration.

Commitment Policy

A Commitment Policy controls how the encryption client handles key commitment during encryption and decryption operations. Version 3 provides three policy options:

FORBID_ENCRYPT_ALLOW_DECRYPT

Encryption behavior: Encrypts objects without key commitment.

Decryption behavior: Allows decryption of objects encrypted with or without key commitment.

Security implications: This policy does not enforce key commitment on newly encrypted objects, which may allow data key tampering. Use this policy only during the initial migration phase when you need to maintain compatibility with V2 clients.

Version compatibility: Objects encrypted with this policy can be read by all V2 and V3 implementations.

REQUIRE_ENCRYPT_ALLOW_DECRYPT

Encryption behavior: Encrypts objects with key commitment using the ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEY algorithm.

Decryption behavior: Allows decryption of objects encrypted with or without key commitment.

Security implications: This policy provides enhanced security for newly encrypted objects while maintaining the ability to read existing objects. This is the recommended policy for most migration scenarios.

Version compatibility: Objects encrypted with this policy can only be read by V3 and the latest V2 implementations.

Migration considerations: Before using this policy, ensure all clients that need to read the encrypted objects have been upgraded to V3 or the latest V2.

REQUIRE_ENCRYPT_REQUIRE_DECRYPT

Encryption behavior: Encrypts objects with key commitment using the ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEY algorithm.

Decryption behavior: Only allows decryption of objects encrypted with key commitment. Objects encrypted without key commitment will fail to decrypt.

Security implications: This policy provides the highest level of security by enforcing key commitment for both encryption and decryption. Use this policy only after all objects have been migrated to use key commitment.

Version compatibility: Only V3 implementations can use this policy. Attempting to decrypt V1 or V2 encrypted objects with this policy will fail.

Migration considerations: This policy should only be used after completing the full migration and re-encrypting all existing objects with key commitment.

AES GCM with Key Commitment

The AES GCM with Key Commitment (ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEY) algorithm is a new encryption algorithm introduced in V3 that provides protection against data key tampering attacks.

Security enhancement: ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEY protects against data key tampering by cryptographically binding the data key to the encrypted content. This prevents attackers from substituting a different data key during decryption, which could lead to the decryption of unintended data.

Version compatibility: Objects encrypted with ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEY can only be decrypted by V3 and the lastest V2 implementations of the Amazon S3 encryption client. V1 clients cannot decrypt objects encrypted with this algorithm.

Important

Upgrade requirement: Before enabling encryption with ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEY (by using REQUIRE_ENCRYPT_ALLOW_DECRYPT or REQUIRE_ENCRYPT_REQUIRE_DECRYPT policies), you must ensure that all clients that need to read the encrypted objects have been upgraded to V3. Failure to upgrade all readers will result in decryption failures for objects encrypted with key commitment.

Update existing clients to read new formats

The V3 encryption client uses encryption algorithms and key commitment features that older versions of the client don't support. The first step in the migration is to update your V2 decryption clients to the latest SDK release. After completing this step, your application's V2 clients will be able to decrypt objects encrypted by V3 encryption clients. See details below for each installation method of the Amazon SDK for PHP.

Building and installing the latest SDK version

To complete this migration, you must use the latest version of the aws/aws-sdk-php package that includes V3 encryption client support.

Installing from Composer

For projects that were installed using Composer, in the Composer file, update the SDK package to the latest version of the SDK and then run the following command.

composer update aws/aws-sdk-php

Installing Using the Phar or Zip File

Use one of the following methods. Be sure to place the updated SDK file in the location required by your code, which is determined by the require statement.

For projects that were installed using the Phar file, download the updated file: aws.phar.

<?php require '/path/to/aws.phar'; ?>

For projects that were installed using the Zip file, download the updated file: .

<?php require '/path/to/aws-autoloader.php'; ?>

Building, installing, and deploying applications

After updating the SDK, rebuild and redeploy your application to ensure all components are using the updated version. This step is critical to ensure that your V2 clients can read objects encrypted by V3 clients.

Follow your organization's standard deployment procedures to roll out the updated application. Ensure that all instances of your application are updated before proceeding to migrate your encryption and decryption clients to V3.

After deployment, verify that your application can still decrypt existing objects and that no errors occur during normal operations. This confirms that the SDK update was successful and your application is ready for the next phase of migration.

Migrate Encryption and Decryption clients to V3

After updating your clients to read the new encryption formats, you can update your applications to the V3 encryption and decryption clients. The following examples show you how to successfully migrate your code from V2 to V3.

Using V3 Encryption Clients

V3 introduces the S3EncryptionClientV3 class and KmsMaterialsProviderV3 to replace the V2 equivalents. The key differences in V3 are:

  • V3 uses KmsMaterialsProviderV3 (same as V2) but verifies encryption context when decrypting objects in GetObject calls.

  • V3 introduces Commitment Policies to control encryption and decryption behavior.

Example: Migrating from V2 to V3 with KMS Encryption

Pre-migration (V2)

use Aws\S3\Crypto\S3EncryptionClientV2; use Aws\S3\S3Client; use Aws\Crypto\KmsMaterialsProviderV2; use Aws\Kms\KmsClient; $encryptionClient = new S3EncryptionClientV2( new S3Client([ 'profile' => 'default', 'region' => 'us-east-1', 'version' => 'latest', ]) ); $kmsKeyId = 'kms-key-id'; $materialsProvider = new KmsMaterialsProviderV2( new KmsClient([ 'profile' => 'default', 'region' => 'us-east-1', 'version' => 'latest', ]), $kmsKeyId ); $bucket = 'the-bucket-name'; $key = 'the-file-name'; $cipherOptions = [ 'Cipher' => 'gcm', 'KeySize' => 256, ]; $encryptionClient->putObject([ '@MaterialsProvider' => $materialsProvider, '@CipherOptions' => $cipherOptions, '@KmsEncryptionContext' => ['context-key' => 'context-value'], 'Bucket' => $bucket, 'Key' => $key, 'Body' => fopen('file-to-encrypt.txt', 'r'), ]); $result = $encryptionClient->getObject([ '@KmsAllowDecryptWithAnyCmk' => true, '@SecurityProfile' => 'V2_AND_LEGACY', '@CommitmentPolicy' => 'FORBID_ENCRYPT_ALLOW_DECRYPT', '@MaterialsProvider' => $materialsProvider, '@CipherOptions' => $cipherOptions, 'Bucket' => $bucket, 'Key' => $key, ]);

During migration (V3 with backward compatibility)

use Aws\S3\Crypto\S3EncryptionClientV3; use Aws\S3\S3Client; use Aws\Crypto\KmsMaterialsProviderV3; use Aws\Kms\KmsClient; // Create V3 encryption client $encryptionClient = new S3EncryptionClientV3( new S3Client([ 'profile' => 'default', 'region' => 'us-east-1', 'version' => 'latest', ]) ); // Create encryption materials $kmsKeyId = 'kms-key-id'; $materialsProvider = new KmsMaterialsProviderV3( new KmsClient([ 'profile' => 'default', 'region' => 'us-east-1', 'version' => 'latest', ]), $kmsKeyId ); $bucket = 'the-bucket-name'; $key = 'the-file-name'; $cipherOptions = [ 'Cipher' => 'gcm', 'KeySize' => 256, ]; $encryptionClient->putObject([ '@MaterialsProvider' => $materialsProvider, '@CipherOptions' => $cipherOptions, '@CommitmentPolicy' => 'REQUIRE_ENCRYPT_ALLOW_DECRYPT', '@KmsEncryptionContext' => ['context-key' => 'context-value'], 'Bucket' => $bucket, 'Key' => $key, 'Body' => fopen('file-to-encrypt.txt', 'r'), ]); $result = $encryptionClient->getObject([ '@SecurityProfile' => 'V3_AND_LEGACY', '@CommitmentPolicy' => 'REQUIRE_ENCRYPT_ALLOW_DECRYPT', '@MaterialsProvider' => $materialsProvider, '@CipherOptions' => $cipherOptions, 'Bucket' => $bucket, 'Key' => $key, ]);

Post-migration (V3 with key commitment)

use Aws\S3\Crypto\S3EncryptionClientV3; use Aws\S3\S3Client; use Aws\Crypto\KmsMaterialsProviderV3; use Aws\Kms\KmsClient; // Create V3 encryption client $encryptionClient = new S3EncryptionClientV3( new S3Client([ 'profile' => 'default', 'region' => 'us-east-1', 'version' => 'latest', ]) ); // Create encryption materials $kmsKeyId = 'kms-key-id'; $materialsProvider = new KmsMaterialsProviderV3( new KmsClient([ 'profile' => 'default', 'region' => 'us-east-1', 'version' => 'latest', ]), $kmsKeyId ); $bucket = 'the-bucket-name'; $key = 'the-file-name'; $cipherOptions = [ 'Cipher' => 'gcm', 'KeySize' => 256, ]; $encryptionClient->putObject([ '@MaterialsProvider' => $materialsProvider, '@CipherOptions' => $cipherOptions, // Use the commitment policy (REQUIRE_ENCRYPT_REQUIRE_DECRYPT) // This encrypts with key commitment and does not decrypt V2 objects '@CommitmentPolicy' => 'REQUIRE_ENCRYPT_REQUIRE_DECRYPT', '@KmsEncryptionContext' => ['context-key' => 'context-value'], 'Bucket' => $bucket, 'Key' => $key, 'Body' => fopen('file-to-encrypt.txt', 'r'), ]); $result = $encryptionClient->getObject([ '@SecurityProfile' => 'V3', // Use the commitment policy (REQUIRE_ENCRYPT_REQUIRE_DECRYPT) // This encrypts with key commitment and does not decrypt V2 objects '@CommitmentPolicy' => 'REQUIRE_ENCRYPT_REQUIRE_DECRYPT', '@MaterialsProvider' => $materialsProvider, '@CipherOptions' => $cipherOptions, 'Bucket' => $bucket, 'Key' => $key, ]);

Key differences in V3:

  • Use KmsMaterialsProviderV3 instead of KmsMaterialsProviderV2

  • The @KmsEncryptionContext parameter is still required for putObject operations

  • The @KmsEncryptionContext parameter is optional for getObject operations and will verify that the supplied encryption context matches the one in the object.

  • The @SecurityProfile parameter controls which encryption versions can be decrypted. Set to 'V3_AND_LEGACY' to support reading V1 and V2 encrypted objects during migration

  • The @CommitmentPolicy parameter controls the commitment policy for this operation. Set to 'FORBID_ENCRYPT_ALLOW_DECRYPT' to support reading non commitment encrypted objects during migration

Additional examples

The following examples demonstrate additional configuration options available in V3 that can help you manage the migration process and control encryption behavior.

Enabling legacy support

During migration, you may need to decrypt objects that were encrypted with V1 or V2 of the Amazon S3 encryption client. The @SecurityProfile parameter controls which encryption versions your V3 client can decrypt.

When to use this configuration: Use the 'V3_AND_LEGACY' security profile when your application needs to read objects encrypted by V1 or V2 clients. This is common during the migration period when you have a mix of old and new encrypted objects in your buckets.

use Aws\S3\Crypto\S3EncryptionClientV3; use Aws\S3\S3Client; use Aws\Crypto\KmsMaterialsProviderV3; use Aws\Kms\KmsClient; $kmsKeyId = 'kms-key-id'; $materialsProvider = new KmsMaterialsProviderV3( new KmsClient([ 'profile' => 'default', 'region' => 'us-east-1', 'version' => 'latest', ]), $kmsKeyId ); $encryptionClient = new S3EncryptionClientV3( new S3Client([ 'profile' => 'default', 'region' => 'us-east-1', 'version' => 'latest', ]) ); $bucket = 'the-bucket-name'; $key = 'the-file-name'; $cipherOptions = [ 'Cipher' => 'gcm', 'KeySize' => 256, ]; // Decrypt objects encrypted with V1, V2, or V3 $result = $encryptionClient->getObject([ '@SecurityProfile' => 'V3_AND_LEGACY', '@CommitmentPolicy' => 'REQUIRE_ENCRYPT_ALLOW_DECRYPT', '@MaterialsProvider' => $materialsProvider, '@CipherOptions' => $cipherOptions, 'Bucket' => $bucket, 'Key' => $key, ]);

The @SecurityProfile parameter accepts the following values:

  • 'V3' (default): Only decrypt objects encrypted with V3 using key commitment

  • 'V3_AND_LEGACY': Decrypt objects encrypted with V1, V2, or V3

Important

After completing your migration and re-encrypting all objects with V3, you should remove the @SecurityProfile parameter or set it to 'V3' to ensure maximum security.

Configuring storage method

The Amazon S3 encryption client can store encryption metadata in two ways: in the object's metadata headers or in a separate instruction file. The @MetadataStrategy parameter controls which storage method is used.

When to use this configuration: Use 'INSTRUCTION_FILE' when you need to preserve the original object metadata or when working with objects that have metadata size constraints. Use 'METADATA' (the default) for simpler deployments where encryption metadata can be stored alongside the object.

use Aws\S3\Crypto\S3EncryptionClientV3; use Aws\S3\S3Client; use Aws\Crypto\KmsMaterialsProviderV3; use Aws\Kms\KmsClient; $kmsKeyId = 'kms-key-id'; $materialsProvider = new KmsMaterialsProviderV3( new KmsClient([ 'profile' => 'default', 'region' => 'us-east-1', 'version' => 'latest', ]), $kmsKeyId ); $encryptionClient = new S3EncryptionClientV3( new S3Client([ 'profile' => 'default', 'region' => 'us-east-1', 'version' => 'latest', ]) ); $bucket = 'the-bucket-name'; $key = 'the-file-name'; $cipherOptions = [ 'Cipher' => 'gcm', 'KeySize' => 256, ]; // Store encryption metadata in a separate instruction file $encryptionClient->putObject([ '@MaterialsProvider' => $materialsProvider, '@CipherOptions' => $cipherOptions, '@CommitmentPolicy' => 'REQUIRE_ENCRYPT_REQUIRE_DECRYPT', '@MetadataStrategy' => 'INSTRUCTION_FILE', '@KmsEncryptionContext' => ['context-key' => 'context-value'], 'Bucket' => $bucket, 'Key' => $key, 'Body' => fopen('file-to-encrypt.txt', 'r'), ]); // Store encryption metadata in object headers (default) $encryptionClient->putObject([ '@MaterialsProvider' => $materialsProvider, '@CipherOptions' => $cipherOptions, '@CommitmentPolicy' => 'REQUIRE_ENCRYPT_REQUIRE_DECRYPT', '@MetadataStrategy' => 'METADATA', '@KmsEncryptionContext' => ['context-key' => 'context-value'], 'Bucket' => $bucket, 'Key' => $key, 'Body' => fopen('file-to-encrypt.txt', 'r'), ]);

The @MetadataStrategy parameter accepts the following values:

  • 'METADATA' (default): Store encryption metadata in the object's metadata headers

  • 'INSTRUCTION_FILE': Store encryption metadata in a separate instruction file with the suffix .instruction

Note

When using 'INSTRUCTION_FILE', the AES GCM with Key Commitment algorithm provides additional protection against data key tampering. Objects using 'METADATA' storage do not benefit from this additional protection.