diff options
author | Andrew Dolgov <[email protected]> | 2022-11-23 21:14:33 +0300 |
---|---|---|
committer | Andrew Dolgov <[email protected]> | 2022-11-23 21:14:33 +0300 |
commit | 0c8af4992cb0f7589dcafaad65ada12753c64594 (patch) | |
tree | 18e83d068c3e7dd2499331de977782b382279396 /vendor/aws/aws-sdk-php/src/S3/Crypto |
initial
Diffstat (limited to 'vendor/aws/aws-sdk-php/src/S3/Crypto')
9 files changed, 1398 insertions, 0 deletions
diff --git a/vendor/aws/aws-sdk-php/src/S3/Crypto/CryptoParamsTrait.php b/vendor/aws/aws-sdk-php/src/S3/Crypto/CryptoParamsTrait.php new file mode 100644 index 0000000..57253a4 --- /dev/null +++ b/vendor/aws/aws-sdk-php/src/S3/Crypto/CryptoParamsTrait.php @@ -0,0 +1,75 @@ +<?php +namespace Aws\S3\Crypto; + +use Aws\Crypto\MaterialsProvider; +use Aws\Crypto\MetadataEnvelope; +use Aws\Crypto\MetadataStrategyInterface; + +trait CryptoParamsTrait +{ + protected function getMaterialsProvider(array $args) + { + if ($args['@MaterialsProvider'] instanceof MaterialsProvider) { + return $args['@MaterialsProvider']; + } + + throw new \InvalidArgumentException('An instance of MaterialsProvider' + . ' must be passed in the "MaterialsProvider" field.'); + } + + protected function getInstructionFileSuffix(array $args) + { + return !empty($args['@InstructionFileSuffix']) + ? $args['@InstructionFileSuffix'] + : $this->instructionFileSuffix; + } + + protected function determineGetObjectStrategy( + $result, + $instructionFileSuffix + ) { + if (isset($result['Metadata'][MetadataEnvelope::CONTENT_KEY_V2_HEADER])) { + return new HeadersMetadataStrategy(); + } + + return new InstructionFileMetadataStrategy( + $this->client, + $instructionFileSuffix + ); + } + + protected function getMetadataStrategy(array $args, $instructionFileSuffix) + { + if (!empty($args['@MetadataStrategy'])) { + if ($args['@MetadataStrategy'] instanceof MetadataStrategyInterface) { + return $args['@MetadataStrategy']; + } + + if (is_string($args['@MetadataStrategy'])) { + switch ($args['@MetadataStrategy']) { + case HeadersMetadataStrategy::class: + return new HeadersMetadataStrategy(); + case InstructionFileMetadataStrategy::class: + return new InstructionFileMetadataStrategy( + $this->client, + $instructionFileSuffix + ); + default: + throw new \InvalidArgumentException('Could not match the' + . ' specified string in "MetadataStrategy" to a' + . ' predefined strategy.'); + } + } else { + throw new \InvalidArgumentException('The metadata strategy that' + . ' was passed to "MetadataStrategy" was unrecognized.'); + } + } elseif ($instructionFileSuffix) { + return new InstructionFileMetadataStrategy( + $this->client, + $instructionFileSuffix + ); + } + + return null; + } +} diff --git a/vendor/aws/aws-sdk-php/src/S3/Crypto/CryptoParamsTraitV2.php b/vendor/aws/aws-sdk-php/src/S3/Crypto/CryptoParamsTraitV2.php new file mode 100644 index 0000000..0549817 --- /dev/null +++ b/vendor/aws/aws-sdk-php/src/S3/Crypto/CryptoParamsTraitV2.php @@ -0,0 +1,19 @@ +<?php +namespace Aws\S3\Crypto; + +use Aws\Crypto\MaterialsProviderInterfaceV2; + +trait CryptoParamsTraitV2 +{ + use CryptoParamsTrait; + + protected function getMaterialsProvider(array $args) + { + if ($args['@MaterialsProvider'] instanceof MaterialsProviderInterfaceV2) { + return $args['@MaterialsProvider']; + } + + throw new \InvalidArgumentException('An instance of MaterialsProviderInterfaceV2' + . ' must be passed in the "MaterialsProvider" field.'); + } +} diff --git a/vendor/aws/aws-sdk-php/src/S3/Crypto/HeadersMetadataStrategy.php b/vendor/aws/aws-sdk-php/src/S3/Crypto/HeadersMetadataStrategy.php new file mode 100644 index 0000000..ea2d993 --- /dev/null +++ b/vendor/aws/aws-sdk-php/src/S3/Crypto/HeadersMetadataStrategy.php @@ -0,0 +1,52 @@ +<?php +namespace Aws\S3\Crypto; + +use \Aws\Crypto\MetadataStrategyInterface; +use \Aws\Crypto\MetadataEnvelope; + +class HeadersMetadataStrategy implements MetadataStrategyInterface +{ + /** + * Places the information in the MetadataEnvelope in to the metadata for + * the PutObject request of the encrypted object. + * + * @param MetadataEnvelope $envelope Encryption data to save according to + * the strategy. + * @param array $args Arguments for PutObject that can be manipulated to + * store strategy related information. + * + * @return array Updated arguments for PutObject. + */ + public function save(MetadataEnvelope $envelope, array $args) + { + foreach ($envelope as $header=>$value) { + $args['Metadata'][$header] = $value; + } + + return $args; + } + + /** + * Generates a MetadataEnvelope according to the metadata headers from the + * GetObject result. + * + * @param array $args Arguments from Command and Result that contains + * S3 Object information, relevant headers, and command + * configuration. + * + * @return MetadataEnvelope + */ + public function load(array $args) + { + $envelope = new MetadataEnvelope(); + $constantValues = MetadataEnvelope::getConstantValues(); + + foreach ($constantValues as $constant) { + if (!empty($args['Metadata'][$constant])) { + $envelope[$constant] = $args['Metadata'][$constant]; + } + } + + return $envelope; + } +} diff --git a/vendor/aws/aws-sdk-php/src/S3/Crypto/InstructionFileMetadataStrategy.php b/vendor/aws/aws-sdk-php/src/S3/Crypto/InstructionFileMetadataStrategy.php new file mode 100644 index 0000000..5065928 --- /dev/null +++ b/vendor/aws/aws-sdk-php/src/S3/Crypto/InstructionFileMetadataStrategy.php @@ -0,0 +1,90 @@ +<?php +namespace Aws\S3\Crypto; + +use \Aws\Crypto\MetadataStrategyInterface; +use \Aws\Crypto\MetadataEnvelope; +use \Aws\S3\S3Client; + +/** + * Stores and reads encryption MetadataEnvelope information in a file on Amazon + * S3. + * + * A file with the contents of a MetadataEnvelope will be created or read from + * alongside the base file on Amazon S3. The provided client will be used for + * reading or writing this object. A specified suffix (default of '.instruction' + * will be applied to each of the operations involved with the instruction file. + * + * If there is a failure after an instruction file has been uploaded, it will + * not be automatically deleted. + */ +class InstructionFileMetadataStrategy implements MetadataStrategyInterface +{ + const DEFAULT_FILE_SUFFIX = '.instruction'; + + private $client; + private $suffix; + + /** + * @param S3Client $client Client for use in uploading the instruction file. + * @param string|null $suffix Optional override suffix for instruction file + * object keys. + */ + public function __construct(S3Client $client, $suffix = null) + { + $this->suffix = empty($suffix) + ? self::DEFAULT_FILE_SUFFIX + : $suffix; + $this->client = $client; + } + + /** + * Places the information in the MetadataEnvelope to a location on S3. + * + * @param MetadataEnvelope $envelope Encryption data to save according to + * the strategy. + * @param array $args Starting arguments for PutObject, used for saving + * extra the instruction file. + * + * @return array Updated arguments for PutObject. + */ + public function save(MetadataEnvelope $envelope, array $args) + { + $this->client->putObject([ + 'Bucket' => $args['Bucket'], + 'Key' => $args['Key'] . $this->suffix, + 'Body' => json_encode($envelope) + ]); + + return $args; + } + + /** + * Uses the strategy's client to retrieve the instruction file from S3 and generates + * a MetadataEnvelope from its contents. + * + * @param array $args Arguments from Command and Result that contains + * S3 Object information, relevant headers, and command + * configuration. + * + * @return MetadataEnvelope + */ + public function load(array $args) + { + $result = $this->client->getObject([ + 'Bucket' => $args['Bucket'], + 'Key' => $args['Key'] . $this->suffix + ]); + + $metadataHeaders = json_decode($result['Body'], true); + $envelope = new MetadataEnvelope(); + $constantValues = MetadataEnvelope::getConstantValues(); + + foreach ($constantValues as $constant) { + if (!empty($metadataHeaders[$constant])) { + $envelope[$constant] = $metadataHeaders[$constant]; + } + } + + return $envelope; + } +} diff --git a/vendor/aws/aws-sdk-php/src/S3/Crypto/S3EncryptionClient.php b/vendor/aws/aws-sdk-php/src/S3/Crypto/S3EncryptionClient.php new file mode 100644 index 0000000..30b5100 --- /dev/null +++ b/vendor/aws/aws-sdk-php/src/S3/Crypto/S3EncryptionClient.php @@ -0,0 +1,340 @@ +<?php +namespace Aws\S3\Crypto; + +use Aws\Crypto\DecryptionTrait; +use Aws\HashingStream; +use Aws\PhpHash; +use Aws\Crypto\AbstractCryptoClient; +use Aws\Crypto\EncryptionTrait; +use Aws\Crypto\MetadataEnvelope; +use Aws\Crypto\MaterialsProvider; +use Aws\Crypto\Cipher\CipherBuilderTrait; +use Aws\S3\S3Client; +use GuzzleHttp\Promise; +use GuzzleHttp\Promise\PromiseInterface; +use GuzzleHttp\Psr7; + +/** + * Provides a wrapper for an S3Client that supplies functionality to encrypt + * data on putObject[Async] calls and decrypt data on getObject[Async] calls. + * + * Legacy implementation using older encryption workflow. + * + * AWS strongly recommends the upgrade to the S3EncryptionClientV2 (over the + * S3EncryptionClient), as it offers updated data security best practices to our + * customers who upgrade. S3EncryptionClientV2 contains breaking changes, so this + * will require planning by engineering teams to migrate. New workflows should + * just start with S3EncryptionClientV2. + * + * @deprecated + */ +class S3EncryptionClient extends AbstractCryptoClient +{ + use CipherBuilderTrait; + use CryptoParamsTrait; + use DecryptionTrait; + use EncryptionTrait; + use UserAgentTrait; + + const CRYPTO_VERSION = '1n'; + + private $client; + private $instructionFileSuffix; + + /** + * @param S3Client $client The S3Client to be used for true uploading and + * retrieving objects from S3 when using the + * encryption client. + * @param string|null $instructionFileSuffix Suffix for a client wide + * default when using instruction + * files for metadata storage. + */ + public function __construct( + S3Client $client, + $instructionFileSuffix = null + ) { + $this->appendUserAgent($client, 'feat/s3-encrypt/' . self::CRYPTO_VERSION); + $this->client = $client; + $this->instructionFileSuffix = $instructionFileSuffix; + } + + private static function getDefaultStrategy() + { + return new HeadersMetadataStrategy(); + } + + /** + * Encrypts the data in the 'Body' field of $args and promises to upload it + * to the specified location on S3. + * + * @param array $args Arguments for encrypting an object and uploading it + * to S3 via PutObject. + * + * The required configuration arguments are as follows: + * + * - @MaterialsProvider: (MaterialsProvider) Provides Cek, Iv, and Cek + * encrypting/decrypting for encryption metadata. + * - @CipherOptions: (array) Cipher options for encrypting data. Only the + * Cipher option is required. Accepts the following: + * - Cipher: (string) cbc|gcm + * See also: AbstractCryptoClient::$supportedCiphers. Note that + * cbc is deprecated and gcm should be used when possible. + * - KeySize: (int) 128|192|256 + * See also: MaterialsProvider::$supportedKeySizes + * - Aad: (string) Additional authentication data. This option is + * passed directly to OpenSSL when using gcm. It is ignored when + * using cbc. Note if you pass in Aad for gcm encryption, the + * PHP SDK will be able to decrypt the resulting object, but other + * AWS SDKs may not be able to do so. + * + * The optional configuration arguments are as follows: + * + * - @MetadataStrategy: (MetadataStrategy|string|null) Strategy for storing + * MetadataEnvelope information. Defaults to using a + * HeadersMetadataStrategy. Can either be a class implementing + * MetadataStrategy, a class name of a predefined strategy, or empty/null + * to default. + * - @InstructionFileSuffix: (string|null) Suffix used when writing to an + * instruction file if using an InstructionFileMetadataHandler. + * + * @return PromiseInterface + * + * @throws \InvalidArgumentException Thrown when arguments above are not + * passed or are passed incorrectly. + */ + public function putObjectAsync(array $args) + { + $provider = $this->getMaterialsProvider($args); + unset($args['@MaterialsProvider']); + + $instructionFileSuffix = $this->getInstructionFileSuffix($args); + unset($args['@InstructionFileSuffix']); + + $strategy = $this->getMetadataStrategy($args, $instructionFileSuffix); + unset($args['@MetadataStrategy']); + + $envelope = new MetadataEnvelope(); + + return Promise\Create::promiseFor($this->encrypt( + Psr7\Utils::streamFor($args['Body']), + $args['@CipherOptions'] ?: [], + $provider, + $envelope + ))->then( + function ($encryptedBodyStream) use ($args) { + $hash = new PhpHash('sha256'); + $hashingEncryptedBodyStream = new HashingStream( + $encryptedBodyStream, + $hash, + self::getContentShaDecorator($args) + ); + return [$hashingEncryptedBodyStream, $args]; + } + )->then( + function ($putObjectContents) use ($strategy, $envelope) { + list($bodyStream, $args) = $putObjectContents; + if ($strategy === null) { + $strategy = self::getDefaultStrategy(); + } + + $updatedArgs = $strategy->save($envelope, $args); + $updatedArgs['Body'] = $bodyStream; + return $updatedArgs; + } + )->then( + function ($args) { + unset($args['@CipherOptions']); + return $this->client->putObjectAsync($args); + } + ); + } + + private static function getContentShaDecorator(&$args) + { + return function ($hash) use (&$args) { + $args['ContentSHA256'] = bin2hex($hash); + }; + } + + /** + * Encrypts the data in the 'Body' field of $args and uploads it to the + * specified location on S3. + * + * @param array $args Arguments for encrypting an object and uploading it + * to S3 via PutObject. + * + * The required configuration arguments are as follows: + * + * - @MaterialsProvider: (MaterialsProvider) Provides Cek, Iv, and Cek + * encrypting/decrypting for encryption metadata. + * - @CipherOptions: (array) Cipher options for encrypting data. A Cipher + * is required. Accepts the following options: + * - Cipher: (string) cbc|gcm + * See also: AbstractCryptoClient::$supportedCiphers. Note that + * cbc is deprecated and gcm should be used when possible. + * - KeySize: (int) 128|192|256 + * See also: MaterialsProvider::$supportedKeySizes + * - Aad: (string) Additional authentication data. This option is + * passed directly to OpenSSL when using gcm. It is ignored when + * using cbc. Note if you pass in Aad for gcm encryption, the + * PHP SDK will be able to decrypt the resulting object, but other + * AWS SDKs may not be able to do so. + * + * The optional configuration arguments are as follows: + * + * - @MetadataStrategy: (MetadataStrategy|string|null) Strategy for storing + * MetadataEnvelope information. Defaults to using a + * HeadersMetadataStrategy. Can either be a class implementing + * MetadataStrategy, a class name of a predefined strategy, or empty/null + * to default. + * - @InstructionFileSuffix: (string|null) Suffix used when writing to an + * instruction file if an using an InstructionFileMetadataHandler was + * determined. + * + * @return \Aws\Result PutObject call result with the details of uploading + * the encrypted file. + * + * @throws \InvalidArgumentException Thrown when arguments above are not + * passed or are passed incorrectly. + */ + public function putObject(array $args) + { + return $this->putObjectAsync($args)->wait(); + } + + /** + * Promises to retrieve an object from S3 and decrypt the data in the + * 'Body' field. + * + * @param array $args Arguments for retrieving an object from S3 via + * GetObject and decrypting it. + * + * The required configuration argument is as follows: + * + * - @MaterialsProvider: (MaterialsProvider) Provides Cek, Iv, and Cek + * encrypting/decrypting for decryption metadata. May have data loaded + * from the MetadataEnvelope upon decryption. + * + * The optional configuration arguments are as follows: + * + * - SaveAs: (string) The path to a file on disk to save the decrypted + * object data. This will be handled by file_put_contents instead of the + * Guzzle sink. + * + * - @MetadataStrategy: (MetadataStrategy|string|null) Strategy for reading + * MetadataEnvelope information. Defaults to determining based on object + * response headers. Can either be a class implementing MetadataStrategy, + * a class name of a predefined strategy, or empty/null to default. + * - @InstructionFileSuffix: (string) Suffix used when looking for an + * instruction file if an InstructionFileMetadataHandler is being used. + * - @CipherOptions: (array) Cipher options for decrypting data. A Cipher + * is required. Accepts the following options: + * - Aad: (string) Additional authentication data. This option is + * passed directly to OpenSSL when using gcm. It is ignored when + * using cbc. + * + * @return PromiseInterface + * + * @throws \InvalidArgumentException Thrown when required arguments are not + * passed or are passed incorrectly. + */ + public function getObjectAsync(array $args) + { + $provider = $this->getMaterialsProvider($args); + unset($args['@MaterialsProvider']); + + $instructionFileSuffix = $this->getInstructionFileSuffix($args); + unset($args['@InstructionFileSuffix']); + + $strategy = $this->getMetadataStrategy($args, $instructionFileSuffix); + unset($args['@MetadataStrategy']); + + $saveAs = null; + if (!empty($args['SaveAs'])) { + $saveAs = $args['SaveAs']; + } + + $promise = $this->client->getObjectAsync($args) + ->then( + function ($result) use ( + $provider, + $instructionFileSuffix, + $strategy, + $args + ) { + if ($strategy === null) { + $strategy = $this->determineGetObjectStrategy( + $result, + $instructionFileSuffix + ); + } + + $envelope = $strategy->load($args + [ + 'Metadata' => $result['Metadata'] + ]); + + $provider = $provider->fromDecryptionEnvelope($envelope); + + $result['Body'] = $this->decrypt( + $result['Body'], + $provider, + $envelope, + isset($args['@CipherOptions']) + ? $args['@CipherOptions'] + : [] + ); + return $result; + } + )->then( + function ($result) use ($saveAs) { + if (!empty($saveAs)) { + file_put_contents( + $saveAs, + (string)$result['Body'], + LOCK_EX + ); + } + return $result; + } + ); + + return $promise; + } + + /** + * Retrieves an object from S3 and decrypts the data in the 'Body' field. + * + * @param array $args Arguments for retrieving an object from S3 via + * GetObject and decrypting it. + * + * The required configuration argument is as follows: + * + * - @MaterialsProvider: (MaterialsProvider) Provides Cek, Iv, and Cek + * encrypting/decrypting for decryption metadata. May have data loaded + * from the MetadataEnvelope upon decryption. + * + * The optional configuration arguments are as follows: + * + * - SaveAs: (string) The path to a file on disk to save the decrypted + * object data. This will be handled by file_put_contents instead of the + * Guzzle sink. + * - @InstructionFileSuffix: (string|null) Suffix used when looking for an + * instruction file if an InstructionFileMetadataHandler was detected. + * - @CipherOptions: (array) Cipher options for encrypting data. A Cipher + * is required. Accepts the following options: + * - Aad: (string) Additional authentication data. This option is + * passed directly to OpenSSL when using gcm. It is ignored when + * using cbc. + * + * @return \Aws\Result GetObject call result with the 'Body' field + * wrapped in a decryption stream with its metadata + * information. + * + * @throws \InvalidArgumentException Thrown when arguments above are not + * passed or are passed incorrectly. + */ + public function getObject(array $args) + { + return $this->getObjectAsync($args)->wait(); + } +} diff --git a/vendor/aws/aws-sdk-php/src/S3/Crypto/S3EncryptionClientV2.php b/vendor/aws/aws-sdk-php/src/S3/Crypto/S3EncryptionClientV2.php new file mode 100644 index 0000000..5690c76 --- /dev/null +++ b/vendor/aws/aws-sdk-php/src/S3/Crypto/S3EncryptionClientV2.php @@ -0,0 +1,446 @@ +<?php +namespace Aws\S3\Crypto; + +use Aws\Crypto\DecryptionTraitV2; +use Aws\Exception\CryptoException; +use Aws\HashingStream; +use Aws\PhpHash; +use Aws\Crypto\AbstractCryptoClientV2; +use Aws\Crypto\EncryptionTraitV2; +use Aws\Crypto\MetadataEnvelope; +use Aws\Crypto\MaterialsProvider; +use Aws\Crypto\Cipher\CipherBuilderTrait; +use Aws\S3\S3Client; +use GuzzleHttp\Promise; +use GuzzleHttp\Promise\PromiseInterface; +use GuzzleHttp\Psr7; + +/** + * Provides a wrapper for an S3Client that supplies functionality to encrypt + * data on putObject[Async] calls and decrypt data on getObject[Async] calls. + * + * AWS strongly recommends the upgrade to the S3EncryptionClientV2 (over the + * S3EncryptionClient), as it offers updated data security best practices to our + * customers who upgrade. S3EncryptionClientV2 contains breaking changes, so this + * will require planning by engineering teams to migrate. New workflows should + * just start with S3EncryptionClientV2. + * + * Note that for PHP versions of < 7.1, this class uses an AES-GCM polyfill + * for encryption since there is no native PHP support. The performance for large + * inputs will be a lot slower than for PHP 7.1+, so upgrading older PHP version + * environments may be necessary to use this effectively. + * + * Example write path: + * + * <code> + * use Aws\Crypto\KmsMaterialsProviderV2; + * use Aws\S3\Crypto\S3EncryptionClientV2; + * use Aws\S3\S3Client; + * + * $encryptionClient = new S3EncryptionClientV2( + * new S3Client([ + * 'region' => 'us-west-2', + * 'version' => 'latest' + * ]) + * ); + * $materialsProvider = new KmsMaterialsProviderV2( + * new KmsClient([ + * 'profile' => 'default', + * 'region' => 'us-east-1', + * 'version' => 'latest', + * ], + * 'your-kms-key-id' + * ); + * + * $encryptionClient->putObject([ + * '@MaterialsProvider' => $materialsProvider, + * '@CipherOptions' => [ + * 'Cipher' => 'gcm', + * 'KeySize' => 256, + * ], + * '@KmsEncryptionContext' => ['foo' => 'bar'], + * 'Bucket' => 'your-bucket', + * 'Key' => 'your-key', + * 'Body' => 'your-encrypted-data', + * ]); + * </code> + * + * Example read call (using objects from previous example): + * + * <code> + * $encryptionClient->getObject([ + * '@MaterialsProvider' => $materialsProvider, + * '@CipherOptions' => [ + * 'Cipher' => 'gcm', + * 'KeySize' => 256, + * ], + * 'Bucket' => 'your-bucket', + * 'Key' => 'your-key', + * ]); + * </code> + */ +class S3EncryptionClientV2 extends AbstractCryptoClientV2 +{ + use CipherBuilderTrait; + use CryptoParamsTraitV2; + use DecryptionTraitV2; + use EncryptionTraitV2; + use UserAgentTrait; + + const CRYPTO_VERSION = '2.1'; + + private $client; + private $instructionFileSuffix; + private $legacyWarningCount; + + /** + * @param S3Client $client The S3Client to be used for true uploading and + * retrieving objects from S3 when using the + * encryption client. + * @param string|null $instructionFileSuffix Suffix for a client wide + * default when using instruction + * files for metadata storage. + */ + public function __construct( + S3Client $client, + $instructionFileSuffix = null + ) { + $this->appendUserAgent($client, 'feat/s3-encrypt/' . self::CRYPTO_VERSION); + $this->client = $client; + $this->instructionFileSuffix = $instructionFileSuffix; + $this->legacyWarningCount = 0; + } + + private static function getDefaultStrategy() + { + return new HeadersMetadataStrategy(); + } + + /** + * Encrypts the data in the 'Body' field of $args and promises to upload it + * to the specified location on S3. + * + * Note that for PHP versions of < 7.1, this operation uses an AES-GCM + * polyfill for encryption since there is no native PHP support. The + * performance for large inputs will be a lot slower than for PHP 7.1+, so + * upgrading older PHP version environments may be necessary to use this + * effectively. + * + * @param array $args Arguments for encrypting an object and uploading it + * to S3 via PutObject. + * + * The required configuration arguments are as follows: + * + * - @MaterialsProvider: (MaterialsProviderV2) Provides Cek, Iv, and Cek + * encrypting/decrypting for encryption metadata. + * - @CipherOptions: (array) Cipher options for encrypting data. Only the + * Cipher option is required. Accepts the following: + * - Cipher: (string) gcm + * See also: AbstractCryptoClientV2::$supportedCiphers + * - KeySize: (int) 128|256 + * See also: MaterialsProvider::$supportedKeySizes + * - Aad: (string) Additional authentication data. This option is + * passed directly to OpenSSL when using gcm. Note if you pass in + * Aad, the PHP SDK will be able to decrypt the resulting object, + * but other AWS SDKs may not be able to do so. + * - @KmsEncryptionContext: (array) Only required if using + * KmsMaterialsProviderV2. An associative array of key-value + * pairs to be added to the encryption context for KMS key encryption. An + * empty array may be passed if no additional context is desired. + * + * The optional configuration arguments are as follows: + * + * - @MetadataStrategy: (MetadataStrategy|string|null) Strategy for storing + * MetadataEnvelope information. Defaults to using a + * HeadersMetadataStrategy. Can either be a class implementing + * MetadataStrategy, a class name of a predefined strategy, or empty/null + * to default. + * - @InstructionFileSuffix: (string|null) Suffix used when writing to an + * instruction file if using an InstructionFileMetadataHandler. + * + * @return PromiseInterface + * + * @throws \InvalidArgumentException Thrown when arguments above are not + * passed or are passed incorrectly. + */ + public function putObjectAsync(array $args) + { + $provider = $this->getMaterialsProvider($args); + unset($args['@MaterialsProvider']); + + $instructionFileSuffix = $this->getInstructionFileSuffix($args); + unset($args['@InstructionFileSuffix']); + + $strategy = $this->getMetadataStrategy($args, $instructionFileSuffix); + unset($args['@MetadataStrategy']); + + $envelope = new MetadataEnvelope(); + + return Promise\Create::promiseFor($this->encrypt( + Psr7\Utils::streamFor($args['Body']), + $args, + $provider, + $envelope + ))->then( + function ($encryptedBodyStream) use ($args) { + $hash = new PhpHash('sha256'); + $hashingEncryptedBodyStream = new HashingStream( + $encryptedBodyStream, + $hash, + self::getContentShaDecorator($args) + ); + return [$hashingEncryptedBodyStream, $args]; + } + )->then( + function ($putObjectContents) use ($strategy, $envelope) { + list($bodyStream, $args) = $putObjectContents; + if ($strategy === null) { + $strategy = self::getDefaultStrategy(); + } + + $updatedArgs = $strategy->save($envelope, $args); + $updatedArgs['Body'] = $bodyStream; + return $updatedArgs; + } + )->then( + function ($args) { + unset($args['@CipherOptions']); + return $this->client->putObjectAsync($args); + } + ); + } + + private static function getContentShaDecorator(&$args) + { + return function ($hash) use (&$args) { + $args['ContentSHA256'] = bin2hex($hash); + }; + } + + /** + * Encrypts the data in the 'Body' field of $args and uploads it to the + * specified location on S3. + * + * Note that for PHP versions of < 7.1, this operation uses an AES-GCM + * polyfill for encryption since there is no native PHP support. The + * performance for large inputs will be a lot slower than for PHP 7.1+, so + * upgrading older PHP version environments may be necessary to use this + * effectively. + * + * @param array $args Arguments for encrypting an object and uploading it + * to S3 via PutObject. + * + * The required configuration arguments are as follows: + * + * - @MaterialsProvider: (MaterialsProvider) Provides Cek, Iv, and Cek + * encrypting/decrypting for encryption metadata. + * - @CipherOptions: (array) Cipher options for encrypting data. A Cipher + * is required. Accepts the following options: + * - Cipher: (string) gcm + * See also: AbstractCryptoClientV2::$supportedCiphers + * - KeySize: (int) 128|256 + * See also: MaterialsProvider::$supportedKeySizes + * - Aad: (string) Additional authentication data. This option is + * passed directly to OpenSSL when using gcm. Note if you pass in + * Aad, the PHP SDK will be able to decrypt the resulting object, + * but other AWS SDKs may not be able to do so. + * - @KmsEncryptionContext: (array) Only required if using + * KmsMaterialsProviderV2. An associative array of key-value + * pairs to be added to the encryption context for KMS key encryption. An + * empty array may be passed if no additional context is desired. + * + * The optional configuration arguments are as follows: + * + * - @MetadataStrategy: (MetadataStrategy|string|null) Strategy for storing + * MetadataEnvelope information. Defaults to using a + * HeadersMetadataStrategy. Can either be a class implementing + * MetadataStrategy, a class name of a predefined strategy, or empty/null + * to default. + * - @InstructionFileSuffix: (string|null) Suffix used when writing to an + * instruction file if an using an InstructionFileMetadataHandler was + * determined. + * + * @return \Aws\Result PutObject call result with the details of uploading + * the encrypted file. + * + * @throws \InvalidArgumentException Thrown when arguments above are not + * passed or are passed incorrectly. + */ + public function putObject(array $args) + { + return $this->putObjectAsync($args)->wait(); + } + + /** + * Promises to retrieve an object from S3 and decrypt the data in the + * 'Body' field. + * + * @param array $args Arguments for retrieving an object from S3 via + * GetObject and decrypting it. + * + * The required configuration argument is as follows: + * + * - @MaterialsProvider: (MaterialsProviderInterface) Provides Cek, Iv, and Cek + * encrypting/decrypting for decryption metadata. May have data loaded + * from the MetadataEnvelope upon decryption. + * - @SecurityProfile: (string) Must be set to 'V2' or 'V2_AND_LEGACY'. + * - 'V2' indicates that only objects encrypted with S3EncryptionClientV2 + * content encryption and key wrap schemas are able to be decrypted. + * - 'V2_AND_LEGACY' indicates that objects encrypted with both + * S3EncryptionClientV2 and older legacy encryption clients are able + * to be decrypted. + * + * The optional configuration arguments are as follows: + * + * - SaveAs: (string) The path to a file on disk to save the decrypted + * object data. This will be handled by file_put_contents instead of the + * Guzzle sink. + * + * - @MetadataStrategy: (MetadataStrategy|string|null) Strategy for reading + * MetadataEnvelope information. Defaults to determining based on object + * response headers. Can either be a class implementing MetadataStrategy, + * a class name of a predefined strategy, or empty/null to default. + * - @InstructionFileSuffix: (string) Suffix used when looking for an + * instruction file if an InstructionFileMetadataHandler is being used. + * - @CipherOptions: (array) Cipher options for decrypting data. A Cipher + * is required. Accepts the following options: + * - Aad: (string) Additional authentication data. This option is + * passed directly to OpenSSL when using gcm. It is ignored when + * using cbc. + * - @KmsAllowDecryptWithAnyCmk: (bool) This allows decryption with + * KMS materials for any KMS key ID, instead of needing the KMS key ID to + * be specified and provided to the decrypt operation. Ignored for non-KMS + * materials providers. Defaults to false. + * + * @return PromiseInterface + * + * @throws \InvalidArgumentException Thrown when required arguments are not + * passed or are passed incorrectly. + */ + public function getObjectAsync(array $args) + { + $provider = $this->getMaterialsProvider($args); + unset($args['@MaterialsProvider']); + + $instructionFileSuffix = $this->getInstructionFileSuffix($args); + unset($args['@InstructionFileSuffix']); + + $strategy = $this->getMetadataStrategy($args, $instructionFileSuffix); + unset($args['@MetadataStrategy']); + + if (!isset($args['@SecurityProfile']) + || !in_array($args['@SecurityProfile'], self::$supportedSecurityProfiles) + ) { + throw new CryptoException("@SecurityProfile is required and must be" + . " set to 'V2' or 'V2_AND_LEGACY'"); + } + + // Only throw this legacy warning once per client + if (in_array($args['@SecurityProfile'], self::$legacySecurityProfiles) + && $this->legacyWarningCount < 1 + ) { + $this->legacyWarningCount++; + trigger_error( + "This S3 Encryption Client operation is configured to" + . " read encrypted data with legacy encryption modes. If you" + . " don't have objects encrypted with these legacy modes," + . " you should disable support for them to enhance security. ", + E_USER_WARNING + ); + } + + $saveAs = null; + if (!empty($args['SaveAs'])) { + $saveAs = $args['SaveAs']; + } + + $promise = $this->client->getObjectAsync($args) + ->then( + function ($result) use ( + $provider, + $instructionFileSuffix, + $strategy, + $args + ) { + if ($strategy === null) { + $strategy = $this->determineGetObjectStrategy( + $result, + $instructionFileSuffix + ); + } + + $envelope = $strategy->load($args + [ + 'Metadata' => $result['Metadata'] + ]); + + $result['Body'] = $this->decrypt( + $result['Body'], + $provider, + $envelope, + $args + ); + return $result; + } + )->then( + function ($result) use ($saveAs) { + if (!empty($saveAs)) { + file_put_contents( + $saveAs, + (string)$result['Body'], + LOCK_EX + ); + } + return $result; + } + ); + + return $promise; + } + + /** + * Retrieves an object from S3 and decrypts the data in the 'Body' field. + * + * @param array $args Arguments for retrieving an object from S3 via + * GetObject and decrypting it. + * + * The required configuration argument is as follows: + * + * - @MaterialsProvider: (MaterialsProviderInterface) Provides Cek, Iv, and Cek + * encrypting/decrypting for decryption metadata. May have data loaded + * from the MetadataEnvelope upon decryption. + * - @SecurityProfile: (string) Must be set to 'V2' or 'V2_AND_LEGACY'. + * - 'V2' indicates that only objects encrypted with S3EncryptionClientV2 + * content encryption and key wrap schemas are able to be decrypted. + * - 'V2_AND_LEGACY' indicates that objects encrypted with both + * S3EncryptionClientV2 and older legacy encryption clients are able + * to be decrypted. + * + * The optional configuration arguments are as follows: + * + * - SaveAs: (string) The path to a file on disk to save the decrypted + * object data. This will be handled by file_put_contents instead of the + * Guzzle sink. + * - @InstructionFileSuffix: (string|null) Suffix used when looking for an + * instruction file if an InstructionFileMetadataHandler was detected. + * - @CipherOptions: (array) Cipher options for encrypting data. A Cipher + * is required. Accepts the following options: + * - Aad: (string) Additional authentication data. This option is + * passed directly to OpenSSL when using gcm. It is ignored when + * using cbc. + * - @KmsAllowDecryptWithAnyCmk: (bool) This allows decryption with + * KMS materials for any KMS key ID, instead of needing the KMS key ID to + * be specified and provided to the decrypt operation. Ignored for non-KMS + * materials providers. Defaults to false. + * + * @return \Aws\Result GetObject call result with the 'Body' field + * wrapped in a decryption stream with its metadata + * information. + * + * @throws \InvalidArgumentException Thrown when arguments above are not + * passed or are passed incorrectly. + */ + public function getObject(array $args) + { + return $this->getObjectAsync($args)->wait(); + } +} diff --git a/vendor/aws/aws-sdk-php/src/S3/Crypto/S3EncryptionMultipartUploader.php b/vendor/aws/aws-sdk-php/src/S3/Crypto/S3EncryptionMultipartUploader.php new file mode 100644 index 0000000..ddf1d2d --- /dev/null +++ b/vendor/aws/aws-sdk-php/src/S3/Crypto/S3EncryptionMultipartUploader.php @@ -0,0 +1,169 @@ +<?php +namespace Aws\S3\Crypto; + +use Aws\Crypto\AbstractCryptoClient; +use Aws\Crypto\EncryptionTrait; +use Aws\Crypto\MetadataEnvelope; +use Aws\Crypto\Cipher\CipherBuilderTrait; +use Aws\S3\MultipartUploader; +use Aws\S3\S3ClientInterface; +use GuzzleHttp\Promise; + +/** + * Encapsulates the execution of a multipart upload of an encrypted object to S3. + * + * Legacy implementation using older encryption workflow. Use + * S3EncryptionMultipartUploaderV2 if possible. + * + * @deprecated + */ +class S3EncryptionMultipartUploader extends MultipartUploader +{ + use CipherBuilderTrait; + use CryptoParamsTrait; + use EncryptionTrait; + use UserAgentTrait; + + const CRYPTO_VERSION = '1n'; + + /** + * Returns if the passed cipher name is supported for encryption by the SDK. + * + * @param string $cipherName The name of a cipher to verify is registered. + * + * @return bool If the cipher passed is in our supported list. + */ + public static function isSupportedCipher($cipherName) + { + return in_array($cipherName, AbstractCryptoClient::$supportedCiphers); + } + + private $provider; + private $instructionFileSuffix; + private $strategy; + + /** + * Creates a multipart upload for an S3 object after encrypting it. + * + * The required configuration options are as follows: + * + * - @MaterialsProvider: (MaterialsProvider) Provides Cek, Iv, and Cek + * encrypting/decrypting for encryption metadata. + * - @CipherOptions: (array) Cipher options for encrypting data. A Cipher + * is required. Accepts the following options: + * - Cipher: (string) cbc|gcm + * See also: AbstractCryptoClient::$supportedCiphers. Note that + * cbc is deprecated and gcm should be used when possible. + * - KeySize: (int) 128|192|256 + * See also: MaterialsProvider::$supportedKeySizes + * - Aad: (string) Additional authentication data. This option is + * passed directly to OpenSSL when using gcm. It is ignored when + * using cbc. + * - bucket: (string) Name of the bucket to which the object is + * being uploaded. + * - key: (string) Key to use for the object being uploaded. + * + * The optional configuration arguments are as follows: + * + * - @MetadataStrategy: (MetadataStrategy|string|null) Strategy for storing + * MetadataEnvelope information. Defaults to using a + * HeadersMetadataStrategy. Can either be a class implementing + * MetadataStrategy, a class name of a predefined strategy, or empty/null + * to default. + * - @InstructionFileSuffix: (string|null) Suffix used when writing to an + * instruction file if an using an InstructionFileMetadataHandler was + * determined. + * - acl: (string) ACL to set on the object being upload. Objects are + * private by default. + * - before_complete: (callable) Callback to invoke before the + * `CompleteMultipartUpload` operation. The callback should have a + * function signature like `function (Aws\Command $command) {...}`. + * - before_initiate: (callable) Callback to invoke before the + * `CreateMultipartUpload` operation. The callback should have a function + * signature like `function (Aws\Command $command) {...}`. + * - before_upload: (callable) Callback to invoke before any `UploadPart` + * operations. The callback should have a function signature like + * `function (Aws\Command $command) {...}`. + * - concurrency: (int, default=int(5)) Maximum number of concurrent + * `UploadPart` operations allowed during the multipart upload. + * - params: (array) An array of key/value parameters that will be applied + * to each of the sub-commands run by the uploader as a base. + * Auto-calculated options will override these parameters. If you need + * more granularity over parameters to each sub-command, use the before_* + * options detailed above to update the commands directly. + * - part_size: (int, default=int(5242880)) Part size, in bytes, to use when + * doing a multipart upload. This must between 5 MB and 5 GB, inclusive. + * - state: (Aws\Multipart\UploadState) An object that represents the state + * of the multipart upload and that is used to resume a previous upload. + * When this option is provided, the `bucket`, `key`, and `part_size` + * options are ignored. + * + * @param S3ClientInterface $client Client used for the upload. + * @param mixed $source Source of the data to upload. + * @param array $config Configuration used to perform the upload. + */ + public function __construct( + S3ClientInterface $client, + $source, + array $config = [] + ) { + $this->appendUserAgent($client, 'feat/s3-encrypt/' . self::CRYPTO_VERSION); + $this->client = $client; + $config['params'] = []; + if (!empty($config['bucket'])) { + $config['params']['Bucket'] = $config['bucket']; + } + if (!empty($config['key'])) { + $config['params']['Key'] = $config['key']; + } + + $this->provider = $this->getMaterialsProvider($config); + unset($config['@MaterialsProvider']); + + $this->instructionFileSuffix = $this->getInstructionFileSuffix($config); + unset($config['@InstructionFileSuffix']); + $this->strategy = $this->getMetadataStrategy( + $config, + $this->instructionFileSuffix + ); + if ($this->strategy === null) { + $this->strategy = self::getDefaultStrategy(); + } + unset($config['@MetadataStrategy']); + + $config['prepare_data_source'] = $this->getEncryptingDataPreparer(); + + parent::__construct($client, $source, $config); + } + + private static function getDefaultStrategy() + { + return new HeadersMetadataStrategy(); + } + + private function getEncryptingDataPreparer() + { + return function() { + // Defer encryption work until promise is executed + $envelope = new MetadataEnvelope(); + + list($this->source, $params) = Promise\Create::promiseFor($this->encrypt( + $this->source, + $this->config['@cipheroptions'] ?: [], + $this->provider, + $envelope + ))->then( + function ($bodyStream) use ($envelope) { + $params = $this->strategy->save( + $envelope, + $this->config['params'] + ); + return [$bodyStream, $params]; + } + )->wait(); + + $this->source->rewind(); + $this->config['params'] = $params; + }; + } +}
\ No newline at end of file diff --git a/vendor/aws/aws-sdk-php/src/S3/Crypto/S3EncryptionMultipartUploaderV2.php b/vendor/aws/aws-sdk-php/src/S3/Crypto/S3EncryptionMultipartUploaderV2.php new file mode 100644 index 0000000..1bdbccf --- /dev/null +++ b/vendor/aws/aws-sdk-php/src/S3/Crypto/S3EncryptionMultipartUploaderV2.php @@ -0,0 +1,176 @@ +<?php +namespace Aws\S3\Crypto; + +use Aws\Crypto\AbstractCryptoClientV2; +use Aws\Crypto\EncryptionTraitV2; +use Aws\Crypto\MetadataEnvelope; +use Aws\Crypto\Cipher\CipherBuilderTrait; +use Aws\S3\MultipartUploader; +use Aws\S3\S3ClientInterface; +use GuzzleHttp\Promise; + +/** + * Encapsulates the execution of a multipart upload of an encrypted object to S3. + * + * Note that for PHP versions of < 7.1, this class uses an AES-GCM polyfill + * for encryption since there is no native PHP support. The performance for large + * inputs will be a lot slower than for PHP 7.1+, so upgrading older PHP version + * environments may be necessary to use this effectively. + */ +class S3EncryptionMultipartUploaderV2 extends MultipartUploader +{ + use CipherBuilderTrait; + use CryptoParamsTraitV2; + use EncryptionTraitV2; + use UserAgentTrait; + + CONST CRYPTO_VERSION = '2.1'; + + /** + * Returns if the passed cipher name is supported for encryption by the SDK. + * + * @param string $cipherName The name of a cipher to verify is registered. + * + * @return bool If the cipher passed is in our supported list. + */ + public static function isSupportedCipher($cipherName) + { + return in_array($cipherName, AbstractCryptoClientV2::$supportedCiphers); + } + + private $provider; + private $instructionFileSuffix; + private $strategy; + + /** + * Creates a multipart upload for an S3 object after encrypting it. + * + * Note that for PHP versions of < 7.1, this class uses an AES-GCM polyfill + * for encryption since there is no native PHP support. The performance for + * large inputs will be a lot slower than for PHP 7.1+, so upgrading older + * PHP version environments may be necessary to use this effectively. + * + * The required configuration options are as follows: + * + * - @MaterialsProvider: (MaterialsProviderV2) Provides Cek, Iv, and Cek + * encrypting/decrypting for encryption metadata. + * - @CipherOptions: (array) Cipher options for encrypting data. A Cipher + * is required. Accepts the following options: + * - Cipher: (string) gcm + * See also: AbstractCryptoClientV2::$supportedCiphers + * - KeySize: (int) 128|256 + * See also: MaterialsProvider::$supportedKeySizes + * - Aad: (string) Additional authentication data. This option is + * passed directly to OpenSSL when using gcm. + * - @KmsEncryptionContext: (array) Only required if using + * KmsMaterialsProviderV2. An associative array of key-value + * pairs to be added to the encryption context for KMS key encryption. An + * empty array may be passed if no additional context is desired. + * - bucket: (string) Name of the bucket to which the object is + * being uploaded. + * - key: (string) Key to use for the object being uploaded. + * + * The optional configuration arguments are as follows: + * + * - @MetadataStrategy: (MetadataStrategy|string|null) Strategy for storing + * MetadataEnvelope information. Defaults to using a + * HeadersMetadataStrategy. Can either be a class implementing + * MetadataStrategy, a class name of a predefined strategy, or empty/null + * to default. + * - @InstructionFileSuffix: (string|null) Suffix used when writing to an + * instruction file if an using an InstructionFileMetadataHandler was + * determined. + * - acl: (string) ACL to set on the object being upload. Objects are + * private by default. + * - before_complete: (callable) Callback to invoke before the + * `CompleteMultipartUpload` operation. The callback should have a + * function signature like `function (Aws\Command $command) {...}`. + * - before_initiate: (callable) Callback to invoke before the + * `CreateMultipartUpload` operation. The callback should have a function + * signature like `function (Aws\Command $command) {...}`. + * - before_upload: (callable) Callback to invoke before any `UploadPart` + * operations. The callback should have a function signature like + * `function (Aws\Command $command) {...}`. + * - concurrency: (int, default=int(5)) Maximum number of concurrent + * `UploadPart` operations allowed during the multipart upload. + * - params: (array) An array of key/value parameters that will be applied + * to each of the sub-commands run by the uploader as a base. + * Auto-calculated options will override these parameters. If you need + * more granularity over parameters to each sub-command, use the before_* + * options detailed above to update the commands directly. + * - part_size: (int, default=int(5242880)) Part size, in bytes, to use when + * doing a multipart upload. This must between 5 MB and 5 GB, inclusive. + * - state: (Aws\Multipart\UploadState) An object that represents the state + * of the multipart upload and that is used to resume a previous upload. + * When this option is provided, the `bucket`, `key`, and `part_size` + * options are ignored. + * + * @param S3ClientInterface $client Client used for the upload. + * @param mixed $source Source of the data to upload. + * @param array $config Configuration used to perform the upload. + */ + public function __construct( + S3ClientInterface $client, + $source, + array $config = [] + ) { + $this->appendUserAgent($client, 'feat/s3-encrypt/' . self::CRYPTO_VERSION); + $this->client = $client; + $config['params'] = []; + if (!empty($config['bucket'])) { + $config['params']['Bucket'] = $config['bucket']; + } + if (!empty($config['key'])) { + $config['params']['Key'] = $config['key']; + } + + $this->provider = $this->getMaterialsProvider($config); + unset($config['@MaterialsProvider']); + + $this->instructionFileSuffix = $this->getInstructionFileSuffix($config); + unset($config['@InstructionFileSuffix']); + $this->strategy = $this->getMetadataStrategy( + $config, + $this->instructionFileSuffix + ); + if ($this->strategy === null) { + $this->strategy = self::getDefaultStrategy(); + } + unset($config['@MetadataStrategy']); + + $config['prepare_data_source'] = $this->getEncryptingDataPreparer(); + + parent::__construct($client, $source, $config); + } + + private static function getDefaultStrategy() + { + return new HeadersMetadataStrategy(); + } + + private function getEncryptingDataPreparer() + { + return function() { + // Defer encryption work until promise is executed + $envelope = new MetadataEnvelope(); + + list($this->source, $params) = Promise\Create::promiseFor($this->encrypt( + $this->source, + $this->config ?: [], + $this->provider, + $envelope + ))->then( + function ($bodyStream) use ($envelope) { + $params = $this->strategy->save( + $envelope, + $this->config['params'] + ); + return [$bodyStream, $params]; + } + )->wait(); + + $this->source->rewind(); + $this->config['params'] = $params; + }; + } +} diff --git a/vendor/aws/aws-sdk-php/src/S3/Crypto/UserAgentTrait.php b/vendor/aws/aws-sdk-php/src/S3/Crypto/UserAgentTrait.php new file mode 100644 index 0000000..4566275 --- /dev/null +++ b/vendor/aws/aws-sdk-php/src/S3/Crypto/UserAgentTrait.php @@ -0,0 +1,31 @@ +<?php +namespace Aws\S3\Crypto; + +use Aws\AwsClientInterface; +use Aws\Middleware; +use Psr\Http\Message\RequestInterface; + +trait UserAgentTrait +{ + private function appendUserAgent(AwsClientInterface $client, $agentString) + { + $list = $client->getHandlerList(); + $list->appendBuild(Middleware::mapRequest( + function(RequestInterface $req) use ($agentString) { + if (!empty($req->getHeader('User-Agent')) + && !empty($req->getHeader('User-Agent')[0]) + ) { + $userAgent = $req->getHeader('User-Agent')[0]; + if (strpos($userAgent, $agentString) === false) { + $userAgent .= " {$agentString}"; + }; + } else { + $userAgent = $agentString; + } + + $req = $req->withHeader('User-Agent', $userAgent); + return $req; + } + )); + } +} |