Failed Conditions
Push — v7 ( 137ba9...eb2dfc )
by Florent
03:53
created

JWEBuilder   D

Complexity

Total Complexity 70

Size/Duplication

Total Lines 525
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 14

Importance

Changes 0
Metric Value
wmc 70
lcom 1
cbo 14
dl 0
loc 525
rs 4.1333
c 0
b 0
f 0

27 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 1
A getSupportedKeyEncryptionAlgorithms() 0 4 1
A getSupportedContentEncryptionAlgorithms() 0 4 1
A getSupportedCompressionMethods() 0 4 1
A withPayload() 0 7 1
A withAAD() 0 7 1
A withSharedProtectedHeaders() 0 11 2
A withSharedHeaders() 0 11 2
C addRecipient() 0 36 8
B build() 0 26 6
A checkAndSetContentEncryptionAlgorithm() 0 9 3
A processRecipient() 0 14 3
A encryptJWE() 0 11 2
B preparePayload() 0 17 5
B getEncryptedKey() 0 16 6
A getEncryptedKeyFromKeyAgreementAndKeyWrappingAlgorithm() 0 4 1
A getEncryptedKeyFromKeyEncryptionAlgorithm() 0 4 1
A getEncryptedKeyFromKeyWrappingAlgorithm() 0 4 1
A checkKey() 0 9 2
C determineCEK() 0 32 8
A getCompressionMethod() 0 8 2
A areKeyManagementModesCompatible() 0 14 2
A createCEK() 0 4 1
A createIV() 0 4 1
A getKeyEncryptionAlgorithm() 0 12 3
A getContentEncryptionAlgorithm() 0 12 3
A checkDuplicatedHeaderParameters() 0 7 2

How to fix   Complexity   

Complex Class

Complex classes like JWEBuilder often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use JWEBuilder, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * The MIT License (MIT)
7
 *
8
 * Copyright (c) 2014-2017 Spomky-Labs
9
 *
10
 * This software may be modified and distributed under the terms
11
 * of the MIT license.  See the LICENSE file for details.
12
 */
