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 / Crypto / DecryptionTraitV2.php
transferito / vendor / aws / aws-sdk-php / src / Crypto Last commit date
Cipher 11 months ago Polyfill 11 months ago AbstractCryptoClient.php 11 months ago AbstractCryptoClientV2.php 11 months ago AesDecryptingStream.php 11 months ago AesEncryptingStream.php 11 months ago AesGcmDecryptingStream.php 11 months ago AesGcmEncryptingStream.php 11 months ago AesStreamInterface.php 11 months ago AesStreamInterfaceV2.php 11 months ago DecryptionTrait.php 11 months ago DecryptionTraitV2.php 11 months ago EncryptionTrait.php 11 months ago EncryptionTraitV2.php 11 months ago KmsMaterialsProvider.php 11 months ago KmsMaterialsProviderV2.php 11 months ago MaterialsProvider.php 11 months ago MaterialsProviderInterface.php 11 months ago MaterialsProviderInterfaceV2.php 11 months ago MaterialsProviderV2.php 11 months ago MetadataEnvelope.php 11 months ago MetadataStrategyInterface.php 11 months ago
DecryptionTraitV2.php
250 lines
1 <?php
2 namespace Aws\Crypto;
3
4 use Aws\Exception\CryptoException;
5 use GuzzleHttp\Psr7;
6 use GuzzleHttp\Psr7\LimitStream;
7 use Psr\Http\Message\StreamInterface;
8
9 trait DecryptionTraitV2
10 {
11 /**
12 * Dependency to reverse lookup the openssl_* cipher name from the AESName
13 * in the MetadataEnvelope.
14 *
15 * @param $aesName
16 *
17 * @return string
18 *
19 * @internal
20 */
21 abstract protected function getCipherFromAesName($aesName);
22
23 /**
24 * Dependency to generate a CipherMethod from a set of inputs for loading
25 * in to an AesDecryptingStream.
26 *
27 * @param string $cipherName Name of the cipher to generate for decrypting.
28 * @param string $iv Base Initialization Vector for the cipher.
29 * @param int $keySize Size of the encryption key, in bits, that will be
30 * used.
31 *
32 * @return Cipher\CipherMethod
33 *
34 * @internal
35 */
36 abstract protected function buildCipherMethod($cipherName, $iv, $keySize);
37
38 /**
39 * Builds an AesStreamInterface using cipher options loaded from the
40 * MetadataEnvelope and MaterialsProvider. Can decrypt data from both the
41 * legacy and V2 encryption client workflows.
42 *
43 * @param string $cipherText Plain-text data to be encrypted using the
44 * materials, algorithm, and data provided.
45 * @param MaterialsProviderInterfaceV2 $provider A provider to supply and encrypt
46 * materials used in encryption.
47 * @param MetadataEnvelope $envelope A storage envelope for encryption
48 * metadata to be read from.
49 * @param array $options Options used for decryption.
50 *
51 * @return AesStreamInterface
52 *
53 * @throws \InvalidArgumentException Thrown when a value in $cipherOptions
54 * is not valid.
55 *
56 * @internal
57 */
58 public function decrypt(
59 $cipherText,
60 MaterialsProviderInterfaceV2 $provider,
61 MetadataEnvelope $envelope,
62 array $options = []
63 ) {
64 $options['@CipherOptions'] = !empty($options['@CipherOptions'])
65 ? $options['@CipherOptions']
66 : [];
67 $options['@CipherOptions']['Iv'] = base64_decode(
68 $envelope[MetadataEnvelope::IV_HEADER]
69 );
70
71 $options['@CipherOptions']['TagLength'] =
72 $envelope[MetadataEnvelope::CRYPTO_TAG_LENGTH_HEADER] / 8;
73
74 $cek = $provider->decryptCek(
75 base64_decode(
76 $envelope[MetadataEnvelope::CONTENT_KEY_V2_HEADER]
77 ),
78 json_decode(
79 $envelope[MetadataEnvelope::MATERIALS_DESCRIPTION_HEADER],
80 true
81 ),
82 $options
83 );
84 $options['@CipherOptions']['KeySize'] = strlen($cek) * 8;
85 $options['@CipherOptions']['Cipher'] = $this->getCipherFromAesName(
86 $envelope[MetadataEnvelope::CONTENT_CRYPTO_SCHEME_HEADER]
87 );
88
89 $this->validateOptionsAndEnvelope($options, $envelope);
90
91 $decryptionStream = $this->getDecryptingStream(
92 $cipherText,
93 $cek,
94 $options['@CipherOptions']
95 );
96 unset($cek);
97
98 return $decryptionStream;
99 }
100
101 private function getTagFromCiphertextStream(
102 StreamInterface $cipherText,
103 $tagLength
104 ) {
105 $cipherTextSize = $cipherText->getSize();
106 if ($cipherTextSize == null || $cipherTextSize <= 0) {
107 throw new \RuntimeException('Cannot decrypt a stream of unknown'
108 . ' size.');
109 }
110 return (string) new LimitStream(
111 $cipherText,
112 $tagLength,
113 $cipherTextSize - $tagLength
114 );
115 }
116
117 private function getStrippedCiphertextStream(
118 StreamInterface $cipherText,
119 $tagLength
120 ) {
121 $cipherTextSize = $cipherText->getSize();
122 if ($cipherTextSize == null || $cipherTextSize <= 0) {
123 throw new \RuntimeException('Cannot decrypt a stream of unknown'
124 . ' size.');
125 }
126 return new LimitStream(
127 $cipherText,
128 $cipherTextSize - $tagLength,
129 0
130 );
131 }
132
133 private function validateOptionsAndEnvelope($options, $envelope)
134 {
135 $allowedCiphers = AbstractCryptoClientV2::$supportedCiphers;
136 $allowedKeywraps = AbstractCryptoClientV2::$supportedKeyWraps;
137 if ($options['@SecurityProfile'] == 'V2_AND_LEGACY') {
138 $allowedCiphers = array_unique(array_merge(
139 $allowedCiphers,
140 AbstractCryptoClient::$supportedCiphers
141 ));
142 $allowedKeywraps = array_unique(array_merge(
143 $allowedKeywraps,
144 AbstractCryptoClient::$supportedKeyWraps
145 ));
146 }
147
148 $v1SchemaException = new CryptoException("The requested object is encrypted"
149 . " with V1 encryption schemas that have been disabled by"
150 . " client configuration @SecurityProfile=V2. Retry with"
151 . " V2_AND_LEGACY enabled or reencrypt the object.");
152
153 if (!in_array($options['@CipherOptions']['Cipher'], $allowedCiphers)) {
154 if (in_array($options['@CipherOptions']['Cipher'], AbstractCryptoClient::$supportedCiphers)) {
155 throw $v1SchemaException;
156 }
157 throw new CryptoException("The requested object is encrypted with"
158 . " the cipher '{$options['@CipherOptions']['Cipher']}', which is not"
159 . " supported for decryption with the selected security profile."
160 . " This profile allows decryption with: "
161 . implode(", ", $allowedCiphers));
162 }
163 if (!in_array(
164 $envelope[MetadataEnvelope::KEY_WRAP_ALGORITHM_HEADER],
165 $allowedKeywraps
166 )) {
167 if (in_array(
168 $envelope[MetadataEnvelope::KEY_WRAP_ALGORITHM_HEADER],
169 AbstractCryptoClient::$supportedKeyWraps)
170 ) {
171 throw $v1SchemaException;
172 }
173 throw new CryptoException("The requested object is encrypted with"
174 . " the keywrap schema '{$envelope[MetadataEnvelope::KEY_WRAP_ALGORITHM_HEADER]}',"
175 . " which is not supported for decryption with the current security"
176 . " profile.");
177 }
178
179 $matdesc = json_decode(
180 $envelope[MetadataEnvelope::MATERIALS_DESCRIPTION_HEADER],
181 true
182 );
183 if (isset($matdesc['aws:x-amz-cek-alg'])
184 && $envelope[MetadataEnvelope::CONTENT_CRYPTO_SCHEME_HEADER] !==
185 $matdesc['aws:x-amz-cek-alg']
186 ) {
187 throw new CryptoException("There is a mismatch in specified content"
188 . " encryption algrithm between the materials description value"
189 . " and the metadata envelope value: {$matdesc['aws:x-amz-cek-alg']}"
190 . " vs. {$envelope[MetadataEnvelope::CONTENT_CRYPTO_SCHEME_HEADER]}.");
191 }
192 }
193
194 /**
195 * Generates a stream that wraps the cipher text with the proper cipher and
196 * uses the content encryption key (CEK) to decrypt the data when read.
197 *
198 * @param string $cipherText Plain-text data to be encrypted using the
199 * materials, algorithm, and data provided.
200 * @param string $cek A content encryption key for use by the stream for
201 * encrypting the plaintext data.
202 * @param array $cipherOptions Options for use in determining the cipher to
203 * be used for encrypting data.
204 *
205 * @return AesStreamInterface
206 *
207 * @internal
208 */
209 protected function getDecryptingStream(
210 $cipherText,
211 $cek,
212 $cipherOptions
213 ) {
214 $cipherTextStream = Psr7\Utils::streamFor($cipherText);
215 switch ($cipherOptions['Cipher']) {
216 case 'gcm':
217 $cipherOptions['Tag'] = $this->getTagFromCiphertextStream(
218 $cipherTextStream,
219 $cipherOptions['TagLength']
220 );
221
222 return new AesGcmDecryptingStream(
223 $this->getStrippedCiphertextStream(
224 $cipherTextStream,
225 $cipherOptions['TagLength']
226 ),
227 $cek,
228 $cipherOptions['Iv'],
229 $cipherOptions['Tag'],
230 $cipherOptions['Aad'] = isset($cipherOptions['Aad'])
231 ? $cipherOptions['Aad']
232 : '',
233 $cipherOptions['TagLength'] ?: null,
234 $cipherOptions['KeySize']
235 );
236 default:
237 $cipherMethod = $this->buildCipherMethod(
238 $cipherOptions['Cipher'],
239 $cipherOptions['Iv'],
240 $cipherOptions['KeySize']
241 );
242 return new AesDecryptingStream(
243 $cipherTextStream,
244 $cek,
245 $cipherMethod
246 );
247 }
248 }
249 }
250