GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.

AESGCMKWAlgorithm   A
last analyzed

Complexity

Total Complexity 11

Size/Duplication

Total Lines 137
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 11
eloc 40
dl 0
loc 137
ccs 37
cts 37
cp 1
rs 10
c 1
b 0
f 0

6 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 10 3
A _encryptKey() 0 8 1
A fromJWK() 0 13 3
A headerParameters() 0 5 1
A fromKey() 0 4 1
A _decryptKey() 0 8 2
1
<?php
2
3
declare(strict_types = 1);
4
5
namespace Sop\JWX\JWE\KeyAlgorithm;
6
7
use Sop\GCM\AESGCM;
8
use Sop\JWX\JWA\JWA;
9
use Sop\JWX\JWE\KeyAlgorithm\Feature\RandomCEK;
10
use Sop\JWX\JWE\KeyManagementAlgorithm;
11
use Sop\JWX\JWK\JWK;
12
use Sop\JWX\JWK\Symmetric\SymmetricKeyJWK;
13
use Sop\JWX\JWT\Header\Header;
14
use Sop\JWX\JWT\Parameter\AlgorithmParameter;
15
use Sop\JWX\JWT\Parameter\AuthenticationTagParameter;
16
use Sop\JWX\JWT\Parameter\InitializationVectorParameter;
17
18
/**
19
 * Base class for AES GCM key encryption algorithms.
20
 *
21
 * @see https://tools.ietf.org/html/rfc7518#section-4.7
22
 */
23
abstract class AESGCMKWAlgorithm extends KeyManagementAlgorithm
24
{
25
    use RandomCEK;
26
27
    /**
28
     * Mapping from algorithm name to class name.
29
     *
30
     * @internal
31
     *
32
     * @var array
33
     */
34
    public const MAP_ALGO_TO_CLASS = [
35
        JWA::ALGO_A128GCMKW => A128GCMKWAlgorithm::class,
36
        JWA::ALGO_A192GCMKW => A192GCMKWAlgorithm::class,
37
        JWA::ALGO_A256GCMKW => A256GCMKWAlgorithm::class,
38
    ];
39
40
    /**
41
     * Required IV size in bytes.
42
     *
43
     * @var int
44
     */
45
    public const IV_SIZE = 12;
46
47
    /**
48
     * Authentication tag size in bytes.
49
     *
50
     * @var int
51
     */
52
    public const AUTH_TAG_SIZE = 16;
53
54
    /**
55
     * Key encryption key.
56
     *
57
     * @var string
58
     */
59
    protected $_kek;
60
61
    /**
62
     * Initialization vector.
63
     *
64
     * @var string
65
     */
66
    protected $_iv;
67
68
    /**
69
     * Constructor.
70
     *
71
     * @param string $kek Key encryption key
72
     * @param string $iv  Initialization vector
73
     */
74 14
    public function __construct(string $kek, string $iv)
75
    {
76 14
        if (strlen($kek) !== $this->_keySize()) {
77 3
            throw new \LengthException('Invalid key size.');
78
        }
79 11
        if (self::IV_SIZE !== strlen($iv)) {
80 1
            throw new \LengthException('Initialization vector must be 96 bits.');
81
        }
82 10
        $this->_kek = $kek;
83 10
        $this->_iv = $iv;
84 10
    }
85
86
    /**
87
     * Initialize from JWK.
88
     *
89
     * @throws \UnexpectedValueException
90
     *
91
     * @return self
92
     */
93 7
    public static function fromJWK(JWK $jwk, Header $header): KeyManagementAlgorithm
94
    {
95 7
        $jwk = SymmetricKeyJWK::fromJWK($jwk);
96 7
        if (!$header->hasInitializationVector()) {
97 1
            throw new \UnexpectedValueException('No initialization vector.');
98
        }
99 6
        $iv = $header->initializationVector()->initializationVector();
100 6
        $alg = JWA::deriveAlgorithmName($header, $jwk);
101 5
        if (!array_key_exists($alg, self::MAP_ALGO_TO_CLASS)) {
102 1
            throw new \UnexpectedValueException("Unsupported algorithm '{$alg}'.");
103
        }
104 4
        $cls = self::MAP_ALGO_TO_CLASS[$alg];
105 4
        return new $cls($jwk->key(), $iv);
106
    }
107
108
    /**
109
     * Initialize from key encryption key with random IV.
110
     *
111
     * Key size must match the underlying cipher.
112
     *
113
     * @param string $key Key encryption key
114
     */
115 1
    public static function fromKey(string $key): self
116
    {
117 1
        $iv = openssl_random_pseudo_bytes(self::IV_SIZE);
118 1
        return new static($key, $iv);
119
    }
120
121
    /**
122
     * {@inheritdoc}
123
     */
124 2
    public function headerParameters(): array
125
    {
126 2
        return array_merge(parent::headerParameters(),
127 2
            [AlgorithmParameter::fromAlgorithm($this),
128 2
                InitializationVectorParameter::fromString($this->_iv), ]);
129
    }
130
131
    /**
132
     * Get the required key size.
133
     */
134
    abstract protected function _keySize(): int;
135
136
    /**
137
     * {@inheritdoc}
138
     */
139 5
    protected function _encryptKey(string $key, Header &$header): string
140
    {
141 5
        [$ciphertext, $auth_tag] = AESGCM::encrypt($key, '', $this->_kek,
142 5
            $this->_iv, self::AUTH_TAG_SIZE);
143
        // insert authentication tag to the header
144 5
        $header = $header->withParameters(
145 5
            AuthenticationTagParameter::fromString($auth_tag));
146 5
        return $ciphertext;
147
    }
148
149
    /**
150
     * {@inheritdoc}
151
     */
152 5
    protected function _decryptKey(string $ciphertext, Header $header): string
153
    {
154 5
        if (!$header->hasAuthenticationTag()) {
155 1
            throw new \RuntimeException(
156 1
                "Header doesn't contain authentication tag.");
157
        }
158 4
        $auth_tag = $header->authenticationTag()->authenticationTag();
159 4
        return AESGCM::decrypt($ciphertext, $auth_tag, '', $this->_kek, $this->_iv);
160
    }
161
}
162