13
14
namespace Jose\Component\Encryption;
15
16
use Base64Url\Base64Url;
17
use Jose\Component\Core\JWAManager;
18
use Jose\Component\Core\JWK;
19
use Jose\Component\Core\KeyChecker;
20
use Jose\Component\Encryption\Algorithm\ContentEncryptionAlgorithmInterface;
21
use Jose\Component\Encryption\Algorithm\KeyEncryption\DirectEncryptionInterface;
22
use Jose\Component\Encryption\Algorithm\KeyEncryption\KeyAgreementInterface;
23
use Jose\Component\Encryption\Algorithm\KeyEncryption\KeyAgreementWrappingInterface;
24
use Jose\Component\Encryption\Algorithm\KeyEncryption\KeyEncryptionInterface;
25
use Jose\Component\Encryption\Algorithm\KeyEncryption\KeyWrappingInterface;
26
use Jose\Component\Encryption\Algorithm\KeyEncryptionAlgorithmInterface;
27
use Jose\Component\Encryption\Compression\CompressionInterface;
28
use Jose\Component\Encryption\Compression\CompressionMethodsManager;
29
30
final class JWEBuilder
31
{
32
    /**
33
     * @var mixed
34
     */
35
    private $payload;
36
37
    /**
38
     * @var string|null
39
     */
40
    private $aad;
41
42
    /**
43
     * @var Recipient[]
44
     */
45
    private $recipients = [];
46
47
    /**
48
     * @var JWAManager
49
     */
50
    private $keyEncryptionAlgorithmManager;
51
52
    /**
53
     * @var JWAManager
54
     */
55
    private $contentEncryptionAlgorithmManager;
56
57
    /**
58
     * @var CompressionMethodsManager
59
     */
60
    private $compressionManager;
61
62
    /**
63
     * @var array
64
     */
65
    private $sharedProtectedHeaders = [];
66
67
    /**
68
     * @var array
69
     */
70
    private $sharedHeaders = [];
71
72
    /**
73
     * @var null|CompressionInterface
74
     */
75
    private $compressionMethod = null;
76
77
    /**
78
     * @var null|ContentEncryptionAlgorithmInterface
79
     */
80
    private $contentEncryptionAlgorithm = null;
81
82
    /**
83
     * @var null|string
84
     */
85
    private $keyManagementMode = null;
86
87
    /**
88
     * JWEBuilder constructor.
89
     *
90
     * @param JWAManager                $keyEncryptionAlgorithmManager
91
     * @param JWAManager                $contentEncryptionAlgorithmManager
92
     * @param CompressionMethodsManager $compressionManager
93
     */
94
    public function __construct(JWAManager $keyEncryptionAlgorithmManager, JWAManager $contentEncryptionAlgorithmManager, CompressionMethodsManager $compressionManager)
95
    {
96
        $this->keyEncryptionAlgorithmManager = $keyEncryptionAlgorithmManager;
97
        $this->contentEncryptionAlgorithmManager = $contentEncryptionAlgorithmManager;
98
        $this->compressionManager = $compressionManager;
99
    }
100
101
    /**
102
     * @return string[]
103
     */
104
    public function getSupportedKeyEncryptionAlgorithms(): array
105
    {
106
        return $this->keyEncryptionAlgorithmManager->list();
107
    }
108
109
    /**
110
     * @return string[]
111
     */
112
    public function getSupportedContentEncryptionAlgorithms(): array
113
    {
114
        return $this->contentEncryptionAlgorithmManager->list();
115
    }
116
117
    /**
118
     * @return string[]
119
     */
120
    public function getSupportedCompressionMethods(): array
121
    {
122
        return $this->compressionManager->list();
123
    }
124
125
    /**
126
     * @param mixed $payload
127
     *
128
     * @return JWEBuilder
129
     */
130
    public function withPayload($payload): JWEBuilder
131
    {
132
        $clone = clone $this;
133
        $clone->payload = $payload;
134
135
        return $clone;
136
    }
137
138
    /**
139
     * @param string|null $aad
140
     *
141
     * @return JWEBuilder
142
     */
143
    public function withAAD(?string $aad): JWEBuilder
144
    {
145
        $clone = clone $this;
146
        $clone->aad = $aad;
147
148
        return $clone;
149
    }
150
151
    /**
152
     * @param array $sharedProtectedHeaders
153
     *
154
     * @return JWEBuilder
155
     */
156
    public function withSharedProtectedHeaders(array $sharedProtectedHeaders): JWEBuilder
157
    {
158
        $this->checkDuplicatedHeaderParameters($sharedProtectedHeaders, $this->sharedHeaders);
159
        foreach ($this->recipients as $recipient) {
160
            $this->checkDuplicatedHeaderParameters($sharedProtectedHeaders, $recipient->getHeaders());
161
        }
162
        $clone = clone $this;
163
        $clone->sharedProtectedHeaders = $sharedProtectedHeaders;
164
165
        return $clone;
166
    }
167
168
    /**
169
     * @param array $sharedHeaders
170
     *
171
     * @return JWEBuilder
172
     */
173
    public function withSharedHeaders(array $sharedHeaders): JWEBuilder
174
    {
175
        $this->checkDuplicatedHeaderParameters($this->sharedProtectedHeaders, $sharedHeaders);
176
        foreach ($this->recipients as $recipient) {
177
            $this->checkDuplicatedHeaderParameters($sharedHeaders, $recipient->getHeaders());
178
        }
179
        $clone = clone $this;
180
        $clone->sharedHeaders = $sharedHeaders;
181
182
        return $clone;
183
    }
184
185
    /**
186
     * @param JWK   $recipientKey
187
     * @param array $recipientHeaders
188
     *
189
     * @return JWEBuilder
190
     */
191
    public function addRecipient(JWK $recipientKey, array $recipientHeaders = []): JWEBuilder
192
    {
193
        $this->checkDuplicatedHeaderParameters($this->sharedProtectedHeaders, $recipientHeaders);
194
        $this->checkDuplicatedHeaderParameters($this->sharedHeaders, $recipientHeaders);
195
        $clone = clone $this;
196
        $completeHeaders = array_merge($clone->sharedHeaders, $recipientHeaders, $clone->sharedProtectedHeaders);
197
        $clone->checkAndSetContentEncryptionAlgorithm($completeHeaders);
198
        $keyEncryptionAlgorithm = $clone->getKeyEncryptionAlgorithm($completeHeaders);
199
        if (null === $clone->keyManagementMode) {
200
            $clone->keyManagementMode = $keyEncryptionAlgorithm->getKeyManagementMode();
201
        } else {
202
            if (!$clone->areKeyManagementModesCompatible($clone->keyManagementMode, $keyEncryptionAlgorithm->getKeyManagementMode())) {
203
                throw new \InvalidArgumentException('Foreign key management mode forbidden.');
204
            }
205
        }
206
207
        $compressionMethod = $clone->getCompressionMethod($completeHeaders);
208
        if (null !== $compressionMethod) {
209
            if (null === $clone->compressionMethod) {
210
                $clone->compressionMethod = $compressionMethod;
211
            } elseif ($clone->compressionMethod->name() !== $compressionMethod->name()) {
212
                throw new \InvalidArgumentException('Incompatible compression method.');
213
            }
214
        }
215
        if (null === $compressionMethod && null !== $clone->compressionMethod) {
216
            throw new \InvalidArgumentException('Inconsistent compression method.');
217
        }
218
        $clone->checkKey($keyEncryptionAlgorithm, $recipientKey);
219
        $clone->recipients[] = [
220
            'key' => $recipientKey,
221
            'headers' => $recipientHeaders,
222
            'key_encryption_algorithm' => $keyEncryptionAlgorithm,
223
        ];
224
225
        return $clone;
226
    }
227
228
    /**
229
     * @return JWE
230
     */
231
    public function build(): JWE
232
    {
233
        if (0 === count($this->recipients)) {
234
            throw new \LogicException('No recipient.');
235
        }
236
237
        $additionalHeaders = [];
238
        $cek = $this->determineCEK($additionalHeaders);
239
240
        $recipients = [];
241
        foreach ($this->recipients as $recipient) {
242
            $recipient = $this->processRecipient($recipient, $cek, $additionalHeaders);
0 ignored issues
show
Documentation introduced by
$recipient is of type object<Jose\Component\Encryption\Recipient>, but the function expects a array.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
243
            $recipients[] = $recipient;
244
        }
245
246
        if (!empty($additionalHeaders) && 1 === count($this->recipients)) {
247
            $sharedProtectedHeaders = array_merge($additionalHeaders, $this->sharedProtectedHeaders);
248
        } else {
249
            $sharedProtectedHeaders = $this->sharedProtectedHeaders;
250
        }
251
        $encodedSharedProtectedHeaders = empty($sharedProtectedHeaders) ? '' : Base64Url::encode(json_encode($sharedProtectedHeaders));
252
253
        list($ciphertext, $iv, $tag) = $this->encryptJWE($cek, $encodedSharedProtectedHeaders);
254
255
        return JWE::create($ciphertext, $iv, $this->aad, $tag, $this->sharedHeaders, $sharedProtectedHeaders, $encodedSharedProtectedHeaders, $recipients);
256
    }
257
258
    /**
259
     * @param array $completeHeaders
260
     */
261
    private function checkAndSetContentEncryptionAlgorithm(array $completeHeaders): void
262
    {
263
        $contentEncryptionAlgorithm = $this->getContentEncryptionAlgorithm($completeHeaders);
264
        if (null === $this->contentEncryptionAlgorithm) {
265
            $this->contentEncryptionAlgorithm = $contentEncryptionAlgorithm;
266
        } elseif ($contentEncryptionAlgorithm->name() !== $this->contentEncryptionAlgorithm->name()) {
267
            throw new \InvalidArgumentException('Inconsistent content encryption algorithm');
268
        }
269
    }
270
271
    /**
272
     * @param array  $recipient
273
     * @param string $cek
274
     * @param array  $additionalHeaders
275
     *
276
     * @return Recipient
277
     */
278
    private function processRecipient(array $recipient, string $cek, array &$additionalHeaders): Recipient
279
    {
280
        $completeHeaders = array_merge($this->sharedHeaders, $recipient['headers'], $this->sharedProtectedHeaders);
281
        /** @var KeyEncryptionAlgorithmInterface $keyEncryptionAlgorithm */
282
        $keyEncryptionAlgorithm = $recipient['key_encryption_algorithm'];
283
        $encryptedContentEncryptionKey = $this->getEncryptedKey($completeHeaders, $cek, $keyEncryptionAlgorithm, $additionalHeaders, $recipient['key']);
284
        $recipientHeaders = $recipient['headers'];
285
        if (!empty($additionalHeaders) && 1 !== count($this->recipients)) {
286
            $recipientHeaders = array_merge($recipientHeaders, $additionalHeaders);
287
            $additionalHeaders = [];
288
        }
289
290
        return Recipient::create($recipientHeaders, $encryptedContentEncryptionKey);
291
    }
292
293
    /**
294
     * @param string $cek
295
     * @param string $encodedSharedProtectedHeaders
296
     *
297
     * @return array
298
     */
299
    private function encryptJWE(string $cek, string $encodedSharedProtectedHeaders): array
300
    {
301
        $tag = null;
302
        $iv_size = $this->contentEncryptionAlgorithm->getIVSize();
303
        $iv = $this->createIV($iv_size);
304
        $payload = $this->preparePayload();
305
        $aad = $this->aad ? Base64Url::encode($this->aad) : null;
306
        $ciphertext = $this->contentEncryptionAlgorithm->encryptContent($payload, $cek, $iv, $aad, $encodedSharedProtectedHeaders, $tag);
307
308
        return [$ciphertext, $iv, $tag];
309
    }
310
311
    /**
312
     * @return string
313
     */
314
    private function preparePayload(): ?string
315
    {
316
        $prepared = is_string($this->payload) ? $this->payload : json_encode($this->payload);
317
        if (null === $prepared) {
318
            throw new \RuntimeException('The payload is empty or cannot encoded into JSON.');
319
        }
320
321
        if (null === $this->compressionMethod) {
322
            return $prepared;
323
        }
324
        $compressedPayload = $this->compressionMethod->compress($prepared);
325
        if (null === $compressedPayload) {
326
            throw new \RuntimeException('The payload cannot be compressed.');
327
        }
328
329
        return $compressedPayload;
330
    }
331
332
    /**
333
     * @param array                           $completeHeaders
334
     * @param string                          $cek
335
     * @param KeyEncryptionAlgorithmInterface $keyEncryptionAlgorithm
336
     * @param JWK                             $recipientKey
337
     * @param array                           $additionalHeaders
338
     *
339
     * @return string|null
340
     */
341
    private function getEncryptedKey(array $completeHeaders, string $cek, KeyEncryptionAlgorithmInterface $keyEncryptionAlgorithm, array &$additionalHeaders, JWK $recipientKey): ?string
342
    {
343
        if ($keyEncryptionAlgorithm instanceof KeyEncryptionInterface) {
344
            return $this->getEncryptedKeyFromKeyEncryptionAlgorithm($completeHeaders, $cek, $keyEncryptionAlgorithm, $recipientKey, $additionalHeaders);
345
        } elseif ($keyEncryptionAlgorithm instanceof KeyWrappingInterface) {
346
            return $this->getEncryptedKeyFromKeyWrappingAlgorithm($completeHeaders, $cek, $keyEncryptionAlgorithm, $recipientKey, $additionalHeaders);
347
        } elseif ($keyEncryptionAlgorithm instanceof KeyAgreementWrappingInterface) {
348
            return $this->getEncryptedKeyFromKeyAgreementAndKeyWrappingAlgorithm($completeHeaders, $cek, $keyEncryptionAlgorithm, $additionalHeaders, $recipientKey);
349
        } elseif ($keyEncryptionAlgorithm instanceof KeyAgreementInterface) {
350
            return null;
351
        } elseif ($keyEncryptionAlgorithm instanceof DirectEncryptionInterface) {
352
            return null;
353
        }
354
355
        throw new \InvalidArgumentException('Unsupported key encryption algorithm.');
356
    }
357
358
    /**
359
     * @param array                         $completeHeaders
360
     * @param string                        $cek
361
     * @param KeyAgreementWrappingInterface $keyEncryptionAlgorithm
362
     * @param array                         $additionalHeaders
363
     * @param JWK                           $recipientKey
364
     *
365
     * @return string
366
     */
367
    private function getEncryptedKeyFromKeyAgreementAndKeyWrappingAlgorithm(array $completeHeaders, string $cek, KeyAgreementWrappingInterface $keyEncryptionAlgorithm, array &$additionalHeaders, JWK $recipientKey): string
368
    {
369
        return $keyEncryptionAlgorithm->wrapAgreementKey($recipientKey, $cek, $this->contentEncryptionAlgorithm->getCEKSize(), $completeHeaders, $additionalHeaders);
370
    }
371
372
    /**
373
     * @param array                  $completeHeaders
374
     * @param string                 $cek
375
     * @param KeyEncryptionInterface $keyEncryptionAlgorithm
376
     * @param JWK                    $recipientKey
377
     * @param array                  $additionalHeaders
378
     *
379
     * @return string
380
     */
381
    private function getEncryptedKeyFromKeyEncryptionAlgorithm(array $completeHeaders, string $cek, KeyEncryptionInterface $keyEncryptionAlgorithm, JWK $recipientKey, array &$additionalHeaders): string
382
    {
383
        return $keyEncryptionAlgorithm->encryptKey($recipientKey, $cek, $completeHeaders, $additionalHeaders);
384
    }
385
386
    /**
387
     * @param array                $completeHeaders
388
     * @param string               $cek
389
     * @param KeyWrappingInterface $keyEncryptionAlgorithm
390
     * @param JWK                  $recipientKey
391
     * @param array                $additionalHeaders
392
     *
393
     * @return string
394
     */
395
    private function getEncryptedKeyFromKeyWrappingAlgorithm(array $completeHeaders, string $cek, KeyWrappingInterface $keyEncryptionAlgorithm, JWK $recipientKey, array &$additionalHeaders): string
396
    {
397
        return $keyEncryptionAlgorithm->wrapKey($recipientKey, $cek, $completeHeaders, $additionalHeaders);
398
    }
399
400
    /**
401
     * @param KeyEncryptionAlgorithmInterface $keyEncryptionAlgorithm
402
     * @param JWK                             $recipientKey
403
     */
404
    private function checkKey(KeyEncryptionAlgorithmInterface $keyEncryptionAlgorithm, JWK $recipientKey)
405
    {
406
        KeyChecker::checkKeyUsage($recipientKey, 'encryption');
407
        if ('dir' !== $keyEncryptionAlgorithm->name()) {
408
            KeyChecker::checkKeyAlgorithm($recipientKey, $keyEncryptionAlgorithm->name());
409
        } else {
410
            KeyChecker::checkKeyAlgorithm($recipientKey, $this->contentEncryptionAlgorithm->name());
411
        }
412
    }
413
414
    /**
415
     * @param array $additionalHeaders
416
     *
417
     * @return string
418
     */
419
    private function determineCEK(array &$additionalHeaders): string
420
    {
421
        switch ($this->keyManagementMode) {
422
            case KeyEncryptionInterface::MODE_ENCRYPT:
423
            case KeyEncryptionInterface::MODE_WRAP:
424
                return $this->createCEK($this->contentEncryptionAlgorithm->getCEKSize());
425
            case KeyEncryptionInterface::MODE_AGREEMENT:
426
                if (1 !== count($this->recipients)) {
427
                    throw new \LogicException('Unable to encrypt for multiple recipients using key agreement algorithms.');
428
                }
429
                /** @var JWK $key */
430
                $key = $this->recipients[0]['key'];
431
                /** @var KeyAgreementInterface $algorithm */
432
                $algorithm = $this->recipients[0]['key_encryption_algorithm'];
433
                $completeHeaders = array_merge($this->sharedHeaders, $this->recipients[0]['headers'], $this->sharedProtectedHeaders);
434
435
                return $algorithm->getAgreementKey($this->contentEncryptionAlgorithm->getCEKSize(), $this->contentEncryptionAlgorithm->name(), $key, $completeHeaders, $additionalHeaders);
436
            case KeyEncryptionInterface::MODE_DIRECT:
437
                if (1 !== count($this->recipients)) {
438
                    throw new \LogicException('Unable to encrypt for multiple recipients using key agreement algorithms.');
439
                }
440
                /** @var JWK $key */
441
                $key = $this->recipients[0]['key'];
442
                if ('oct' !== $key->get('kty')) {
443
                    throw new \RuntimeException('Wrong key type.');
444
                }
445
446
                return Base64Url::decode($key->get('k'));
447
            default:
448
                throw new \InvalidArgumentException(sprintf('Unsupported key management mode "%s".', $this->keyManagementMode));
449
        }
450
    }
451
452
    /**
453
     * @param array $completeHeaders
454
     *
455
     * @return CompressionInterface|null
456
     */
457
    private function getCompressionMethod(array $completeHeaders): ?CompressionInterface
458
    {
459
        if (!array_key_exists('zip', $completeHeaders)) {
460
            return null;
461
        }
462
463
        return $this->compressionManager->get($completeHeaders['zip']);
464
    }
465
466
    /**
467
     * @param string $current
468
     * @param string $new
469
     *
470
     * @return bool
471
     */
472
    private function areKeyManagementModesCompatible(string $current, string $new): bool
473
    {
474
        $agree = KeyEncryptionAlgorithmInterface::MODE_AGREEMENT;
475
        $dir = KeyEncryptionAlgorithmInterface::MODE_DIRECT;
476
        $enc = KeyEncryptionAlgorithmInterface::MODE_ENCRYPT;
477
        $wrap = KeyEncryptionAlgorithmInterface::MODE_WRAP;
478
        $supportedKeyManagementModeCombinations = [$enc.$enc => true, $enc.$wrap => true, $wrap.$enc => true, $wrap.$wrap => true, $agree.$agree => false, $agree.$dir => false, $agree.$enc => false, $agree.$wrap => false, $dir.$agree => false, $dir.$dir => false, $dir.$enc => false, $dir.$wrap => false, $enc.$agree => false, $enc.$dir => false, $wrap.$agree => false, $wrap.$dir => false];
479
480
        if (array_key_exists($current.$new, $supportedKeyManagementModeCombinations)) {
481
            return $supportedKeyManagementModeCombinations[$current.$new];
482
        }
483
484
        return false;
485
    }
486
487
    /**
488
     * @param int $size
489
     *
490
     * @return string
491
     */
492
    private function createCEK(int $size): string
493
    {
494
        return random_bytes($size / 8);
495
    }
496
497
    /**
498
     * @param int $size
499
     *
500
     * @return string
501
     */
502
    private function createIV(int $size): string
503
    {
504
        return random_bytes($size / 8);
505
    }
506
507
    /**
508
     * @param array $completeHeaders
509
     *
510
     * @return KeyEncryptionAlgorithmInterface
511
     */
512
    private function getKeyEncryptionAlgorithm(array $completeHeaders): KeyEncryptionAlgorithmInterface
513
    {
514
        if (!array_key_exists('alg', $completeHeaders)) {
515
            throw new \InvalidArgumentException('Parameter "alg" is missing.');
516
        }
517
        $keyEncryptionAlgorithm = $this->keyEncryptionAlgorithmManager->get($completeHeaders['alg']);
518
        if (!$keyEncryptionAlgorithm instanceof KeyEncryptionAlgorithmInterface) {
519
            throw new \InvalidArgumentException(sprintf('The key encryption algorithm "%s" is not supported or not a key encryption algorithm instance.', $completeHeaders['alg']));
520
        }
521
522
        return $keyEncryptionAlgorithm;
523
    }
524
525
    /**
526
     * @param array $completeHeaders
527
     *
528
     * @return ContentEncryptionAlgorithmInterface
529
     */
530
    private function getContentEncryptionAlgorithm(array $completeHeaders): ContentEncryptionAlgorithmInterface
531
    {
532
        if (!array_key_exists('enc', $completeHeaders)) {
533
            throw new \InvalidArgumentException('Parameter "enc" is missing.');
534
        }
535
        $contentEncryptionAlgorithm = $this->contentEncryptionAlgorithmManager->get($completeHeaders['enc']);
536
        if (!$contentEncryptionAlgorithm instanceof ContentEncryptionAlgorithmInterface) {
537
            throw new \InvalidArgumentException(sprintf('The content encryption algorithm "%s" is not supported or not a content encryption algorithm instance.', $completeHeaders['alg']));
538
        }
539
540
        return $contentEncryptionAlgorithm;
541
    }
542
543
    /**
544
     * @param array $header1
545
     * @param array $header2
546
     */
547
    private function checkDuplicatedHeaderParameters(array $header1, array $header2)
548
    {
549
        $inter = array_intersect_key($header1, $header2);
550
        if (!empty($inter)) {
551
            throw new \InvalidArgumentException(sprintf('The header contains duplicated entries: %s.', json_encode(array_keys($inter))));
552
        }
553
    }
554
}
555