Completed
Push — master ( 022625...2b82d4 )
by Florent
05:58
created

Encrypter   F

Complexity

Total Complexity 49

Size/Duplication

Total Lines 547
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 21

Importance

Changes 27
Bugs 10 Features 4
Metric Value
wmc 49
c 27
b 10
f 4
lcom 1
cbo 21
dl 0
loc 547
rs 3.9616

19 Methods

Rating   Name   Duplication   Size   Complexity  
B encrypt() 0 68 4
A createEncrypter() 0 10 2
A __construct() 0 14 1
B processRecipient() 0 52 4
B determineCEK() 0 31 5
B getKeyManagementMode() 0 28 3
B getCompressionMethod() 0 35 6
A getContentEncryptionAlgorithm() 0 23 3
B encryptJWE() 0 31 4
A preparePayload() 0 14 3
A getEncryptedKeyFromKeyAgreementAndKeyWrappingAlgorithm() 0 6 1
A getEncryptedKeyFromKeyEncryptionAlgorithm() 0 9 1
A getEncryptedKeyFromKeyWrappingAlgorithm() 0 9 1
A findKeyEncryptionAlgorithm() 0 9 1
A createIV() 0 4 1
A checkKeys() 0 9 2
B areKeyManagementModesCompatible() 0 32 2
A getEncryptedKey() 0 12 4
A createCEK() 0 4 1

How to fix   Complexity   

Complex Class

Complex classes like Encrypter 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 Encrypter, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/*
4
 * The MIT License (MIT)
5
 *
6
 * Copyright (c) 2014-2016 Spomky-Labs
7
 *
8
 * This software may be modified and distributed under the terms
9
 * of the MIT license.  See the LICENSE file for details.
10
 */
