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.
Passed
Branch php72 (880eb0)
by Joni
05:58
created

AESCBCAlgorithm   A

Complexity

Total Complexity 21

Size/Duplication

Total Lines 209
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 2

Test Coverage

Coverage 95.16%

Importance

Changes 0
Metric Value
wmc 21
lcom 1
cbo 2
dl 0
loc 209
ccs 59
cts 62
cp 0.9516
rs 10
c 0
b 0
f 0

11 Methods

Rating   Name   Duplication   Size   Complexity  
A _computeAuthTag() 0 4 1
A headerParameters() 0 3 1
A encrypt() 0 14 2
A _validateKey() 0 4 2
A _validateIV() 0 5 2
A decrypt() 0 16 3
A _aadLen() 0 7 2
A _macKey() 0 3 1
A _getCipherMethod() 0 14 3
A ivSize() 0 3 1
A _encKey() 0 3 1
1
<?php
2
3
declare(strict_types = 1);
4
5
namespace Sop\JWX\JWE\EncryptionAlgorithm;
6
7
use Sop\JWX\JWE\ContentEncryptionAlgorithm;
8
use Sop\JWX\JWE\Exception\AuthenticationException;
9
use Sop\JWX\JWT\Parameter\EncryptionAlgorithmParameter;
10
11
/**
12
 * Base class for algorithms implementing AES in CBC mode with HMAC-SHA.
13
 *
14
 * @see https://tools.ietf.org/html/rfc7518#section-5.2
15
 */
