From 094f14bd35106a0e6b7bda8f379e5422d2659053 Mon Sep 17 00:00:00 2001 From: Jose Corella Date: Tue, 9 Dec 2025 16:27:03 -0800 Subject: [PATCH 1/3] chore(PHP): run migration examples in ci --- all-examples/php/v3/main.php | 353 ++++++++++++++++++++++++++++++++++- 1 file changed, 352 insertions(+), 1 deletion(-) diff --git a/all-examples/php/v3/main.php b/all-examples/php/v3/main.php index e22519c3..e64df5fa 100755 --- a/all-examples/php/v3/main.php +++ b/all-examples/php/v3/main.php @@ -7,9 +7,11 @@ use Aws\Kms\KmsClient; use Aws\S3\Crypto\S3EncryptionClientV3; use Aws\Crypto\KmsMaterialsProviderV3; +use Aws\S3\Crypto\S3EncryptionClientV2; +use Aws\Crypto\KmsMaterialsProviderV2; use Aws\Exception\AwsException; -function main() { +function main(): void { // Check command line arguments if (count($GLOBALS['argv']) !== 5) { echo "Usage: {$GLOBALS['argv'][0]} \n"; @@ -157,7 +159,356 @@ function main() { } } +function testMigration(): void { + if (count($GLOBALS['argv']) !== 5) { + echo "Usage: {$GLOBALS['argv'][0]} \n"; + echo "Example: {$GLOBALS['argv'][0]} avp-21638 s3ec-php-v3 arn:aws:kms:us-east-2:648638458147:key/a47079da-17e4-45a5-b82e-2bac101cad01 us-east-2\n"; + exit(1); + } + + $bucketName = $GLOBALS['argv'][1]; + $objectKey = $GLOBALS['argv'][2]; + $kmsKeyId = $GLOBALS['argv'][3]; + $region = $GLOBALS['argv'][4]; + + echo "=== S3 Encryption Client Pre-migration (V2) Example ===\n"; + echo "Bucket: {$bucketName}\n"; + echo "Object Key: {$objectKey}\n"; + echo "KMS Key ID: {$kmsKeyId}\n"; + echo "Region: {$region}\n"; + echo "\n"; + + try { + $testData = "Hello, World! This is a test message for S3 encryption client Pre-migration (V2) in PHP."; + echo "Original data: {$testData}\n"; + echo "Data length: " . strlen($testData) . " bytes\n"; + echo "\n"; + + $v2EncryptionClient = new S3EncryptionClientV2( + new S3Client([ + 'profile' => 'default', + 'region' => $region, + 'version' => 'latest', + ]) + ); + + $materialsProviderV2 = new KmsMaterialsProviderV2( + new KmsClient([ + 'profile' => 'default', + 'region' => $region, + 'version' => 'latest', + ]), + $kmsKeyId + ); + + $cipherOptions = [ + 'Cipher' => 'gcm', + 'KeySize' => 256, + ]; + + $v2EncryptionClient->putObject([ + '@MaterialsProvider' => $materialsProviderV2, + '@CipherOptions' => $cipherOptions, + '@KmsEncryptionContext' => ['context-key' => 'context-value'], + 'Bucket' => $bucketName, + 'Key' => $objectKey, + 'Body' => $testData, + ]); + + $getResponse = $v2EncryptionClient->getObject([ + '@KmsAllowDecryptWithAnyCmk' => true, + '@SecurityProfile' => 'V2_AND_LEGACY', + '@CommitmentPolicy' => 'FORBID_ENCRYPT_ALLOW_DECRYPT', + '@MaterialsProvider' => $materialsProviderV2, + '@CipherOptions' => $cipherOptions, + 'Bucket' => $bucketName, + 'Key' => $objectKey, + ]); + + // Read the decrypted data + $decryptedData = (string) $getResponse['Body']; + + echo "Successfully downloaded and decrypted object from S3!\n"; + echo " Object size: " . strlen($decryptedData) . " bytes\n"; + echo " Decrypted data: {$decryptedData}\n"; + echo "\n"; + + echo "--- Verify Roundtrip Success ---\n"; + + // Verify the roundtrip was successful + if ($decryptedData === $testData) { + echo "SUCCESS: Roundtrip encryption/decryption completed successfully!\n"; + echo " Original data matches decrypted data\n"; + echo " Data integrity verified\n"; + } else { + echo "ERROR: Roundtrip failed - data mismatch\n"; + echo " Original: {$testData}\n"; + echo " Decrypted: {$decryptedData}\n"; + exit(1); + } + + // Optionally Delete the Object + // echo "--- Cleanup ---\n"; + // Clean up the test object using regular S3 client + // $s3Client->deleteObject([ + // 'Bucket' => $bucketName, + // 'Key' => $objectKey + // ]); + // echo "Test object deleted from S3\n"; + + echo "\n"; + echo "=== Example completed successfully! ===\n"; + + } catch (AwsException $e) { + $errorCode = $e->getAwsErrorCode(); + $errorMessage = $e->getMessage(); + + if (strpos($errorCode, 'NoSuchBucket') !== false) { + echo "Error: S3 bucket '{$bucketName}' does not exist or is not accessible\n"; + echo " {$errorMessage}\n"; + } elseif (strpos($errorCode, 'NotFoundException') !== false) { + echo "Error: KMS key '{$kmsKeyId}' not found or not accessible\n"; + echo " {$errorMessage}\n"; + } elseif (strpos($errorMessage, 'encryption') !== false) { + echo "S3 Encryption Error: {$errorMessage}\n"; + } else { + echo "AWS Service Error: {$errorMessage}\n"; + echo " Error Code: {$errorCode}\n"; + } + exit(1); + } catch (Exception $e) { + echo "Unexpected error: {$e->getMessage()}\n"; + echo " File: {$e->getFile()}:{$e->getLine()}\n"; + exit(1); + } + + echo "=== S3 Encryption Client during migration (V3 with backward compatibility) Example ===\n"; + echo "Bucket: {$bucketName}\n"; + echo "Object Key: {$objectKey}\n"; + echo "KMS Key ID: {$kmsKeyId}\n"; + echo "Region: {$region}\n"; + echo "\n"; + + try { + $testData = "Hello, World! This is a test message for S3 encryption client during migration (V3 with backward compatibility) in PHP."; + echo "Original data: {$testData}\n"; + echo "Data length: " . strlen($testData) . " bytes\n"; + echo "\n"; + + $v2EncryptionClient = new S3EncryptionClientV3( + new S3Client([ + 'profile' => 'default', + 'region' => $region, + 'version' => 'latest', + ]) + ); + + $materialsProviderV3 = new KmsMaterialsProviderV3( + new KmsClient([ + 'profile' => 'default', + 'region' => $region, + 'version' => 'latest', + ]), + $kmsKeyId + ); + + $cipherOptions = [ + 'Cipher' => 'gcm', + 'KeySize' => 256, + ]; + + $v2EncryptionClient->putObject([ + '@MaterialsProvider' => $materialsProviderV3, + '@CipherOptions' => $cipherOptions, + '@CommitmentPolicy' => 'REQUIRE_ENCRYPT_ALLOW_DECRYPT', + '@KmsEncryptionContext' => ['context-key' => 'context-value'], + 'Bucket' => $bucketName, + 'Key' => $objectKey, + 'Body' => $testData, + ]); + + $getResponse = $v2EncryptionClient->getObject([ + '@KmsAllowDecryptWithAnyCmk' => true, + '@SecurityProfile' => 'V3_AND_LEGACY', + '@CommitmentPolicy' => 'REQUIRE_ENCRYPT_ALLOW_DECRYPT', + '@MaterialsProvider' => $materialsProviderV3, + '@CipherOptions' => $cipherOptions, + 'Bucket' => $bucketName, + 'Key' => $objectKey, + ]); + + // Read the decrypted data + $decryptedData = (string) $getResponse['Body']; + + echo "Successfully downloaded and decrypted object from S3!\n"; + echo " Object size: " . strlen($decryptedData) . " bytes\n"; + echo " Decrypted data: {$decryptedData}\n"; + echo "\n"; + + echo "--- Verify Roundtrip Success ---\n"; + + // Verify the roundtrip was successful + if ($decryptedData === $testData) { + echo "SUCCESS: Roundtrip encryption/decryption completed successfully!\n"; + echo " Original data matches decrypted data\n"; + echo " Data integrity verified\n"; + } else { + echo "ERROR: Roundtrip failed - data mismatch\n"; + echo " Original: {$testData}\n"; + echo " Decrypted: {$decryptedData}\n"; + exit(1); + } + + // Optionally Delete the Object + // echo "--- Cleanup ---\n"; + // Clean up the test object using regular S3 client + // $s3Client->deleteObject([ + // 'Bucket' => $bucketName, + // 'Key' => $objectKey + // ]); + // echo "Test object deleted from S3\n"; + + echo "\n"; + echo "=== Example completed successfully! ===\n"; + + } catch (AwsException $e) { + $errorCode = $e->getAwsErrorCode(); + $errorMessage = $e->getMessage(); + + if (strpos($errorCode, 'NoSuchBucket') !== false) { + echo "Error: S3 bucket '{$bucketName}' does not exist or is not accessible\n"; + echo " {$errorMessage}\n"; + } elseif (strpos($errorCode, 'NotFoundException') !== false) { + echo "Error: KMS key '{$kmsKeyId}' not found or not accessible\n"; + echo " {$errorMessage}\n"; + } elseif (strpos($errorMessage, 'encryption') !== false) { + echo "S3 Encryption Error: {$errorMessage}\n"; + } else { + echo "AWS Service Error: {$errorMessage}\n"; + echo " Error Code: {$errorCode}\n"; + } + exit(1); + } catch (Exception $e) { + echo "Unexpected error: {$e->getMessage()}\n"; + echo " File: {$e->getFile()}:{$e->getLine()}\n"; + exit(1); + } + + echo "=== S3 Encryption Client post-migration (V3 with key commitment) Example ===\n"; + echo "Bucket: {$bucketName}\n"; + echo "Object Key: {$objectKey}\n"; + echo "KMS Key ID: {$kmsKeyId}\n"; + echo "Region: {$region}\n"; + echo "\n"; + + try { + $testData = "Hello, World! This is a test message for S3 encryption client post-migration (V3 with key commitment) in PHP."; + echo "Original data: {$testData}\n"; + echo "Data length: " . strlen($testData) . " bytes\n"; + echo "\n"; + + $v2EncryptionClient = new S3EncryptionClientV3( + new S3Client([ + 'profile' => 'default', + 'region' => $region, + 'version' => 'latest', + ]) + ); + + $materialsProviderV3 = new KmsMaterialsProviderV3( + new KmsClient([ + 'profile' => 'default', + 'region' => $region, + 'version' => 'latest', + ]), + $kmsKeyId + ); + + $cipherOptions = [ + 'Cipher' => 'gcm', + 'KeySize' => 256, + ]; + + $v2EncryptionClient->putObject([ + '@MaterialsProvider' => $materialsProviderV3, + '@CipherOptions' => $cipherOptions, + '@CommitmentPolicy' => 'REQUIRE_ENCRYPT_REQUIRE_DECRYPT', + '@KmsEncryptionContext' => ['context-key' => 'context-value'], + 'Bucket' => $bucketName, + 'Key' => $objectKey, + 'Body' => $testData, + ]); + + $getResponse = $v2EncryptionClient->getObject([ + '@KmsAllowDecryptWithAnyCmk' => true, + '@SecurityProfile' => 'V3', + '@CommitmentPolicy' => 'REQUIRE_ENCRYPT_REQUIRE_DECRYPT', + '@MaterialsProvider' => $materialsProviderV3, + '@CipherOptions' => $cipherOptions, + 'Bucket' => $bucketName, + 'Key' => $objectKey, + ]); + + // Read the decrypted data + $decryptedData = (string) $getResponse['Body']; + + echo "Successfully downloaded and decrypted object from S3!\n"; + echo " Object size: " . strlen($decryptedData) . " bytes\n"; + echo " Decrypted data: {$decryptedData}\n"; + echo "\n"; + + echo "--- Verify Roundtrip Success ---\n"; + + // Verify the roundtrip was successful + if ($decryptedData === $testData) { + echo "SUCCESS: Roundtrip encryption/decryption completed successfully!\n"; + echo " Original data matches decrypted data\n"; + echo " Data integrity verified\n"; + } else { + echo "ERROR: Roundtrip failed - data mismatch\n"; + echo " Original: {$testData}\n"; + echo " Decrypted: {$decryptedData}\n"; + exit(1); + } + + // Optionally Delete the Object + // echo "--- Cleanup ---\n"; + // Clean up the test object using regular S3 client + // $s3Client->deleteObject([ + // 'Bucket' => $bucketName, + // 'Key' => $objectKey + // ]); + // echo "Test object deleted from S3\n"; + + echo "\n"; + echo "=== Example completed successfully! ===\n"; + + } catch (AwsException $e) { + $errorCode = $e->getAwsErrorCode(); + $errorMessage = $e->getMessage(); + + if (strpos($errorCode, 'NoSuchBucket') !== false) { + echo "Error: S3 bucket '{$bucketName}' does not exist or is not accessible\n"; + echo " {$errorMessage}\n"; + } elseif (strpos($errorCode, 'NotFoundException') !== false) { + echo "Error: KMS key '{$kmsKeyId}' not found or not accessible\n"; + echo " {$errorMessage}\n"; + } elseif (strpos($errorMessage, 'encryption') !== false) { + echo "S3 Encryption Error: {$errorMessage}\n"; + } else { + echo "AWS Service Error: {$errorMessage}\n"; + echo " Error Code: {$errorCode}\n"; + } + exit(1); + } catch (Exception $e) { + echo "Unexpected error: {$e->getMessage()}\n"; + echo " File: {$e->getFile()}:{$e->getLine()}\n"; + exit(1); + } +} + // Run the main function if this script is executed directly if (php_sapi_name() === 'cli' && isset($GLOBALS['argv']) && basename($GLOBALS['argv'][0]) === basename(__FILE__)) { main(); + testMigration(); } From 10089d0894cfc1c9f7356333b9b7234d202dee8d Mon Sep 17 00:00:00 2001 From: Jose Corella Date: Wed, 10 Dec 2025 11:37:33 -0800 Subject: [PATCH 2/3] fix creds --- all-examples/php/v3/main.php | 6 ------ 1 file changed, 6 deletions(-) diff --git a/all-examples/php/v3/main.php b/all-examples/php/v3/main.php index e64df5fa..9aa9e288 100755 --- a/all-examples/php/v3/main.php +++ b/all-examples/php/v3/main.php @@ -186,7 +186,6 @@ function testMigration(): void { $v2EncryptionClient = new S3EncryptionClientV2( new S3Client([ - 'profile' => 'default', 'region' => $region, 'version' => 'latest', ]) @@ -194,7 +193,6 @@ function testMigration(): void { $materialsProviderV2 = new KmsMaterialsProviderV2( new KmsClient([ - 'profile' => 'default', 'region' => $region, 'version' => 'latest', ]), @@ -297,7 +295,6 @@ function testMigration(): void { $v2EncryptionClient = new S3EncryptionClientV3( new S3Client([ - 'profile' => 'default', 'region' => $region, 'version' => 'latest', ]) @@ -305,7 +302,6 @@ function testMigration(): void { $materialsProviderV3 = new KmsMaterialsProviderV3( new KmsClient([ - 'profile' => 'default', 'region' => $region, 'version' => 'latest', ]), @@ -409,7 +405,6 @@ function testMigration(): void { $v2EncryptionClient = new S3EncryptionClientV3( new S3Client([ - 'profile' => 'default', 'region' => $region, 'version' => 'latest', ]) @@ -417,7 +412,6 @@ function testMigration(): void { $materialsProviderV3 = new KmsMaterialsProviderV3( new KmsClient([ - 'profile' => 'default', 'region' => $region, 'version' => 'latest', ]), From ab24f4c0822d89704c63831f16d76901c3b27470 Mon Sep 17 00:00:00 2001 From: Jose Corella Date: Wed, 10 Dec 2025 13:09:30 -0800 Subject: [PATCH 3/3] typos --- all-examples/php/v3/main.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/all-examples/php/v3/main.php b/all-examples/php/v3/main.php index 9aa9e288..949a0ce1 100755 --- a/all-examples/php/v3/main.php +++ b/all-examples/php/v3/main.php @@ -293,7 +293,7 @@ function testMigration(): void { echo "Data length: " . strlen($testData) . " bytes\n"; echo "\n"; - $v2EncryptionClient = new S3EncryptionClientV3( + $v3EncryptionClient = new S3EncryptionClientV3( new S3Client([ 'region' => $region, 'version' => 'latest', @@ -313,7 +313,7 @@ function testMigration(): void { 'KeySize' => 256, ]; - $v2EncryptionClient->putObject([ + $v3EncryptionClient->putObject([ '@MaterialsProvider' => $materialsProviderV3, '@CipherOptions' => $cipherOptions, '@CommitmentPolicy' => 'REQUIRE_ENCRYPT_ALLOW_DECRYPT', @@ -323,7 +323,7 @@ function testMigration(): void { 'Body' => $testData, ]); - $getResponse = $v2EncryptionClient->getObject([ + $getResponse = $v3EncryptionClient->getObject([ '@KmsAllowDecryptWithAnyCmk' => true, '@SecurityProfile' => 'V3_AND_LEGACY', '@CommitmentPolicy' => 'REQUIRE_ENCRYPT_ALLOW_DECRYPT', @@ -403,7 +403,7 @@ function testMigration(): void { echo "Data length: " . strlen($testData) . " bytes\n"; echo "\n"; - $v2EncryptionClient = new S3EncryptionClientV3( + $v3EncryptionClient = new S3EncryptionClientV3( new S3Client([ 'region' => $region, 'version' => 'latest', @@ -423,7 +423,7 @@ function testMigration(): void { 'KeySize' => 256, ]; - $v2EncryptionClient->putObject([ + $v3EncryptionClient->putObject([ '@MaterialsProvider' => $materialsProviderV3, '@CipherOptions' => $cipherOptions, '@CommitmentPolicy' => 'REQUIRE_ENCRYPT_REQUIRE_DECRYPT', @@ -433,7 +433,7 @@ function testMigration(): void { 'Body' => $testData, ]); - $getResponse = $v2EncryptionClient->getObject([ + $getResponse = $v3EncryptionClient->getObject([ '@KmsAllowDecryptWithAnyCmk' => true, '@SecurityProfile' => 'V3', '@CommitmentPolicy' => 'REQUIRE_ENCRYPT_REQUIRE_DECRYPT',