PluginProbe ʕ •ᴥ•ʔ
Transferito: WP Migration / trunk
Transferito: WP Migration vtrunk
trunk 11.4.0 12.0.0 13.1.0 14.0.0 14.0.11 14.0.7 14.1.0 14.1.1 14.1.2 14.1.3 14.1.4
transferito / vendor / aws / aws-sdk-php / src / S3 / Crypto / S3EncryptionClient.php
transferito / vendor / aws / aws-sdk-php / src / S3 / Crypto Last commit date
CryptoParamsTrait.php 11 months ago CryptoParamsTraitV2.php 11 months ago HeadersMetadataStrategy.php 11 months ago InstructionFileMetadataStrategy.php 11 months ago S3EncryptionClient.php 11 months ago S3EncryptionClientV2.php 11 months ago S3EncryptionMultipartUploader.php 11 months ago S3EncryptionMultipartUploaderV2.php 11 months ago UserAgentTrait.php 11 months ago
S3EncryptionClient.php
341 lines
1 <?php
2 namespace Aws\S3\Crypto;
3
4 use Aws\Crypto\DecryptionTrait;
5 use Aws\HashingStream;
6 use Aws\PhpHash;
7 use Aws\Crypto\AbstractCryptoClient;
8 use Aws\Crypto\EncryptionTrait;
9 use Aws\Crypto\MetadataEnvelope;
10 use Aws\Crypto\MaterialsProvider;
11 use Aws\Crypto\Cipher\CipherBuilderTrait;
12 use Aws\S3\S3Client;
13 use GuzzleHttp\Promise;
14 use GuzzleHttp\Promise\PromiseInterface;
15 use GuzzleHttp\Psr7;
16
17 /**
18 * Provides a wrapper for an S3Client that supplies functionality to encrypt
19 * data on putObject[Async] calls and decrypt data on getObject[Async] calls.
20 *
21 * Legacy implementation using older encryption workflow.
22 *
23 * AWS strongly recommends the upgrade to the S3EncryptionClientV2 (over the
24 * S3EncryptionClient), as it offers updated data security best practices to our
25 * customers who upgrade. S3EncryptionClientV2 contains breaking changes, so this
26 * will require planning by engineering teams to migrate. New workflows should
27 * just start with S3EncryptionClientV2.
28 *
29 * @deprecated
30 */
31 class S3EncryptionClient extends AbstractCryptoClient
32 {
33 use CipherBuilderTrait;
34 use CryptoParamsTrait;
35 use DecryptionTrait;
36 use EncryptionTrait;
37 use UserAgentTrait;
38
39 const CRYPTO_VERSION = '1n';
40
41 private $client;
42 private $instructionFileSuffix;
43
44 /**
45 * @param S3Client $client The S3Client to be used for true uploading and
46 * retrieving objects from S3 when using the
47 * encryption client.
48 * @param string|null $instructionFileSuffix Suffix for a client wide
49 * default when using instruction
50 * files for metadata storage.
51 */
52 public function __construct(
53 S3Client $client,
54 $instructionFileSuffix = null
55 ) {
56 $this->appendUserAgent($client, 'feat/s3-encrypt/' . self::CRYPTO_VERSION);
57 $this->client = $client;
58 $this->instructionFileSuffix = $instructionFileSuffix;
59 }
60
61 private static function getDefaultStrategy()
62 {
63 return new HeadersMetadataStrategy();
64 }
65
66 /**
67 * Encrypts the data in the 'Body' field of $args and promises to upload it
68 * to the specified location on S3.
69 *
70 * @param array $args Arguments for encrypting an object and uploading it
71 * to S3 via PutObject.
72 *
73 * The required configuration arguments are as follows:
74 *
75 * - @MaterialsProvider: (MaterialsProvider) Provides Cek, Iv, and Cek
76 * encrypting/decrypting for encryption metadata.
77 * - @CipherOptions: (array) Cipher options for encrypting data. Only the
78 * Cipher option is required. Accepts the following:
79 * - Cipher: (string) cbc|gcm
80 * See also: AbstractCryptoClient::$supportedCiphers. Note that
81 * cbc is deprecated and gcm should be used when possible.
82 * - KeySize: (int) 128|192|256
83 * See also: MaterialsProvider::$supportedKeySizes
84 * - Aad: (string) Additional authentication data. This option is
85 * passed directly to OpenSSL when using gcm. It is ignored when
86 * using cbc. Note if you pass in Aad for gcm encryption, the
87 * PHP SDK will be able to decrypt the resulting object, but other
88 * AWS SDKs may not be able to do so.
89 *
90 * The optional configuration arguments are as follows:
91 *
92 * - @MetadataStrategy: (MetadataStrategy|string|null) Strategy for storing
93 * MetadataEnvelope information. Defaults to using a
94 * HeadersMetadataStrategy. Can either be a class implementing
95 * MetadataStrategy, a class name of a predefined strategy, or empty/null
96 * to default.
97 * - @InstructionFileSuffix: (string|null) Suffix used when writing to an
98 * instruction file if using an InstructionFileMetadataHandler.
99 *
100 * @return PromiseInterface
101 *
102 * @throws \InvalidArgumentException Thrown when arguments above are not
103 * passed or are passed incorrectly.
104 */
105 public function putObjectAsync(array $args)
106 {
107 $provider = $this->getMaterialsProvider($args);
108 unset($args['@MaterialsProvider']);
109
110 $instructionFileSuffix = $this->getInstructionFileSuffix($args);
111 unset($args['@InstructionFileSuffix']);
112
113 $strategy = $this->getMetadataStrategy($args, $instructionFileSuffix);
114 unset($args['@MetadataStrategy']);
115
116 $envelope = new MetadataEnvelope();
117
118 return Promise\Create::promiseFor($this->encrypt(
119 Psr7\Utils::streamFor($args['Body']),
120 $args['@CipherOptions'] ?: [],
121 $provider,
122 $envelope
123 ))->then(
124 function ($encryptedBodyStream) use ($args) {
125 $hash = new PhpHash('sha256');
126 $hashingEncryptedBodyStream = new HashingStream(
127 $encryptedBodyStream,
128 $hash,
129 self::getContentShaDecorator($args)
130 );
131 return [$hashingEncryptedBodyStream, $args];
132 }
133 )->then(
134 function ($putObjectContents) use ($strategy, $envelope) {
135 list($bodyStream, $args) = $putObjectContents;
136 if ($strategy === null) {
137 $strategy = self::getDefaultStrategy();
138 }
139
140 $updatedArgs = $strategy->save($envelope, $args);
141 $updatedArgs['Body'] = $bodyStream;
142 return $updatedArgs;
143 }
144 )->then(
145 function ($args) {
146 unset($args['@CipherOptions']);
147 return $this->client->putObjectAsync($args);
148 }
149 );
150 }
151
152 private static function getContentShaDecorator(&$args)
153 {
154 return function ($hash) use (&$args) {
155 $args['ContentSHA256'] = bin2hex($hash);
156 };
157 }
158
159 /**
160 * Encrypts the data in the 'Body' field of $args and uploads it to the
161 * specified location on S3.
162 *
163 * @param array $args Arguments for encrypting an object and uploading it
164 * to S3 via PutObject.
165 *
166 * The required configuration arguments are as follows:
167 *
168 * - @MaterialsProvider: (MaterialsProvider) Provides Cek, Iv, and Cek
169 * encrypting/decrypting for encryption metadata.
170 * - @CipherOptions: (array) Cipher options for encrypting data. A Cipher
171 * is required. Accepts the following options:
172 * - Cipher: (string) cbc|gcm
173 * See also: AbstractCryptoClient::$supportedCiphers. Note that
174 * cbc is deprecated and gcm should be used when possible.
175 * - KeySize: (int) 128|192|256
176 * See also: MaterialsProvider::$supportedKeySizes
177 * - Aad: (string) Additional authentication data. This option is
178 * passed directly to OpenSSL when using gcm. It is ignored when
179 * using cbc. Note if you pass in Aad for gcm encryption, the
180 * PHP SDK will be able to decrypt the resulting object, but other
181 * AWS SDKs may not be able to do so.
182 *
183 * The optional configuration arguments are as follows:
184 *
185 * - @MetadataStrategy: (MetadataStrategy|string|null) Strategy for storing
186 * MetadataEnvelope information. Defaults to using a
187 * HeadersMetadataStrategy. Can either be a class implementing
188 * MetadataStrategy, a class name of a predefined strategy, or empty/null
189 * to default.
190 * - @InstructionFileSuffix: (string|null) Suffix used when writing to an
191 * instruction file if an using an InstructionFileMetadataHandler was
192 * determined.
193 *
194 * @return \Aws\Result PutObject call result with the details of uploading
195 * the encrypted file.
196 *
197 * @throws \InvalidArgumentException Thrown when arguments above are not
198 * passed or are passed incorrectly.
199 */
200 public function putObject(array $args)
201 {
202 return $this->putObjectAsync($args)->wait();
203 }
204
205 /**
206 * Promises to retrieve an object from S3 and decrypt the data in the
207 * 'Body' field.
208 *
209 * @param array $args Arguments for retrieving an object from S3 via
210 * GetObject and decrypting it.
211 *
212 * The required configuration argument is as follows:
213 *
214 * - @MaterialsProvider: (MaterialsProvider) Provides Cek, Iv, and Cek
215 * encrypting/decrypting for decryption metadata. May have data loaded
216 * from the MetadataEnvelope upon decryption.
217 *
218 * The optional configuration arguments are as follows:
219 *
220 * - SaveAs: (string) The path to a file on disk to save the decrypted
221 * object data. This will be handled by file_put_contents instead of the
222 * Guzzle sink.
223 *
224 * - @MetadataStrategy: (MetadataStrategy|string|null) Strategy for reading
225 * MetadataEnvelope information. Defaults to determining based on object
226 * response headers. Can either be a class implementing MetadataStrategy,
227 * a class name of a predefined strategy, or empty/null to default.
228 * - @InstructionFileSuffix: (string) Suffix used when looking for an
229 * instruction file if an InstructionFileMetadataHandler is being used.
230 * - @CipherOptions: (array) Cipher options for decrypting data. A Cipher
231 * is required. Accepts the following options:
232 * - Aad: (string) Additional authentication data. This option is
233 * passed directly to OpenSSL when using gcm. It is ignored when
234 * using cbc.
235 *
236 * @return PromiseInterface
237 *
238 * @throws \InvalidArgumentException Thrown when required arguments are not
239 * passed or are passed incorrectly.
240 */
241 public function getObjectAsync(array $args)
242 {
243 $provider = $this->getMaterialsProvider($args);
244 unset($args['@MaterialsProvider']);
245
246 $instructionFileSuffix = $this->getInstructionFileSuffix($args);
247 unset($args['@InstructionFileSuffix']);
248
249 $strategy = $this->getMetadataStrategy($args, $instructionFileSuffix);
250 unset($args['@MetadataStrategy']);
251
252 $saveAs = null;
253 if (!empty($args['SaveAs'])) {
254 $saveAs = $args['SaveAs'];
255 }
256
257 $promise = $this->client->getObjectAsync($args)
258 ->then(
259 function ($result) use (
260 $provider,
261 $instructionFileSuffix,
262 $strategy,
263 $args
264 ) {
265 if ($strategy === null) {
266 $strategy = $this->determineGetObjectStrategy(
267 $result,
268 $instructionFileSuffix
269 );
270 }
271
272 $envelope = $strategy->load($args + [
273 'Metadata' => $result['Metadata']
274 ]);
275
276 $provider = $provider->fromDecryptionEnvelope($envelope);
277
278 $result['Body'] = $this->decrypt(
279 $result['Body'],
280 $provider,
281 $envelope,
282 isset($args['@CipherOptions'])
283 ? $args['@CipherOptions']
284 : []
285 );
286 return $result;
287 }
288 )->then(
289 function ($result) use ($saveAs) {
290 if (!empty($saveAs)) {
291 file_put_contents(
292 $saveAs,
293 (string)$result['Body'],
294 LOCK_EX
295 );
296 }
297 return $result;
298 }
299 );
300
301 return $promise;
302 }
303
304 /**
305 * Retrieves an object from S3 and decrypts the data in the 'Body' field.
306 *
307 * @param array $args Arguments for retrieving an object from S3 via
308 * GetObject and decrypting it.
309 *
310 * The required configuration argument is as follows:
311 *
312 * - @MaterialsProvider: (MaterialsProvider) Provides Cek, Iv, and Cek
313 * encrypting/decrypting for decryption metadata. May have data loaded
314 * from the MetadataEnvelope upon decryption.
315 *
316 * The optional configuration arguments are as follows:
317 *
318 * - SaveAs: (string) The path to a file on disk to save the decrypted
319 * object data. This will be handled by file_put_contents instead of the
320 * Guzzle sink.
321 * - @InstructionFileSuffix: (string|null) Suffix used when looking for an
322 * instruction file if an InstructionFileMetadataHandler was detected.
323 * - @CipherOptions: (array) Cipher options for encrypting data. A Cipher
324 * is required. Accepts the following options:
325 * - Aad: (string) Additional authentication data. This option is
326 * passed directly to OpenSSL when using gcm. It is ignored when
327 * using cbc.
328 *
329 * @return \Aws\Result GetObject call result with the 'Body' field
330 * wrapped in a decryption stream with its metadata
331 * information.
332 *
333 * @throws \InvalidArgumentException Thrown when arguments above are not
334 * passed or are passed incorrectly.
335 */
336 public function getObject(array $args)
337 {
338 return $this->getObjectAsync($args)->wait();
339 }
340 }
341