16
abstract class AESCBCAlgorithm implements ContentEncryptionAlgorithm
17
{
18
    /**
19
     * {@inheritdoc}
20
     */
21 23
    public function encrypt(string $plaintext, string $key, string $iv,
22
        string $aad): array
23
    {
24 23
        $this->_validateKey($key);
25 22
        $this->_validateIV($iv);
26 20
        $ciphertext = openssl_encrypt($plaintext, $this->_getCipherMethod(),
27 20
            $this->_encKey($key), OPENSSL_RAW_DATA, $iv);
28 20
        if (false === $ciphertext) {
29
            throw new \RuntimeException(
30
                'openssl_encrypt() failed: ' . $this->_getLastOpenSSLError());
31
        }
32 20
        $auth_data = $aad . $iv . $ciphertext . $this->_aadLen($aad);
33 20
        $auth_tag = $this->_computeAuthTag($auth_data, $key);
34 20
        return [$ciphertext, $auth_tag];
35
    }
36
37
    /**
38
     * {@inheritdoc}
39
     */
40 17
    public function decrypt(string $ciphertext, string $key, string $iv,
41
        string $aad, string $auth_tag): string
42
    {
43 17
        $this->_validateKey($key);
44 17
        $this->_validateIV($iv);
45 17
        $auth_data = $aad . $iv . $ciphertext . $this->_aadLen($aad);
46 17
        if ($this->_computeAuthTag($auth_data, $key) !== $auth_tag) {
47 1
            throw new AuthenticationException('Message authentication failed.');
48
        }
49 16
        $plaintext = openssl_decrypt($ciphertext, $this->_getCipherMethod(),
50 16
            $this->_encKey($key), OPENSSL_RAW_DATA, $iv);
51 16
        if (false === $plaintext) {
52 1
            throw new \RuntimeException(
53 1
                'openssl_decrypt() failed: ' . $this->_getLastOpenSSLError());
54
        }
55 15
        return $plaintext;
56
    }
57
58
    /**
59
     * {@inheritdoc}
60
     */
61 13
    public function ivSize(): int
62
    {
63 13
        return 16;
64
    }
65
66
    /**
67
     * {@inheritdoc}
68
     */
69 11
    public function headerParameters(): array
70
    {
71 11
        return [EncryptionAlgorithmParameter::fromAlgorithm($this)];
72
    }
73
74
    /**
75
     * Get cipher method name that is recognized by OpenSSL.
76
     *
77
     * @return string
78
     */
79
    abstract protected function _cipherMethod(): string;
80
81
    /**
82
     * Get algorithm name that is recognized by the Hash extension.
83
     *
84
     * @return string
85
     */
86
    abstract protected function _hashAlgo(): string;
87
88
    /**
89
     * Get length of the encryption key.
90
     *
91
     * @return int
92
     */
93
    abstract protected function _encKeyLen(): int;
94
95
    /**
96
     * Get length of the MAC key.
97
     *
98
     * @return int
99
     */
100
    abstract protected function _macKeyLen(): int;
101
102
    /**
103
     * Get length of the authentication tag.
104
     *
105
     * @return int
106
     */
107
    abstract protected function _tagLen(): int;
108
109
    /**
110
     * Get cipher method and verify that it's supported.
111
     *
112
     * @throws \RuntimeException
113
     *
114
     * @return string
115
     */
116 38
    final protected function _getCipherMethod(): string
117
    {
118 38
        static $supported_ciphers;
119 38
        if (!isset($supported_ciphers)) {
120 4
            $supported_ciphers = array_flip(
121 4
                array_map('strtolower', openssl_get_cipher_methods(false)));
122
        }
123 38
        $method = $this->_cipherMethod();
124 38
        if (!isset($supported_ciphers[$method])) {
125 1
            throw new \RuntimeException(
126 1
                "Cipher method {$method} is not" .
127 1
                     ' supported by this version of OpenSSL.');
128
        }
129 37
        return $method;
130
    }
131
132
    /**
133
     * Check that key is valid.
134
     *
135
     * @param string $key
136
     *
137
     * @throws \RuntimeException
138
     */
139 39
    final protected function _validateKey(string $key): void
140
    {
141 39
        if (strlen($key) !== $this->keySize()) {
142 1
            throw new \RuntimeException('Invalid key size.');
143
        }
144 38
    }
145
146
    /**
147
     * Check that IV is valid.
148
     *
149
     * @param string $iv
150
     *
151
     * @throws \RuntimeException
152
     */
153 38
    final protected function _validateIV(string $iv): void
154
    {
155 38
        $len = openssl_cipher_iv_length($this->_getCipherMethod());
156 37
        if ($len !== strlen($iv)) {
157 1
            throw new \RuntimeException('Invalid IV length.');
158
        }
159 36
    }
160
161
    /**
162
     * Get MAC key from CEK.
163
     *
164
     * @param string $key
165
     *
166
     * @return string
167
     */
168 36
    final protected function _macKey(string $key): string
169
    {
170 36
        return substr($key, 0, $this->_macKeyLen());
171
    }
172
173
    /**
174
     * Get encryption key from CEK.
175
     *
176
     * @param string $key
177
     *
178
     * @return string
179
     */
180 36
    final protected function _encKey(string $key): string
181
    {
182 36
        return substr($key, -$this->_encKeyLen());
183
    }
184
185
    /**
186
     * Compute AL value.
187
     *
188
     * @param string $aad
189
     *
190
     * @return string 64 bits
191
     */
192 36
    final protected function _aadLen(string $aad): string
193
    {
194
        // truncate on 32 bit hosts
195 36
        if (PHP_INT_SIZE < 8) {
196
            return "\0\0\0\0" . pack('N', strlen($aad) * 8);
197
        }
198 36
        return pack('J', strlen($aad) * 8);
199
    }
200
201
    /**
202
     * Compute authentication tag.
203
     *
204
     * @param string $data
205
     * @param string $key  CEK
206
     *
207
     * @return string
208
     */
209 36
    final protected function _computeAuthTag(string $data, string $key): string
210
    {
211 36
        $tag = hash_hmac($this->_hashAlgo(), $data, $this->_macKey($key), true);
212 36
        return substr($tag, 0, $this->_tagLen());
213
    }
214
215
    /**
216
     * Get last OpenSSL error message.
217
     *
218
     * @return null|string
219
     */
220 1
    protected function _getLastOpenSSLError(): ?string
221
    {
222 1
        $msg = null;
223 1
        while (false !== ($err = openssl_error_string())) {
224 1
            $msg = $err;
225
        }
226 1
        return $msg;
227
    }
228
}
229