S3EncryptionMultipartUploader.php 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. <?php
  2. namespace Aws\S3\Crypto;
  3. use Aws\Crypto\AbstractCryptoClient;
  4. use Aws\Crypto\EncryptionTrait;
  5. use Aws\Crypto\MetadataEnvelope;
  6. use Aws\Crypto\Cipher\CipherBuilderTrait;
  7. use Aws\S3\MultipartUploader;
  8. use Aws\S3\S3ClientInterface;
  9. use GuzzleHttp\Promise;
  10. /**
  11. * Encapsulates the execution of a multipart upload of an encrypted object to S3.
  12. *
  13. * Legacy implementation using older encryption workflow. Use
  14. * S3EncryptionMultipartUploaderV2 if possible.
  15. *
  16. * @deprecated
  17. */
  18. class S3EncryptionMultipartUploader extends MultipartUploader
  19. {
  20. use CipherBuilderTrait;
  21. use CryptoParamsTrait;
  22. use EncryptionTrait;
  23. use UserAgentTrait;
  24. const CRYPTO_VERSION = '1n';
  25. /**
  26. * Returns if the passed cipher name is supported for encryption by the SDK.
  27. *
  28. * @param string $cipherName The name of a cipher to verify is registered.
  29. *
  30. * @return bool If the cipher passed is in our supported list.
  31. */
  32. public static function isSupportedCipher($cipherName)
  33. {
  34. return in_array($cipherName, AbstractCryptoClient::$supportedCiphers);
  35. }
  36. private $provider;
  37. private $instructionFileSuffix;
  38. private $strategy;
  39. /**
  40. * Creates a multipart upload for an S3 object after encrypting it.
  41. *
  42. * The required configuration options are as follows:
  43. *
  44. * - @MaterialsProvider: (MaterialsProvider) Provides Cek, Iv, and Cek
  45. * encrypting/decrypting for encryption metadata.
  46. * - @CipherOptions: (array) Cipher options for encrypting data. A Cipher
  47. * is required. Accepts the following options:
  48. * - Cipher: (string) cbc|gcm
  49. * See also: AbstractCryptoClient::$supportedCiphers. Note that
  50. * cbc is deprecated and gcm should be used when possible.
  51. * - KeySize: (int) 128|192|256
  52. * See also: MaterialsProvider::$supportedKeySizes
  53. * - Aad: (string) Additional authentication data. This option is
  54. * passed directly to OpenSSL when using gcm. It is ignored when
  55. * using cbc.
  56. * - bucket: (string) Name of the bucket to which the object is
  57. * being uploaded.
  58. * - key: (string) Key to use for the object being uploaded.
  59. *
  60. * The optional configuration arguments are as follows:
  61. *
  62. * - @MetadataStrategy: (MetadataStrategy|string|null) Strategy for storing
  63. * MetadataEnvelope information. Defaults to using a
  64. * HeadersMetadataStrategy. Can either be a class implementing
  65. * MetadataStrategy, a class name of a predefined strategy, or empty/null
  66. * to default.
  67. * - @InstructionFileSuffix: (string|null) Suffix used when writing to an
  68. * instruction file if an using an InstructionFileMetadataHandler was
  69. * determined.
  70. * - acl: (string) ACL to set on the object being upload. Objects are
  71. * private by default.
  72. * - before_complete: (callable) Callback to invoke before the
  73. * `CompleteMultipartUpload` operation. The callback should have a
  74. * function signature like `function (Aws\Command $command) {...}`.
  75. * - before_initiate: (callable) Callback to invoke before the
  76. * `CreateMultipartUpload` operation. The callback should have a function
  77. * signature like `function (Aws\Command $command) {...}`.
  78. * - before_upload: (callable) Callback to invoke before any `UploadPart`
  79. * operations. The callback should have a function signature like
  80. * `function (Aws\Command $command) {...}`.
  81. * - concurrency: (int, default=int(5)) Maximum number of concurrent
  82. * `UploadPart` operations allowed during the multipart upload.
  83. * - params: (array) An array of key/value parameters that will be applied
  84. * to each of the sub-commands run by the uploader as a base.
  85. * Auto-calculated options will override these parameters. If you need
  86. * more granularity over parameters to each sub-command, use the before_*
  87. * options detailed above to update the commands directly.
  88. * - part_size: (int, default=int(5242880)) Part size, in bytes, to use when
  89. * doing a multipart upload. This must between 5 MB and 5 GB, inclusive.
  90. * - state: (Aws\Multipart\UploadState) An object that represents the state
  91. * of the multipart upload and that is used to resume a previous upload.
  92. * When this option is provided, the `bucket`, `key`, and `part_size`
  93. * options are ignored.
  94. *
  95. * @param S3ClientInterface $client Client used for the upload.
  96. * @param mixed $source Source of the data to upload.
  97. * @param array $config Configuration used to perform the upload.
  98. */
  99. public function __construct(
  100. S3ClientInterface $client,
  101. $source,
  102. array $config = []
  103. ) {
  104. $this->appendUserAgent($client, 'feat/s3-encrypt/' . self::CRYPTO_VERSION);
  105. $this->client = $client;
  106. $config['params'] = [];
  107. if (!empty($config['bucket'])) {
  108. $config['params']['Bucket'] = $config['bucket'];
  109. }
  110. if (!empty($config['key'])) {
  111. $config['params']['Key'] = $config['key'];
  112. }
  113. $this->provider = $this->getMaterialsProvider($config);
  114. unset($config['@MaterialsProvider']);
  115. $this->instructionFileSuffix = $this->getInstructionFileSuffix($config);
  116. unset($config['@InstructionFileSuffix']);
  117. $this->strategy = $this->getMetadataStrategy(
  118. $config,
  119. $this->instructionFileSuffix
  120. );
  121. if ($this->strategy === null) {
  122. $this->strategy = self::getDefaultStrategy();
  123. }
  124. unset($config['@MetadataStrategy']);
  125. $config['prepare_data_source'] = $this->getEncryptingDataPreparer();
  126. parent::__construct($client, $source, $config);
  127. }
  128. private static function getDefaultStrategy()
  129. {
  130. return new HeadersMetadataStrategy();
  131. }
  132. private function getEncryptingDataPreparer()
  133. {
  134. return function() {
  135. // Defer encryption work until promise is executed
  136. $envelope = new MetadataEnvelope();
  137. list($this->source, $params) = Promise\Create::promiseFor($this->encrypt(
  138. $this->source,
  139. $this->config['@cipheroptions'] ?: [],
  140. $this->provider,
  141. $envelope
  142. ))->then(
  143. function ($bodyStream) use ($envelope) {
  144. $params = $this->strategy->save(
  145. $envelope,
  146. $this->config['params']
  147. );
  148. return [$bodyStream, $params];
  149. }
  150. )->wait();
  151. $this->source->rewind();
  152. $this->config['params'] = $params;
  153. };
  154. }
  155. }