PluginProbe
Media Cloud Sync / 1.2.10
Media Cloud Sync v1.2.10
1.4.2 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 All 36 releases
media-cloud-sync / includes / sdk / s3 / Aws / S3 / Crypto / S3EncryptionClient.php

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

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