Completed
Push — master ( 1a59c2...c73113 )
by Florent
02:55
created

Encrypter   C

Complexity

Total Complexity 47

Size/Duplication

Total Lines 529
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 18

Importance

Changes 37
Bugs 18 Features 4
Metric Value
wmc 47
c 37
b 18
f 4
lcom 1
cbo 18
dl 0
loc 529
rs 5.5079

18 Methods

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