11
12
namespace Jose;
13
14
use Assert\Assertion;
15
use Base64Url\Base64Url;
16
use Jose\Algorithm\ContentEncryptionAlgorithmInterface;
17
use Jose\Algorithm\KeyEncryption\KeyAgreementWrappingInterface;
18
use Jose\Algorithm\KeyEncryption\KeyEncryptionInterface;
19
use Jose\Algorithm\KeyEncryption\KeyWrappingInterface;
20
use Jose\Algorithm\KeyEncryptionAlgorithmInterface;
21
use Jose\Behaviour\CommonCipheringMethods;
22
use Jose\Behaviour\HasCompressionManager;
23
use Jose\Behaviour\HasJWAManager;
24
use Jose\Behaviour\HasKeyChecker;
25
use Jose\Behaviour\HasLogger;
26
use Jose\Compression\CompressionInterface;
27
use Jose\Factory\AlgorithmManagerFactory;
28
use Jose\Factory\CompressionManagerFactory;
29
use Jose\Object\JWEInterface;
30
use Jose\Object\JWKInterface;
31
use Jose\Object\Recipient;
32
use Jose\Object\RecipientInterface;
33
use Psr\Log\LoggerInterface;
34
use Psr\Log\LogLevel;
35
36
final class Encrypter implements EncrypterInterface
37
{
38
    use HasKeyChecker;
39
    use HasJWAManager;
40
    use HasCompressionManager;
41
    use HasLogger;
42
    use CommonCipheringMethods;
43
44
    /**
45
     * {@inheritdoc}
46
     */
47
    public static function createEncrypter(array $key_encryption_algorithms, array $content_encryption_algorithms, array $compression_methods = ['DEF', 'ZLIB', 'GZ'], LoggerInterface $logger = null)
48
    {
49
        $encrypter = new self($key_encryption_algorithms, $content_encryption_algorithms, $compression_methods);
50
51
        if (null !== $logger) {
52
            $encrypter->enableLogging($logger);
53
        }
54
55
        return $encrypter;
56
    }
57
58
    /**
59
     * Decrypter constructor.
60
     *
61
     * @param string[]|\Jose\Algorithm\KeyEncryptionAlgorithmInterface[]     $key_encryption_algorithms
62
     * @param string[]|\Jose\Algorithm\ContentEncryptionAlgorithmInterface[] $content_encryption_algorithms
63
     * @param string[]|\Jose\Compression\CompressionInterface[]              $compression_methods
64
     */
65
    public function __construct(
66
        array $key_encryption_algorithms,
67
        array $content_encryption_algorithms,
68
        array $compression_methods
69
    ) {
70
        $this->setKeyEncryptionAlgorithms($key_encryption_algorithms);
71
        $this->setContentEncryptionAlgorithms($content_encryption_algorithms);
72
        $this->setCompressionMethods($compression_methods);
73
        $this->setJWAManager(AlgorithmManagerFactory::createAlgorithmManager(array_merge(
74
            $key_encryption_algorithms,
75
            $content_encryption_algorithms
76
        )));
77
        $this->setCompressionManager(CompressionManagerFactory::createCompressionManager($compression_methods));
78
    }
79
80
    /**
81
     * {@inheritdoc}
82
     */
83
    public function encrypt(JWEInterface &$jwe)
84
    {
85
        $this->log(LogLevel::INFO, 'Trying to encrypt the JWE object', ['jwe' => $jwe]);
86
        Assertion::false($jwe->isEncrypted(), 'The JWE is already encrypted.');
87
        Assertion::greaterThan($jwe->countRecipients(), 0, 'The JWE does not contain recipient.');
88
89
        // Content Encryption Algorithm
90
        $this->log(LogLevel::DEBUG, 'Trying to find the content encryption algorithm');
91
        $content_encryption_algorithm = $this->getContentEncryptionAlgorithm($jwe);
92
        $this->log(LogLevel::DEBUG, 'The content encryption algorithm has been found', ['content_encryption_algorithm', $content_encryption_algorithm]);
93
94
        // Compression Method
95
        $this->log(LogLevel::DEBUG, 'Trying to find the compression method (if needed)');
96
        $compression_method = $this->getCompressionMethod($jwe);
97
        $this->log(LogLevel::DEBUG, 'The compression method search is finished', ['compression_method', $compression_method]);
98
99
        // Key Management Mode
100
        $this->log(LogLevel::DEBUG, 'Trying to find the key management mode');
101
        $key_management_mode = $this->getKeyManagementMode($jwe);
102
        $this->log(LogLevel::DEBUG, 'The key management mode has been found', ['key_management_mode', $key_management_mode]);
103
104
        // Additional Headers
105
        $additional_headers = [];
106
107
        // CEK
108
        $this->log(LogLevel::DEBUG, 'Trying to determine the content encryption key (CEK)');
109
        $cek = $this->determineCEK(
110
            $jwe,
111
            $content_encryption_algorithm,
112
            $key_management_mode,
113
            $additional_headers
114
        );
115
        $this->log(LogLevel::DEBUG, 'The content encryption key has been determined', ['cek', $cek]);
116
117
        $nb_recipients = $jwe->countRecipients();
118
119
        $this->log(LogLevel::DEBUG, 'Trying to encrypt the content encryption key (CEK) for all recipients');
120
        for ($i = 0; $i < $nb_recipients; $i++) {
121
            $this->log(LogLevel::DEBUG, 'Processing with recipient #{index}', ['index', $i]);
122
            $this->processRecipient(
123
                $jwe,
124
                $jwe->getRecipient($i),
125
                $cek,
126
                $content_encryption_algorithm,
127
                $additional_headers
128
            );
129
            $this->log(LogLevel::DEBUG, 'Processing done');
130
        }
131
132
        if (!empty($additional_headers) && 1 === $jwe->countRecipients()) {
133
            $this->log(LogLevel::DEBUG, 'Additional headers will be added to the shared protected headers', ['additional_headers' => $additional_headers]);
134
            $jwe = $jwe->withSharedProtectedHeaders(array_merge(
135
                $jwe->getSharedProtectedHeaders(),
136
                $additional_headers
137
            ));
138
            $this->log(LogLevel::DEBUG, 'Additional headers added');
139
        }
140
141
        // IV
142
        $this->log(LogLevel::DEBUG, 'Creating Initialization Vector (IV)');
143
        $iv_size = $content_encryption_algorithm->getIVSize();
144
        $iv = $this->createIV($iv_size);
145
        $this->log(LogLevel::DEBUG, 'Initialization Vector (IV) creation done', ['iv' => $iv]);
146
147
        $this->log(LogLevel::DEBUG, 'Trying to encrypt the JWE object ');
148
        $this->encryptJWE($jwe, $content_encryption_algorithm, $cek, $iv, $compression_method);
149
        $this->log(LogLevel::DEBUG, 'JWE object encryption done.');
150
    }
151
152
    /**
153
     * @param \Jose\Object\JWEInterface                           $jwe
154
     * @param \Jose\Object\RecipientInterface                     $recipient
155
     * @param string                                              $cek
156
     * @param \Jose\Algorithm\ContentEncryptionAlgorithmInterface $content_encryption_algorithm
157
     * @param array                                               $additional_headers
158
     */
159
    private function processRecipient(JWEInterface $jwe,
160
                                      RecipientInterface &$recipient,
161
                                      $cek,
162
                                      ContentEncryptionAlgorithmInterface $content_encryption_algorithm,
163
                                      array &$additional_headers
164
    ) {
165
        if (null === $recipient->getRecipientKey()) {
166
            $this->log(LogLevel::WARNING, 'The recipient key is not set. Aborting.');
167
168
            return;
169
        }
170
        $complete_headers = array_merge(
171
            $jwe->getSharedProtectedHeaders(),
172
            $jwe->getSharedHeaders(),
173
            $recipient->getHeaders()
174
        );
175
176
        $this->log(LogLevel::DEBUG, 'Trying to find the key encryption algorithm');
177
        $key_encryption_algorithm = $this->findKeyEncryptionAlgorithm($complete_headers);
178
        $this->log(LogLevel::DEBUG, 'The key encryption algorithm has been found', ['key_encryption_algorithm' => $key_encryption_algorithm]);
179
180
        // We check keys (usage and algorithm if restrictions are set)
181
        $this->log(LogLevel::DEBUG, 'Checking recipient key usage');
182
        $this->checkKeys(
183
            $key_encryption_algorithm,
184
            $content_encryption_algorithm,
185
            $recipient->getRecipientKey()
186
        );
187
        $this->log(LogLevel::DEBUG, 'Recipient key usage checks done');
188
189
        $this->log(LogLevel::DEBUG, 'Trying to compute the content encryption key');
190
        $encrypted_content_encryption_key = $this->getEncryptedKey(
191
            $complete_headers,
192
            $cek,
193
            $key_encryption_algorithm,
194
            $content_encryption_algorithm,
195
            $additional_headers,
196
            $recipient->getRecipientKey()
197
        );
198
        $this->log(LogLevel::DEBUG, 'Content encryption key computation done', ['encrypted_content_encryption_key' => $encrypted_content_encryption_key]);
199
200
        $recipient_headers = $recipient->getHeaders();
201
        if (!empty($additional_headers) && 1 !== $jwe->countRecipients()) {
202
            $recipient_headers = array_merge(
203
                $recipient_headers,
204
                $additional_headers
205
            );
206
            $additional_headers = [];
207
        }
208
209
        $recipient = Recipient::createRecipientFromLoadedJWE($recipient_headers, $encrypted_content_encryption_key);
210
    }
211
212
    /**
213
     * @param \Jose\Object\JWEInterface                           $jwe
214
     * @param \Jose\Algorithm\ContentEncryptionAlgorithmInterface $content_encryption_algorithm
215
     * @param string                                              $key_management_mode
216
     * @param array                                               $additional_headers
217
     *
218
     * @return string
219
     */
220
    private function determineCEK(JWEInterface $jwe,
221
                                  ContentEncryptionAlgorithmInterface $content_encryption_algorithm,
222
                                  $key_management_mode,
223
                                  array &$additional_headers
224
    ) {
225
        switch ($key_management_mode) {
226
            case KeyEncryptionInterface::MODE_ENCRYPT:
227
            case KeyEncryptionInterface::MODE_WRAP:
228
                return $this->createCEK($content_encryption_algorithm->getCEKSize());
229
            case KeyEncryptionInterface::MODE_AGREEMENT:
230
                Assertion::eq(1, $jwe->countRecipients(), 'Unable to encrypt for multiple recipients using key agreement algorithms.');
231
232
                $complete_headers = array_merge(
233
                    $jwe->getSharedProtectedHeaders(),
234
                    $jwe->getSharedHeaders(),
235
                    $jwe->getRecipient(0)->getHeaders()
236
                );
237
                $algorithm = $this->findKeyEncryptionAlgorithm($complete_headers);
238
239
                return $algorithm->getAgreementKey($content_encryption_algorithm->getCEKSize(), $content_encryption_algorithm->getAlgorithmName(), $jwe->getRecipient(0)->getRecipientKey(), $complete_headers, $additional_headers);
240
            case KeyEncryptionInterface::MODE_DIRECT:
241
                Assertion::eq(1, $jwe->countRecipients(), 'Unable to encrypt for multiple recipients using key agreement algorithms.');
242
243
                Assertion::eq($jwe->getRecipient(0)->getRecipientKey()->get('kty'), 'oct', 'Wrong key type.');
244
                Assertion::true($jwe->getRecipient(0)->getRecipientKey()->has('k'), 'The key parameter "k" is missing.');
245
246
                return Base64Url::decode($jwe->getRecipient(0)->getRecipientKey()->get('k'));
247
            default:
248
                throw new \InvalidArgumentException(sprintf('Unsupported key management mode "%s".', $key_management_mode));
249
        }
250
    }
251
252
    /**
253
     * @param \Jose\Object\JWEInterface $jwe
254
     *
255
     * @return string
256
     */
257
    private function getKeyManagementMode(JWEInterface $jwe)
258
    {
259
        $mode = null;
260
        $recipients = $jwe->getRecipients();
261
262
        foreach ($recipients as $recipient) {
263
            $complete_headers = array_merge(
264
                $jwe->getSharedProtectedHeaders(),
265
                $jwe->getSharedHeaders(),
266
                $recipient->getHeaders()
267
            );
268
            Assertion::keyExists($complete_headers, 'alg', 'Parameter "alg" is missing.');
269
270
            $key_encryption_algorithm = $this->getJWAManager()->getAlgorithm($complete_headers['alg']);
271
            Assertion::isInstanceOf($key_encryption_algorithm, KeyEncryptionAlgorithmInterface::class, sprintf('The key encryption algorithm "%s" is not supported or not a key encryption algorithm instance.', $complete_headers['alg']));
272
273
            if (null === $mode) {
274
                $mode = $key_encryption_algorithm->getKeyManagementMode();
275
            } else {
276
                Assertion::true(
277
                    $this->areKeyManagementModesCompatible($mode, $key_encryption_algorithm->getKeyManagementMode()),
278
                    'Foreign key management mode forbidden.'
279
                );
280
            }
281
        }
282
283
        return $mode;
284
    }
285
286
    /**
287
     * @param \Jose\Object\JWEInterface $jwe
288
     *
289
     * @return \Jose\Compression\CompressionInterface|null
290
     */
291
    private function getCompressionMethod(JWEInterface $jwe)
292
    {
293
        $method = null;
294
        $nb_recipients = $jwe->countRecipients();
295
296
        for ($i = 0; $i < $nb_recipients; $i++) {
297
            $complete_headers = array_merge(
298
                $jwe->getSharedProtectedHeaders(),
299
                $jwe->getSharedHeaders(),
300
                $jwe->getRecipient($i)->getHeaders()
301
            );
302
            if (array_key_exists('zip', $complete_headers)) {
303
                if (null === $method) {
304
                    if (0 === $i) {
305
                        $method = $complete_headers['zip'];
306
                    } else {
307
                        throw new \InvalidArgumentException('Inconsistent "zip" parameter.');
308
                    }
309
                } else {
310
                    Assertion::eq($method, $complete_headers['zip'], 'Inconsistent "zip" parameter.');
311
                }
312
            } else {
313
                Assertion::eq(null, $method, 'Inconsistent "zip" parameter.');
314
            }
315
        }
316
317
        if (null === $method) {
318
            return;
319
        }
320
321
        $compression_method = $this->getCompressionManager()->getCompressionAlgorithm($method);
322
        Assertion::isInstanceOf($compression_method, CompressionInterface::class, sprintf('Compression method "%s" not supported.', $method));
323
324
        return $compression_method;
325
    }
326
327
    /**
328
     * @param \Jose\Object\JWEInterface $jwe
329
     *
330
     * @return \Jose\Algorithm\ContentEncryptionAlgorithmInterface
331
     */
332
    private function getContentEncryptionAlgorithm(JWEInterface $jwe)
333
    {
334
        $algorithm = null;
335
336
        foreach ($jwe->getRecipients() as $recipient) {
337
            $complete_headers = array_merge(
338
                $jwe->getSharedProtectedHeaders(),
339
                $jwe->getSharedHeaders(),
340
                $recipient->getHeaders()
341
            );
342
            Assertion::keyExists($complete_headers, 'enc', 'Parameter "enc" is missing.');
343
            if (null === $algorithm) {
344
                $algorithm = $complete_headers['enc'];
345
            } else {
346
                Assertion::eq($algorithm, $complete_headers['enc'], 'Foreign content encryption algorithms are not allowed.');
347
            }
348
        }
349
350
        $content_encryption_algorithm = $this->getJWAManager()->getAlgorithm($algorithm);
351
        Assertion::isInstanceOf($content_encryption_algorithm, ContentEncryptionAlgorithmInterface::class, sprintf('The content encryption algorithm "%s" is not supported or not a content encryption algorithm instance.', $algorithm));
352
353
        return $content_encryption_algorithm;
354
    }
355
356
    /**
357
     * @param \Jose\Object\JWEInterface                           $jwe
358
     * @param \Jose\Algorithm\ContentEncryptionAlgorithmInterface $content_encryption_algorithm
359
     * @param string                                              $cek
360
     * @param string                                              $iv
361
     * @param \Jose\Compression\CompressionInterface|null         $compression_method
362
     */
363
    private function encryptJWE(JWEInterface &$jwe,
364
                                ContentEncryptionAlgorithmInterface $content_encryption_algorithm,
365
                                $cek,
366
                                $iv,
367
                                CompressionInterface $compression_method = null
368
    ) {
369
        if (!empty($jwe->getSharedProtectedHeaders())) {
370
            $jwe = $jwe->withEncodedSharedProtectedHeaders(Base64Url::encode(json_encode($jwe->getSharedProtectedHeaders())));
371
        }
372
373
        // We encrypt the payload and get the tag
374
        $tag = null;
375
        $payload = $this->preparePayload($jwe->getPayload(), $compression_method);
376
377
        $ciphertext = $content_encryption_algorithm->encryptContent(
378
            $payload,
379
            $cek,
380
            $iv,
381
            null === $jwe->getAAD() ? null : Base64Url::encode($jwe->getAAD()),
382
            $jwe->getEncodedSharedProtectedHeaders(),
383
            $tag
384
        );
385
386
        $jwe = $jwe->withCiphertext($ciphertext);
387
        $jwe = $jwe->withIV($iv);
388
389
        // Tag
390
        if (null !== $tag) {
391
            $jwe = $jwe->withTag($tag);
392
        }
393
    }
394
395
    /**
396
     * @param \Jose\Algorithm\KeyEncryptionAlgorithmInterface     $key_encryption_algorithm
397
     * @param \Jose\Algorithm\ContentEncryptionAlgorithmInterface $content_encryption_algorithm
398
     * @param \Jose\Object\JWKInterface                           $recipient_key
399
     */
400
    private function checkKeys(KeyEncryptionAlgorithmInterface $key_encryption_algorithm, ContentEncryptionAlgorithmInterface $content_encryption_algorithm, JWKInterface $recipient_key)
401
    {
402
        $this->checkKeyUsage($recipient_key, 'encryption');
403
        if ('dir' !== $key_encryption_algorithm->getAlgorithmName()) {
404
            $this->checkKeyAlgorithm($recipient_key, $key_encryption_algorithm->getAlgorithmName());
405
        } else {
406
            $this->checkKeyAlgorithm($recipient_key, $content_encryption_algorithm->getAlgorithmName());
407
        }
408
    }
409
410
    /**
411
     * @param string $current
412
     * @param string $new
413
     *
414
     * @return bool
415
     */
416
    private function areKeyManagementModesCompatible($current, $new)
417
    {
418
        $agree = KeyEncryptionAlgorithmInterface::MODE_AGREEMENT;
419
        $dir = KeyEncryptionAlgorithmInterface::MODE_DIRECT;
420
        $enc = KeyEncryptionAlgorithmInterface::MODE_ENCRYPT;
421
        $wrap = KeyEncryptionAlgorithmInterface::MODE_WRAP;
422
423
        $supported_key_management_mode_combinations = [
424
            $enc.$enc     => true,
425
            $enc.$wrap    => true,
426
            $wrap.$enc    => true,
427
            $wrap.$wrap   => true,
428
            $agree.$agree => false,
429
            $agree.$dir   => false,
430
            $agree.$enc   => false,
431
            $agree.$wrap  => false,
432
            $dir.$agree   => false,
433
            $dir.$dir     => false,
434
            $dir.$enc     => false,
435
            $dir.$wrap    => false,
436
            $enc.$agree   => false,
437
            $enc.$dir     => false,
438
            $wrap.$agree  => false,
439
            $wrap.$dir    => false,
440
        ];
441
442
        if (array_key_exists($current.$new, $supported_key_management_mode_combinations)) {
443
            return $supported_key_management_mode_combinations[$current.$new];
444
        }
445
446
        return false;
447
    }
448
449
    /**
450
     * @param string                                      $payload
451
     * @param \Jose\Compression\CompressionInterface|null $compression_method
452
     *
453
     * @return string
454
     */
455
    private function preparePayload($payload, CompressionInterface $compression_method = null)
456
    {
457
        $prepared = is_string($payload) ? $payload : json_encode($payload);
458
459
        Assertion::notNull($prepared, 'The payload is empty or cannot encoded into JSON.');
460
461
        if (null === $compression_method) {
462
            return $prepared;
463
        }
464
        $compressed_payload = $compression_method->compress($prepared);
465
        Assertion::string($compressed_payload, 'Compression failed.');
466
467
        return $compressed_payload;
468
    }
469
470
    /**
471
     * @param array                                               $complete_headers
472
     * @param string                                              $cek
473
     * @param \Jose\Algorithm\KeyEncryptionAlgorithmInterface     $key_encryption_algorithm
474
     * @param \Jose\Algorithm\ContentEncryptionAlgorithmInterface $content_encryption_algorithm
475
     * @param \Jose\Object\JWKInterface                           $recipient_key
476
     * @param array                                               $additional_headers
477
     *
478
     * @return string|null
479
     */
480
    private function getEncryptedKey(array $complete_headers, $cek, KeyEncryptionAlgorithmInterface $key_encryption_algorithm, ContentEncryptionAlgorithmInterface $content_encryption_algorithm, array &$additional_headers, JWKInterface $recipient_key)
481
    {
482
        if ($key_encryption_algorithm instanceof KeyEncryptionInterface) {
483
            return $this->getEncryptedKeyFromKeyEncryptionAlgorithm($complete_headers, $cek, $key_encryption_algorithm, $recipient_key, $additional_headers);
484
        } elseif ($key_encryption_algorithm instanceof KeyWrappingInterface) {
485
            return $this->getEncryptedKeyFromKeyWrappingAlgorithm($complete_headers, $cek, $key_encryption_algorithm, $recipient_key, $additional_headers);
486
        } elseif ($key_encryption_algorithm instanceof KeyAgreementWrappingInterface) {
487
            return $this->getEncryptedKeyFromKeyAgreementAndKeyWrappingAlgorithm($complete_headers, $cek, $key_encryption_algorithm, $content_encryption_algorithm, $additional_headers, $recipient_key);
488
        }
489
490
        // Using KeyAgreementInterface or DirectEncryptionInterface, the encrypted key is an empty string
491
    }
492
493
    /**
494
     * @param array                                                       $complete_headers
495
     * @param string                                                      $cek
496
     * @param \Jose\Algorithm\KeyEncryption\KeyAgreementWrappingInterface $key_encryption_algorithm
497
     * @param \Jose\Algorithm\ContentEncryptionAlgorithmInterface         $content_encryption_algorithm
498
     * @param array                                                       $additional_headers
499
     * @param \Jose\Object\JWKInterface                                   $recipient_key
500
     *
501
     * @return string
502
     */
503
    private function getEncryptedKeyFromKeyAgreementAndKeyWrappingAlgorithm(array $complete_headers, $cek, KeyAgreementWrappingInterface $key_encryption_algorithm, ContentEncryptionAlgorithmInterface $content_encryption_algorithm, array &$additional_headers, JWKInterface $recipient_key)
504
    {
505
        $jwt_cek = $key_encryption_algorithm->wrapAgreementKey($recipient_key, $cek, $content_encryption_algorithm->getCEKSize(), $complete_headers, $additional_headers);
506
507
        return $jwt_cek;
508
    }
509
510
    /**
511
     * @param array                                                $complete_headers
512
     * @param string                                               $cek
513
     * @param \Jose\Algorithm\KeyEncryption\KeyEncryptionInterface $key_encryption_algorithm
514
     * @param \Jose\Object\JWKInterface                            $recipient_key
515
     * @param array                                                $additional_headers
516
     *
517
     * @return string
518
     */
519
    private function getEncryptedKeyFromKeyEncryptionAlgorithm(array $complete_headers, $cek, KeyEncryptionInterface $key_encryption_algorithm, JWKInterface $recipient_key, array &$additional_headers)
520
    {
521
        return $key_encryption_algorithm->encryptKey(
522
            $recipient_key,
523
            $cek,
524
            $complete_headers,
525
            $additional_headers
526
        );
527
    }
528
529
    /**
530
     * @param array                                              $complete_headers
531
     * @param string                                             $cek
532
     * @param \Jose\Algorithm\KeyEncryption\KeyWrappingInterface $key_encryption_algorithm
533
     * @param \Jose\Object\JWKInterface                          $recipient_key
534
     * @param array                                              $additional_headers
535
     *
536
     * @return string
537
     */
538
    private function getEncryptedKeyFromKeyWrappingAlgorithm(array $complete_headers, $cek, KeyWrappingInterface $key_encryption_algorithm, JWKInterface $recipient_key, &$additional_headers)
539
    {
540
        return $key_encryption_algorithm->wrapKey(
541
            $recipient_key,
542
            $cek,
543
            $complete_headers,
544
            $additional_headers
545
        );
546
    }
547
548
    /**
549
     * @param array $complete_headers
550
     *
551
     * @return \Jose\Algorithm\KeyEncryptionAlgorithmInterface
552
     */
553
    private function findKeyEncryptionAlgorithm(array $complete_headers)
554
    {
555
        Assertion::keyExists($complete_headers, 'alg', 'Parameter "alg" is missing.');
556
557
        $key_encryption_algorithm = $this->getJWAManager()->getAlgorithm($complete_headers['alg']);
558
        Assertion::isInstanceOf($key_encryption_algorithm, KeyEncryptionAlgorithmInterface::class, sprintf('The key encryption algorithm "%s" is not supported or not a key encryption algorithm instance.', $complete_headers['alg']));
559
560
        return $key_encryption_algorithm;
561
    }
562
563
    /**
564
     * @param int $size
565
     *
566
     * @return string
567
     */
568
    private function createCEK($size)
569
    {
570
        return random_bytes($size / 8);
571
    }
572
573
    /**
574
     * @param int $size
575
     *
576
     * @return string
577
     */
578
    private function createIV($size)
579
    {
580
        return random_bytes($size / 8);
581
    }
582
}
583