PluginProbe
Media Cloud Sync / 1.3.11
Media Cloud Sync v1.3.11
1.4.1 1.4.0 1.3.12 1.3.11 1.3.10 trunk 1.0.0 1.0.1 1.0.2 1.0.3 1.1.0 1.1.1 1.2.0 1.2.10 1.2.11 1.2.12 1.2.13 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.2.7 1.2.8 1.2.9 All 35 releases
media-cloud-sync / includes / sdk / s3 / Aws / S3 / Crypto / S3EncryptionClient.php

S3EncryptionClient.php in Media Cloud Sync 1.3.11, at includes/sdk/s3/Aws/S3/Crypto/S3EncryptionClient.php

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