Failed Conditions
Push — master ( 66e9c8...1d7ac7 )
by Florent
03:24
created

Encrypter   D

Complexity

Total Complexity 48

Size/Duplication

Total Lines 450
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 20

Importance

Changes 27
Bugs 9 Features 4
Metric Value
wmc 48
c 27
b 9
f 4
lcom 1
cbo 20
dl 0
loc 450
rs 4.5032

19 Methods

Rating   Name   Duplication   Size   Complexity  
A createEncrypter() 0 6 1
A __construct() 0 14 1
B encrypt() 0 36 4
B processRecipient() 0 26 4
B determineCEK() 0 25 5
A getKeyManagementMode() 0 21 3
B getCompressionMethod() 0 31 6
A getContentEncryptionAlgorithm() 0 23 3
B encryptJWE() 0 31 4
A checkKeys() 0 9 2
A areKeyManagementModesCompatible() 0 15 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\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\Compression\CompressionInterface;
26
use Jose\Factory\AlgorithmManagerFactory;
27
use Jose\Factory\CompressionManagerFactory;
28
use Jose\Object\JWEInterface;
29
use Jose\Object\JWKInterface;
30
use Jose\Object\Recipient;
31
use Jose\Object\RecipientInterface;
32
33
final class Encrypter implements EncrypterInterface
34
{
35
    use HasKeyChecker;
36
    use HasJWAManager;
37
    use HasCompressionManager;
38
    use CommonCipheringMethods;
39
40
    /**
41
     * {@inheritdoc}
42
     */
43
    public static function createEncrypter(array $key_encryption_algorithms, array $content_encryption_algorithms, array $compression_methods = ['DEF', 'ZLIB', 'GZ'])
44
    {
45
        $encrypter = new self($key_encryption_algorithms, $content_encryption_algorithms, $compression_methods);
46
47
        return $encrypter;
48
    }
49
50
    /**
51
     * Decrypter constructor.
52
     *
53
     * @param string[]|\Jose\Algorithm\KeyEncryptionAlgorithmInterface[]     $key_encryption_algorithms
54
     * @param string[]|\Jose\Algorithm\ContentEncryptionAlgorithmInterface[] $content_encryption_algorithms
55
     * @param string[]|\Jose\Compression\CompressionInterface[]              $compression_methods
56
     */
57
    public function __construct(
58
        array $key_encryption_algorithms,
59
        array $content_encryption_algorithms,
60
        array $compression_methods
61
    ) {
62
        $this->setKeyEncryptionAlgorithms($key_encryption_algorithms);
63
        $this->setContentEncryptionAlgorithms($content_encryption_algorithms);
64
        $this->setCompressionMethods($compression_methods);
65
        $this->setJWAManager(AlgorithmManagerFactory::createAlgorithmManager(array_merge(
66
            $key_encryption_algorithms,
67
            $content_encryption_algorithms
68
        )));
69
        $this->setCompressionManager(CompressionManagerFactory::createCompressionManager($compression_methods));
70
    }
71
72
    /**
73
     * {@inheritdoc}
74
     */
75
    public function encrypt(JWEInterface &$jwe)
76
    {
77
        Assertion::false($jwe->isEncrypted(), 'The JWE is already encrypted.');
78
        Assertion::greaterThan($jwe->countRecipients(), 0, 'The JWE does not contain recipient.');
79
80
        // Content Encryption Algorithm
81
        $content_encryption_algorithm = $this->getContentEncryptionAlgorithm($jwe);
82
83
        // Compression Method
84
        $compression_method = $this->getCompressionMethod($jwe);
85
86
        // Key Management Mode
87
        $key_management_mode = $this->getKeyManagementMode($jwe);
88
89
        // Additional Headers
90
        $additional_headers = [];
91
92
        // CEK
93
        $cek = $this->determineCEK($jwe, $content_encryption_algorithm, $key_management_mode, $additional_headers);
94
95
        $nb_recipients = $jwe->countRecipients();
96
97
        for ($i = 0; $i < $nb_recipients; $i++) {
98
            $this->processRecipient($jwe, $jwe->getRecipient($i), $cek, $content_encryption_algorithm, $additional_headers);
99
        }
100
101
        if (!empty($additional_headers) && 1 === $jwe->countRecipients()) {
102
            $jwe = $jwe->withSharedProtectedHeaders(array_merge($jwe->getSharedProtectedHeaders(), $additional_headers));
103
        }
104
105
        // IV
106
        $iv_size = $content_encryption_algorithm->getIVSize();
107
        $iv = $this->createIV($iv_size);
108
109
        $this->encryptJWE($jwe, $content_encryption_algorithm, $cek, $iv, $compression_method);
110
    }
111
112
    /**
113
     * @param \Jose\Object\JWEInterface                           $jwe
114
     * @param \Jose\Object\RecipientInterface                     $recipient
115
     * @param string                                              $cek
116
     * @param \Jose\Algorithm\ContentEncryptionAlgorithmInterface $content_encryption_algorithm
117
     * @param array                                               $additional_headers
118
     */
119
    private function processRecipient(JWEInterface $jwe,
120
                                      RecipientInterface &$recipient,
121
                                      $cek,
122
                                      ContentEncryptionAlgorithmInterface $content_encryption_algorithm,
123
                                      array &$additional_headers
124
    ) {
125
        if (null === $recipient->getRecipientKey()) {
126
            return;
127
        }
128
        $complete_headers = array_merge($jwe->getSharedProtectedHeaders(), $jwe->getSharedHeaders(), $recipient->getHeaders());
129
130
        $key_encryption_algorithm = $this->findKeyEncryptionAlgorithm($complete_headers);
131
132
        // We check keys (usage and algorithm if restrictions are set)
133
        $this->checkKeys($key_encryption_algorithm, $content_encryption_algorithm, $recipient->getRecipientKey());
0 ignored issues
show
Bug introduced by
It seems like $key_encryption_algorithm defined by $this->findKeyEncryption...ithm($complete_headers) on line 130 can be null; however, Jose\Encrypter::checkKeys() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
134
135
        $encrypted_content_encryption_key = $this->getEncryptedKey($complete_headers, $cek, $key_encryption_algorithm, $content_encryption_algorithm, $additional_headers, $recipient->getRecipientKey());
0 ignored issues
show
Bug introduced by
It seems like $key_encryption_algorithm defined by $this->findKeyEncryption...ithm($complete_headers) on line 130 can be null; however, Jose\Encrypter::getEncryptedKey() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
136
137
        $recipient_headers = $recipient->getHeaders();
138
        if (!empty($additional_headers) && 1 !== $jwe->countRecipients()) {
139
            $recipient_headers = array_merge($recipient_headers, $additional_headers);
140
            $additional_headers = [];
141
        }
142
143
        $recipient = Recipient::createRecipientFromLoadedJWE($recipient_headers, $encrypted_content_encryption_key);
144
    }
145
146
    /**
147
     * @param \Jose\Object\JWEInterface                           $jwe
148
     * @param \Jose\Algorithm\ContentEncryptionAlgorithmInterface $content_encryption_algorithm
149
     * @param string                                              $key_management_mode
150
     * @param array                                               $additional_headers
151
     *
152
     * @return string
153
     */
154
    private function determineCEK(JWEInterface $jwe,
155
                                  ContentEncryptionAlgorithmInterface $content_encryption_algorithm,
156
                                  $key_management_mode,
157
                                  array &$additional_headers
158
    ) {
159
        switch ($key_management_mode) {
160
            case KeyEncryptionInterface::MODE_ENCRYPT:
161
            case KeyEncryptionInterface::MODE_WRAP:
162
                return $this->createCEK($content_encryption_algorithm->getCEKSize());
163
            case KeyEncryptionInterface::MODE_AGREEMENT:
164
                Assertion::eq(1, $jwe->countRecipients(), 'Unable to encrypt for multiple recipients using key agreement algorithms.');
165
                $complete_headers = array_merge($jwe->getSharedProtectedHeaders(), $jwe->getSharedHeaders(), $jwe->getRecipient(0)->getHeaders());
166
                $algorithm = $this->findKeyEncryptionAlgorithm($complete_headers);
167
168
                return $algorithm->getAgreementKey($content_encryption_algorithm->getCEKSize(), $content_encryption_algorithm->getAlgorithmName(), $jwe->getRecipient(0)->getRecipientKey(), $complete_headers, $additional_headers);
169
            case KeyEncryptionInterface::MODE_DIRECT:
170
                Assertion::eq(1, $jwe->countRecipients(), 'Unable to encrypt for multiple recipients using key agreement algorithms.');
171
                Assertion::eq($jwe->getRecipient(0)->getRecipientKey()->get('kty'), 'oct', 'Wrong key type.');
172
                Assertion::true($jwe->getRecipient(0)->getRecipientKey()->has('k'), 'The key parameter "k" is missing.');
173
174
                return Base64Url::decode($jwe->getRecipient(0)->getRecipientKey()->get('k'));
175
            default:
176
                throw new \InvalidArgumentException(sprintf('Unsupported key management mode "%s".', $key_management_mode));
177
        }
178
    }
179
180
    /**
181
     * @param \Jose\Object\JWEInterface $jwe
182
     *
183
     * @return string
184
     */
185
    private function getKeyManagementMode(JWEInterface $jwe)
186
    {
187
        $mode = null;
188
        $recipients = $jwe->getRecipients();
189
190
        foreach ($recipients as $recipient) {
191
            $complete_headers = array_merge($jwe->getSharedProtectedHeaders(), $jwe->getSharedHeaders(), $recipient->getHeaders());
192
            Assertion::keyExists($complete_headers, 'alg', 'Parameter "alg" is missing.');
193
194
            $key_encryption_algorithm = $this->getJWAManager()->getAlgorithm($complete_headers['alg']);
195
            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']));
196
197
            if (null === $mode) {
198
                $mode = $key_encryption_algorithm->getKeyManagementMode();
199
            } else {
200
                Assertion::true($this->areKeyManagementModesCompatible($mode, $key_encryption_algorithm->getKeyManagementMode()), 'Foreign key management mode forbidden.');
201
            }
202
        }
203
204
        return $mode;
205
    }
206
207
    /**
208
     * @param \Jose\Object\JWEInterface $jwe
209
     *
210
     * @return \Jose\Compression\CompressionInterface|null
211
     */
212
    private function getCompressionMethod(JWEInterface $jwe)
213
    {
214
        $method = null;
215
        $nb_recipients = $jwe->countRecipients();
216
217
        for ($i = 0; $i < $nb_recipients; $i++) {
218
            $complete_headers = array_merge($jwe->getSharedProtectedHeaders(), $jwe->getSharedHeaders(), $jwe->getRecipient($i)->getHeaders());
219
            if (array_key_exists('zip', $complete_headers)) {
220
                if (null === $method) {
221
                    if (0 === $i) {
222
                        $method = $complete_headers['zip'];
223
                    } else {
224
                        throw new \InvalidArgumentException('Inconsistent "zip" parameter.');
225
                    }
226
                } else {
227
                    Assertion::eq($method, $complete_headers['zip'], 'Inconsistent "zip" parameter.');
228
                }
229
            } else {
230
                Assertion::eq(null, $method, 'Inconsistent "zip" parameter.');
231
            }
232
        }
233
234
        if (null === $method) {
235
            return;
236
        }
237
238
        $compression_method = $this->getCompressionManager()->getCompressionAlgorithm($method);
239
        Assertion::isInstanceOf($compression_method, CompressionInterface::class, sprintf('Compression method "%s" not supported.', $method));
240
241
        return $compression_method;
242
    }
243
244
    /**
245
     * @param \Jose\Object\JWEInterface $jwe
246
     *
247
     * @return \Jose\Algorithm\ContentEncryptionAlgorithmInterface
248
     */
249
    private function getContentEncryptionAlgorithm(JWEInterface $jwe)
250
    {
251
        $algorithm = null;
252
253
        foreach ($jwe->getRecipients() as $recipient) {
254
            $complete_headers = array_merge(
255
                $jwe->getSharedProtectedHeaders(),
256
                $jwe->getSharedHeaders(),
257
                $recipient->getHeaders()
258
            );
259
            Assertion::keyExists($complete_headers, 'enc', 'Parameter "enc" is missing.');
260
            if (null === $algorithm) {
261
                $algorithm = $complete_headers['enc'];
262
            } else {
263
                Assertion::eq($algorithm, $complete_headers['enc'], 'Foreign content encryption algorithms are not allowed.');
264
            }
265
        }
266
267
        $content_encryption_algorithm = $this->getJWAManager()->getAlgorithm($algorithm);
268
        Assertion::isInstanceOf($content_encryption_algorithm, ContentEncryptionAlgorithmInterface::class, sprintf('The content encryption algorithm "%s" is not supported or not a content encryption algorithm instance.', $algorithm));
269
270
        return $content_encryption_algorithm;
271
    }
272
273
    /**
274
     * @param \Jose\Object\JWEInterface                           $jwe
275
     * @param \Jose\Algorithm\ContentEncryptionAlgorithmInterface $content_encryption_algorithm
276
     * @param string                                              $cek
277
     * @param string                                              $iv
278
     * @param \Jose\Compression\CompressionInterface|null         $compression_method
279
     */
280
    private function encryptJWE(JWEInterface &$jwe,
281
                                ContentEncryptionAlgorithmInterface $content_encryption_algorithm,
282
                                $cek,
283
                                $iv,
284
                                CompressionInterface $compression_method = null
285
    ) {
286
        if (!empty($jwe->getSharedProtectedHeaders())) {
287
            $jwe = $jwe->withEncodedSharedProtectedHeaders(Base64Url::encode(json_encode($jwe->getSharedProtectedHeaders())));
288
        }
289
290
        // We encrypt the payload and get the tag
291
        $tag = null;
292
        $payload = $this->preparePayload($jwe->getPayload(), $compression_method);
293
294
        $ciphertext = $content_encryption_algorithm->encryptContent(
295
            $payload,
296
            $cek,
297
            $iv,
298
            null === $jwe->getAAD() ? null : Base64Url::encode($jwe->getAAD()),
299
            $jwe->getEncodedSharedProtectedHeaders(),
300
            $tag
301
        );
302
303
        $jwe = $jwe->withCiphertext($ciphertext);
304
        $jwe = $jwe->withIV($iv);
305
306
        // Tag
307
        if (null !== $tag) {
308
            $jwe = $jwe->withTag($tag);
309
        }
310
    }
311
312
    /**
313
     * @param \Jose\Algorithm\KeyEncryptionAlgorithmInterface     $key_encryption_algorithm
314
     * @param \Jose\Algorithm\ContentEncryptionAlgorithmInterface $content_encryption_algorithm
315
     * @param \Jose\Object\JWKInterface                           $recipient_key
316
     */
317
    private function checkKeys(KeyEncryptionAlgorithmInterface $key_encryption_algorithm, ContentEncryptionAlgorithmInterface $content_encryption_algorithm, JWKInterface $recipient_key)
318
    {
319
        $this->checkKeyUsage($recipient_key, 'encryption');
320
        if ('dir' !== $key_encryption_algorithm->getAlgorithmName()) {
321
            $this->checkKeyAlgorithm($recipient_key, $key_encryption_algorithm->getAlgorithmName());
322
        } else {
323
            $this->checkKeyAlgorithm($recipient_key, $content_encryption_algorithm->getAlgorithmName());
324
        }
325
    }
326
327
    /**
328
     * @param string $current
329
     * @param string $new
330
     *
331
     * @return bool
332
     */
333
    private function areKeyManagementModesCompatible($current, $new)
334
    {
335
        $agree = KeyEncryptionAlgorithmInterface::MODE_AGREEMENT;
336
        $dir = KeyEncryptionAlgorithmInterface::MODE_DIRECT;
337
        $enc = KeyEncryptionAlgorithmInterface::MODE_ENCRYPT;
338
        $wrap = KeyEncryptionAlgorithmInterface::MODE_WRAP;
339
340
        $supported_key_management_mode_combinations = [$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,];
341
342
        if (array_key_exists($current.$new, $supported_key_management_mode_combinations)) {
343
            return $supported_key_management_mode_combinations[$current.$new];
344
        }
345
346
        return false;
347
    }
348
349
    /**
350
     * @param string                                      $payload
351
     * @param \Jose\Compression\CompressionInterface|null $compression_method
352
     *
353
     * @return string
354
     */
355
    private function preparePayload($payload, CompressionInterface $compression_method = null)
356
    {
357
        $prepared = is_string($payload) ? $payload : json_encode($payload);
358
359
        Assertion::notNull($prepared, 'The payload is empty or cannot encoded into JSON.');
360
361
        if (null === $compression_method) {
362
            return $prepared;
363
        }
364
        $compressed_payload = $compression_method->compress($prepared);
365
        Assertion::string($compressed_payload, 'Compression failed.');
366
367
        return $compressed_payload;
368
    }
369
370
    /**
371
     * @param array                                               $complete_headers
372
     * @param string                                              $cek
373
     * @param \Jose\Algorithm\KeyEncryptionAlgorithmInterface     $key_encryption_algorithm
374
     * @param \Jose\Algorithm\ContentEncryptionAlgorithmInterface $content_encryption_algorithm
375
     * @param \Jose\Object\JWKInterface                           $recipient_key
376
     * @param array                                               $additional_headers
377
     *
378
     * @return string|null
379
     */
380
    private function getEncryptedKey(array $complete_headers, $cek, KeyEncryptionAlgorithmInterface $key_encryption_algorithm, ContentEncryptionAlgorithmInterface $content_encryption_algorithm, array &$additional_headers, JWKInterface $recipient_key)
381
    {
382
        if ($key_encryption_algorithm instanceof KeyEncryptionInterface) {
383
            return $this->getEncryptedKeyFromKeyEncryptionAlgorithm($complete_headers, $cek, $key_encryption_algorithm, $recipient_key, $additional_headers);
384
        } elseif ($key_encryption_algorithm instanceof KeyWrappingInterface) {
385
            return $this->getEncryptedKeyFromKeyWrappingAlgorithm($complete_headers, $cek, $key_encryption_algorithm, $recipient_key, $additional_headers);
386
        } elseif ($key_encryption_algorithm instanceof KeyAgreementWrappingInterface) {
387
            return $this->getEncryptedKeyFromKeyAgreementAndKeyWrappingAlgorithm($complete_headers, $cek, $key_encryption_algorithm, $content_encryption_algorithm, $additional_headers, $recipient_key);
388
        }
389
390
        // Using KeyAgreementInterface or DirectEncryptionInterface, the encrypted key is an empty string
391
    }
392
393
    /**
394
     * @param array                                                       $complete_headers
395
     * @param string                                                      $cek
396
     * @param \Jose\Algorithm\KeyEncryption\KeyAgreementWrappingInterface $key_encryption_algorithm
397
     * @param \Jose\Algorithm\ContentEncryptionAlgorithmInterface         $content_encryption_algorithm
398
     * @param array                                                       $additional_headers
399
     * @param \Jose\Object\JWKInterface                                   $recipient_key
400
     *
401
     * @return string
402
     */
403
    private function getEncryptedKeyFromKeyAgreementAndKeyWrappingAlgorithm(array $complete_headers, $cek, KeyAgreementWrappingInterface $key_encryption_algorithm, ContentEncryptionAlgorithmInterface $content_encryption_algorithm, array &$additional_headers, JWKInterface $recipient_key)
404
    {
405
        $jwt_cek = $key_encryption_algorithm->wrapAgreementKey($recipient_key, $cek, $content_encryption_algorithm->getCEKSize(), $complete_headers, $additional_headers);
406
407
        return $jwt_cek;
408
    }
409
410
    /**
411
     * @param array                                                $complete_headers
412
     * @param string                                               $cek
413
     * @param \Jose\Algorithm\KeyEncryption\KeyEncryptionInterface $key_encryption_algorithm
414
     * @param \Jose\Object\JWKInterface                            $recipient_key
415
     * @param array                                                $additional_headers
416
     *
417
     * @return string
418
     */
419
    private function getEncryptedKeyFromKeyEncryptionAlgorithm(array $complete_headers, $cek, KeyEncryptionInterface $key_encryption_algorithm, JWKInterface $recipient_key, array &$additional_headers)
420
    {
421
        return $key_encryption_algorithm->encryptKey(
422
            $recipient_key,
423
            $cek,
424
            $complete_headers,
425
            $additional_headers
426
        );
427
    }
428
429
    /**
430
     * @param array                                              $complete_headers
431
     * @param string                                             $cek
432
     * @param \Jose\Algorithm\KeyEncryption\KeyWrappingInterface $key_encryption_algorithm
433
     * @param \Jose\Object\JWKInterface                          $recipient_key
434
     * @param array                                              $additional_headers
435
     *
436
     * @return string
437
     */
438
    private function getEncryptedKeyFromKeyWrappingAlgorithm(array $complete_headers, $cek, KeyWrappingInterface $key_encryption_algorithm, JWKInterface $recipient_key, &$additional_headers)
439
    {
440
        return $key_encryption_algorithm->wrapKey(
441
            $recipient_key,
442
            $cek,
443
            $complete_headers,
444
            $additional_headers
445
        );
446
    }
447
448
    /**
449
     * @param array $complete_headers
450
     *
451
     * @return \Jose\Algorithm\KeyEncryptionAlgorithmInterface
452
     */
453
    private function findKeyEncryptionAlgorithm(array $complete_headers)
454
    {
455
        Assertion::keyExists($complete_headers, 'alg', 'Parameter "alg" is missing.');
456
457
        $key_encryption_algorithm = $this->getJWAManager()->getAlgorithm($complete_headers['alg']);
458
        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']));
459
460
        return $key_encryption_algorithm;
461
    }
462
463
    /**
464
     * @param int $size
465
     *
466
     * @return string
467
     */
468
    private function createCEK($size)
469
    {
470
        return random_bytes($size / 8);
471
    }
472
473
    /**
474
     * @param int $size
475
     *
476
     * @return string
477
     */
478
    private function createIV($size)
479
    {
480
        return random_bytes($size / 8);
481
    }
482
}
483