Completed
Push — develop ( d84806...78f8e0 )
by Florent
02:53
created

Encrypter::computeRecipient()   B

Complexity

Conditions 3
Paths 2

Size

Total Lines 25
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 1 Features 0
Metric Value
c 3
b 1
f 0
dl 0
loc 25
rs 8.8571
cc 3
eloc 18
nc 2
nop 7

1 Method

Rating   Name   Duplication   Size   Complexity  
A Encrypter::getEncryptedKeyFromKeyAgreementAndKeyWrappingAlgorithm() 0 6 1
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\RecipientInterface;
31
use Jose\Util\StringUtil;
32
use Psr\Log\LoggerInterface;
33
34
/**
35
 */
36
final class Encrypter implements EncrypterInterface
37
{
38
    use HasKeyChecker;
39
    use HasJWAManager;
40
    use HasCompressionManager;
41
    use HasLogger;
42
43
    /**
44
     * Encrypter constructor.
45
     *
46
     * @param \Jose\Algorithm\JWAManagerInterface           $jwa_manager
47
     * @param \Jose\Compression\CompressionManagerInterface $compression_manager
48
     * @param \Psr\Log\LoggerInterface|null                 $logger
49
     */
50
    public function __construct(
51
        JWAManagerInterface $jwa_manager,
52
        CompressionManagerInterface $compression_manager,
53
        LoggerInterface $logger = null
54
    ) {
55
        $this->setJWAManager($jwa_manager);
56
        $this->setCompressionManager($compression_manager);
57
58
        if (null !== $logger) {
59
            $this->setLogger($logger);
60
        }
61
    }
62
63
    /**
64
     * {@inheritdoc}
65
     */
66
    public function encrypt(JWEInterface &$jwe)
67
    {
68
        Assertion::greaterThan($jwe->countRecipients(), 0, 'The JWE does not contain recipient.');
69
70
        // Content Encryption Algorithm
71
        $content_encryption_algorithm = $this->getContentEncryptionAlgorithm($jwe);
72
73
        // Compression Method
74
        $compression_method = $this->getCompressionMethod($jwe);
75
76
        // Key Management Mode
77
        $key_management_mode = $this->getKeyManagementMode($jwe);
78
79
        // Additional Headers
80
        $additional_headers = [];
81
82
        // CEK
83
        $cek = $this->determineCEK(
84
            $jwe,
85
            $content_encryption_algorithm,
0 ignored issues
show
Bug introduced by
It seems like $content_encryption_algorithm defined by $this->getContentEncryptionAlgorithm($jwe) on line 71 can be null; however, Jose\Encrypter::determineCEK() 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...
86
            $key_management_mode,
87
            $additional_headers
88
        );
89
90
        for($i = 0; $i < $jwe->countRecipients(); $i++) {
0 ignored issues
show
Performance Best Practice introduced by
Consider avoiding function calls on each iteration of the for loop.

If you have a function call in the test part of a for loop, this function is executed on each iteration. Often such a function, can be moved to the initialization part and be cached.

// count() is called on each iteration
for ($i=0; $i < count($collection); $i++) { }

// count() is only called once
for ($i=0, $c=count($collection); $i<$c; $i++) { }
Loading history...
91
92
            $this->processRecipient(
93
                $jwe,
94
                $jwe->getRecipient($i),
95
                $cek,
96
                $content_encryption_algorithm,
0 ignored issues
show
Bug introduced by
It seems like $content_encryption_algorithm defined by $this->getContentEncryptionAlgorithm($jwe) on line 71 can be null; however, Jose\Encrypter::processRecipient() 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...
97
                $additional_headers
98
            );
99
        }
100
101
        if (!empty($additional_headers) && 1 === $jwe->countRecipients()) {
102
            $jwe = $jwe->withSharedProtectedHeaders(array_merge(
103
                $jwe->getSharedProtectedHeaders(),
104
                $additional_headers
105
            ));
106
        }
107
108
        // IV
109
        if (null !== $iv_size = $content_encryption_algorithm->getIVSize()) {
110
            $iv = $this->createIV($iv_size);
111
            $jwe = $jwe->withIV($iv);
112
        }
113
114
        $jwe = $jwe ->withContentEncryptionKey($cek);
115
116
        $this->encryptJWE($jwe, $content_encryption_algorithm, $compression_method);
0 ignored issues
show
Bug introduced by
It seems like $content_encryption_algorithm defined by $this->getContentEncryptionAlgorithm($jwe) on line 71 can be null; however, Jose\Encrypter::encryptJWE() 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...
117
    }
118
119
    /**
120
     * @param \Jose\Object\JWEInterface                           $jwe
121
     * @param \Jose\Object\RecipientInterface                     $recipient
122
     * @param string                                              $cek
123
     * @param \Jose\Algorithm\ContentEncryptionAlgorithmInterface $content_encryption_algorithm
124
     * @param array                                               $additional_headers
125
     */
126
    private function processRecipient(JWEInterface $jwe,
127
                                      RecipientInterface &$recipient,
128
                                      $cek,
129
                                      ContentEncryptionAlgorithmInterface $content_encryption_algorithm,
130
                                      array &$additional_headers
131
    ) {
132
        $complete_headers = array_merge(
133
            $jwe->getSharedProtectedHeaders(),
134
            $jwe->getSharedHeaders(),
135
            $recipient->getHeaders()
136
        );
137
138
        $key_encryption_algorithm = $this->findKeyEncryptionAlgorithm($complete_headers);
139
140
        // We check keys (usage and algorithm if restrictions are set)
141
        $this->checkKeys(
142
            $key_encryption_algorithm,
0 ignored issues
show
Bug introduced by
It seems like $key_encryption_algorithm defined by $this->findKeyEncryption...ithm($complete_headers) on line 138 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...
143
            $content_encryption_algorithm,
144
            $recipient->getRecipientKey()
145
        );
146
147
        $encrypted_content_encryption_key = $this->getEncryptedKey(
148
            $complete_headers,
149
            $cek,
150
            $key_encryption_algorithm,
0 ignored issues
show
Bug introduced by
It seems like $key_encryption_algorithm defined by $this->findKeyEncryption...ithm($complete_headers) on line 138 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...
151
            $content_encryption_algorithm,
152
            $additional_headers,
153
            $recipient->getRecipientKey()
154
        );
155
156
        if (!empty($additional_headers) && 1 !== $jwe->countRecipients()) {
157
            foreach ($additional_headers as $key => $value) {
158
                $recipient = $recipient->withHeader($key, $value);
159
            }
160
        }
161
        if (null !== $encrypted_content_encryption_key) {
162
            $recipient = $recipient->withEncryptedKey($encrypted_content_encryption_key);
163
        }
164
    }
165
166
    /**
167
     * @param \Jose\Object\JWEInterface                           $jwe
168
     * @param \Jose\Algorithm\ContentEncryptionAlgorithmInterface $content_encryption_algorithm
169
     * @param string                                               $key_management_mode
170
     * @param array                                                $additional_headers
171
     *
172
     * @return string
173
     */
174
    private function determineCEK(JWEInterface $jwe,
175
                                  ContentEncryptionAlgorithmInterface $content_encryption_algorithm,
176
                                  $key_management_mode,
177
                                  array &$additional_headers
178
    ) {
179
        switch($key_management_mode) {
180
            case KeyEncryptionInterface::MODE_ENCRYPT:
181
            case KeyEncryptionInterface::MODE_WRAP:
182
                return $this->createCEK($content_encryption_algorithm->getCEKSize());
183
            case KeyEncryptionInterface::MODE_AGREEMENT:
184
                Assertion::eq(1, $jwe->countRecipients(), 'Unable to encrypt for multiple recipients using key agreement algorithms.');
185
186
                $complete_headers = array_merge(
187
                    $jwe->getSharedProtectedHeaders(),
188
                    $jwe->getSharedHeaders(),
189
                    $jwe->getRecipient(0)->getHeaders()
190
                );
191
                $algorithm = $this->findKeyEncryptionAlgorithm($complete_headers);
192
193
                return $algorithm->getAgreementKey($content_encryption_algorithm->getCEKSize(), $content_encryption_algorithm->getAlgorithmName(), $jwe->getRecipient(0)->getRecipientKey(), $complete_headers, $additional_headers);
194
            case KeyEncryptionInterface::MODE_DIRECT:
195
                Assertion::eq(1, $jwe->countRecipients(), 'Unable to encrypt for multiple recipients using key agreement algorithms.');
196
197
                Assertion::eq($jwe->getRecipient(0)->getRecipientKey()->get('kty'), 'oct', 'Wrong key type.');
198
                Assertion::true($jwe->getRecipient(0)->getRecipientKey()->has('k'), 'The key parameter "k" is missing.');
199
200
                return Base64Url::decode($jwe->getRecipient(0)->getRecipientKey()->get('k'));
201
            default:
202
                throw new \InvalidArgumentException(sprintf('Unsupported key management mode "%s".', $key_management_mode));
203
        }
204
    }
205
206
    /**
207
     * @param \Jose\Object\JWEInterface $jwe
208
     *
209
     * @return string
210
     */
211
    private function getKeyManagementMode(JWEInterface $jwe)
212
    {
213
        $mode = null;
214
215
        foreach($jwe->getRecipients() as $recipient) {
216
            $complete_headers = array_merge(
217
                $jwe->getSharedProtectedHeaders(),
218
                $jwe->getSharedHeaders(),
219
                $recipient->getHeaders()
220
            );
221
            Assertion::keyExists($complete_headers, 'alg', 'Parameter "alg" is missing.');
222
223
            $key_encryption_algorithm = $this->getJWAManager()->getAlgorithm($complete_headers['alg']);
224
            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']));
225
226
            if (null === $mode) {
227
                $mode = $key_encryption_algorithm->getKeyManagementMode();
228
            } else {
229
                Assertion::true(
230
                    $this->areKeyManagementModesCompatible($mode, $key_encryption_algorithm->getKeyManagementMode()),
231
                    'Foreign key management mode forbidden.'
232
                );
233
            }
234
        }
235
236
        return $mode;
237
    }
238
239
    /**
240
     * @param \Jose\Object\JWEInterface $jwe
241
     *
242
     * @return \Jose\Algorithm\ContentEncryptionAlgorithmInterface
243
     */
244
    private function getCompressionMethod(JWEInterface $jwe)
245
    {
246
        $method = null;
247
248
        for($i = 0; $i < $jwe->countRecipients(); $i++) {
0 ignored issues
show
Performance Best Practice introduced by
Consider avoiding function calls on each iteration of the for loop.

If you have a function call in the test part of a for loop, this function is executed on each iteration. Often such a function, can be moved to the initialization part and be cached.

// count() is called on each iteration
for ($i=0; $i < count($collection); $i++) { }

// count() is only called once
for ($i=0, $c=count($collection); $i<$c; $i++) { }
Loading history...
249
            $complete_headers = array_merge(
250
                $jwe->getSharedProtectedHeaders(),
251
                $jwe->getSharedHeaders(),
252
                $jwe->getRecipient($i)->getHeaders()
253
            );
254
            if (array_key_exists('zip', $complete_headers)) {
255
                if (null === $method) {
256
                    if (0 === $i) {
257
                        $method = $complete_headers['zip'];
258
                    } else {
259
                        throw new \InvalidArgumentException('Inconsistent "zip" parameter.');
260
                    }
261
                } else {
262
                    Assertion::eq($method, $complete_headers['enc'], 'Foreign compression methods are not allowed.');
263
                }
264
            } else {
265
                if (null !== $method) {
266
                    throw new \InvalidArgumentException('Inconsistent "zip" parameter.');
267
                }
268
            }
269
        }
270
271
        if (null ===$method) {
272
            return;
273
        }
274
275
        $compression_method = $this->getCompressionManager()->getCompressionAlgorithm($method);
276
        Assertion::isInstanceOf($compression_method, CompressionInterface::class, sprintf('Compression method "%s" not supported.', $method));
277
278
        return $compression_method;
279
    }
280
281
    /**
282
     * @param \Jose\Object\JWEInterface $jwe
283
     *
284
     * @return \Jose\Algorithm\ContentEncryptionAlgorithmInterface
285
     */
286
    private function getContentEncryptionAlgorithm(JWEInterface $jwe)
287
    {
288
        $algorithm = null;
289
290
        foreach($jwe->getRecipients() as $recipient) {
291
            $complete_headers = array_merge(
292
                $jwe->getSharedProtectedHeaders(),
293
                $jwe->getSharedHeaders(),
294
                $recipient->getHeaders()
295
            );
296
            Assertion::keyExists($complete_headers, 'enc', 'Parameter "enc" is missing.');
297
            if (null === $algorithm) {
298
                $algorithm = $complete_headers['enc'];
299
            } else {
300
                Assertion::eq($algorithm, $complete_headers['enc'], 'Foreign content encryption algorithms are not allowed.');
301
            }
302
        }
303
304
        $content_encryption_algorithm = $this->getJWAManager()->getAlgorithm($algorithm);
305
        Assertion::isInstanceOf($content_encryption_algorithm, ContentEncryptionAlgorithmInterface::class, sprintf('The content encryption algorithm "%s" is not supported or not a content encryption algorithm instance.', $algorithm));
306
307
        return $content_encryption_algorithm;
308
    }
309
310
    /**
311
     * @param \Jose\Object\JWEInterface                           $jwe
312
     * @param \Jose\Algorithm\ContentEncryptionAlgorithmInterface $content_encryption_algorithm
313
     * @param \Jose\Compression\CompressionInterface|null         $compression_method
314
     */
315
    private function encryptJWE(JWEInterface &$jwe,
316
                                ContentEncryptionAlgorithmInterface $content_encryption_algorithm,
317
                                CompressionInterface $compression_method = null
318
    ) {
319
        if (!empty($jwe->getSharedProtectedHeaders())) {
320
            $jwe = $jwe->withEncodedSharedProtectedHeaders(Base64Url::encode(json_encode($jwe->getSharedProtectedHeaders())));
321
        }
322
323
        // We encrypt the payload and get the tag
324
        $tag = null;
325
        $payload = $this->preparePayload($jwe->getPayload(), $compression_method);
326
327
        $ciphertext = $content_encryption_algorithm->encryptContent(
328
            $payload,
329
            $jwe->getContentEncryptionKey(),
330
            $jwe->getIV(),
331
            $jwe->getAAD(),
332
            $jwe->getEncodedSharedProtectedHeaders(),
333
            $tag
334
        );
335
        $jwe = $jwe->withCiphertext($ciphertext);
336
337
        // Tag
338
        if (null !== $tag) {
339
            $jwe = $jwe->withTag($tag);
340
        }
341
    }
342
343
    /**
344
     * @param \Jose\Algorithm\KeyEncryptionAlgorithmInterface     $key_encryption_algorithm
345
     * @param \Jose\Algorithm\ContentEncryptionAlgorithmInterface $content_encryption_algorithm
346
     * @param \Jose\Object\JWKInterface                           $recipient_key
347
     */
348
    private function checkKeys(KeyEncryptionAlgorithmInterface $key_encryption_algorithm, ContentEncryptionAlgorithmInterface $content_encryption_algorithm, JWKInterface $recipient_key)
349
    {
350
        $this->checkKeyUsage($recipient_key, 'encryption');
351
        if ('dir' !== $key_encryption_algorithm->getAlgorithmName()) {
352
            $this->checkKeyAlgorithm($recipient_key, $key_encryption_algorithm->getAlgorithmName());
353
        } else {
354
            $this->checkKeyAlgorithm($recipient_key, $content_encryption_algorithm->getAlgorithmName());
355
        }
356
    }
357
358
    /**
359
     * @param string $current
360
     * @param string $new
361
     *
362
     * @return bool
363
     */
364
    private function areKeyManagementModesCompatible($current, $new)
365
    {
366
        $agree = KeyEncryptionAlgorithmInterface::MODE_AGREEMENT;
367
        $dir = KeyEncryptionAlgorithmInterface::MODE_DIRECT;
368
        $enc = KeyEncryptionAlgorithmInterface::MODE_ENCRYPT;
369
        $wrap = KeyEncryptionAlgorithmInterface::MODE_WRAP;
370
371
        $supported_key_management_mode_combinations = [
372
            $enc.$enc     => true,
373
            $enc.$wrap    => true,
374
            $wrap.$enc    => true,
375
            $wrap.$wrap   => true,
376
            $agree.$agree => false,
377
            $agree.$dir   => false,
378
            $agree.$enc   => false,
379
            $agree.$wrap  => false,
380
            $dir.$agree   => false,
381
            $dir.$dir     => false,
382
            $dir.$enc     => false,
383
            $dir.$wrap    => false,
384
            $enc.$agree   => false,
385
            $enc.$dir     => false,
386
            $wrap.$agree  => false,
387
            $wrap.$dir    => false,
388
        ];
389
390
        if (array_key_exists($current.$new, $supported_key_management_mode_combinations)) {
391
            return $supported_key_management_mode_combinations[$current.$new];
392
        }
393
394
        return false;
395
    }
396
397
    /**
398
     * @param string                                      $payload
399
     * @param \Jose\Compression\CompressionInterface|null $compression_method
400
     *
401
     * @return string
402
     */
403
    private function preparePayload($payload, CompressionInterface $compression_method = null)
404
    {
405
        $prepared = is_string($payload) ? $payload : json_encode($payload);
406
407
        Assertion::notNull($prepared, 'The payload is empty or cannot encoded into JSON.');
408
409
        if (null === $compression_method) {
410
            return $prepared;
411
        }
412
        $compressed_payload = $compression_method->compress($prepared);
413
        Assertion::string($compressed_payload, 'Compression failed.');
414
415
        return $compressed_payload;
416
    }
417
418
    /**
419
     * @param array                                               $complete_headers
420
     * @param string                                              $cek
421
     * @param \Jose\Algorithm\KeyEncryptionAlgorithmInterface     $key_encryption_algorithm
422
     * @param \Jose\Algorithm\ContentEncryptionAlgorithmInterface $content_encryption_algorithm
423
     * @param \Jose\Object\JWKInterface                           $recipient_key
424
     * @param array                                               $additional_headers
425
     *
426
     * @return string|null
427
     */
428
    private function getEncryptedKey(array $complete_headers, $cek, KeyEncryptionAlgorithmInterface $key_encryption_algorithm, ContentEncryptionAlgorithmInterface $content_encryption_algorithm, array &$additional_headers, JWKInterface $recipient_key)
429
    {
430
        if ($key_encryption_algorithm instanceof KeyEncryptionInterface) {
431
            return $this->getEncryptedKeyFromKeyEncryptionAlgorithm($complete_headers, $cek, $key_encryption_algorithm, $recipient_key, $additional_headers);
432
        } elseif ($key_encryption_algorithm instanceof KeyWrappingInterface) {
433
            return $this->getEncryptedKeyFromKeyWrappingAlgorithm($complete_headers, $cek, $key_encryption_algorithm, $recipient_key, $additional_headers);
434
        } elseif ($key_encryption_algorithm instanceof KeyAgreementWrappingInterface) {
435
            return $this->getEncryptedKeyFromKeyAgreementAndKeyWrappingAlgorithm($complete_headers, $cek, $key_encryption_algorithm, $content_encryption_algorithm, $additional_headers, $recipient_key);
436
        }
437
438
        // Using KeyAgreementInterface or DirectEncryptionInterface, the encrypted key is an empty string
439
    }
440
441
    /**
442
     * @param array                                                       $complete_headers
443
     * @param string                                                      $cek
444
     * @param \Jose\Algorithm\KeyEncryption\KeyAgreementWrappingInterface $key_encryption_algorithm
445
     * @param \Jose\Algorithm\ContentEncryptionAlgorithmInterface         $content_encryption_algorithm
446
     * @param array                                                       $additional_headers
447
     * @param \Jose\Object\JWKInterface                                   $recipient_key
448
     *
449
     * @return string
450
     */
451
    private function getEncryptedKeyFromKeyAgreementAndKeyWrappingAlgorithm(array $complete_headers, $cek, KeyAgreementWrappingInterface $key_encryption_algorithm, ContentEncryptionAlgorithmInterface $content_encryption_algorithm, array &$additional_headers, JWKInterface $recipient_key)
452
    {
453
        $jwt_cek = $key_encryption_algorithm->wrapAgreementKey($recipient_key, $cek, $content_encryption_algorithm->getCEKSize(), $complete_headers, $additional_headers);
454
455
        return $jwt_cek;
456
    }
457
458
    /**
459
     * @param array                                                $complete_headers
460
     * @param string                                               $cek
461
     * @param \Jose\Algorithm\KeyEncryption\KeyEncryptionInterface $key_encryption_algorithm
462
     * @param \Jose\Object\JWKInterface                            $recipient_key
463
     * @param array                                                $additional_headers
464
     *
465
     * @return string
466
     */
467
    private function getEncryptedKeyFromKeyEncryptionAlgorithm(array $complete_headers, $cek, KeyEncryptionInterface $key_encryption_algorithm, JWKInterface $recipient_key, array &$additional_headers)
468
    {
469
        return $key_encryption_algorithm->encryptKey(
470
            $recipient_key,
471
            $cek,
472
            $complete_headers,
473
            $additional_headers
474
        );
475
    }
476
477
    /**
478
     * @param array                                              $complete_headers
479
     * @param string                                             $cek
480
     * @param \Jose\Algorithm\KeyEncryption\KeyWrappingInterface $key_encryption_algorithm
481
     * @param \Jose\Object\JWKInterface                          $recipient_key
482
     * @param array                                              $additional_headers
483
     *
484
     * @return string
485
     */
486
    private function getEncryptedKeyFromKeyWrappingAlgorithm(array $complete_headers, $cek, KeyWrappingInterface $key_encryption_algorithm, JWKInterface $recipient_key, &$additional_headers)
487
    {
488
        return $key_encryption_algorithm->wrapKey(
489
            $recipient_key,
490
            $cek,
491
            $complete_headers,
492
            $additional_headers
493
        );
494
    }
495
496
    /**
497
     * @param array $complete_headers
498
     *
499
     * @return \Jose\Algorithm\KeyEncryptionAlgorithmInterface
500
     */
501
    private function findKeyEncryptionAlgorithm(array $complete_headers)
502
    {
503
        Assertion::keyExists($complete_headers, 'alg', 'Parameter "alg" is missing.');
504
505
        $key_encryption_algorithm = $this->getJWAManager()->getAlgorithm($complete_headers['alg']);
506
        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']));
507
508
        return $key_encryption_algorithm;
509
    }
510
511
    /**
512
     * @param int $size
513
     *
514
     * @return string
515
     */
516
    private function createCEK($size)
517
    {
518
        return StringUtil::generateRandomBytes($size / 8);
519
    }
520
521
    /**
522
     * @param int $size
523
     *
524
     * @return string
525
     */
526
    private function createIV($size)
527
    {
528
        return StringUtil::generateRandomBytes($size / 8);
529
    }
530
}
531