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.

AESCBCAlgorithm::_encKey()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
eloc 1
dl 0
loc 3
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
crap 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
    abstract protected function _cipherMethod(): string;
78
79
    /**
80
     * Get algorithm name that is recognized by the Hash extension.
81
     */
82
    abstract protected function _hashAlgo(): string;
83
84
    /**
85
     * Get length of the encryption key.
86
     */
87
    abstract protected function _encKeyLen(): int;
88
89
    /**
90
     * Get length of the MAC key.
91
     */
92
    abstract protected function _macKeyLen(): int;
93
94
    /**
95
     * Get length of the authentication tag.
96
     */
97
    abstract protected function _tagLen(): int;
98
99
    /**
100
     * Get cipher method and verify that it's supported.
101
     *
102
     * @throws \RuntimeException
103
     */
104 38
    final protected function _getCipherMethod(): string
105
    {
106 38
        static $supported_ciphers;
107 38
        if (!isset($supported_ciphers)) {
108 4
            $supported_ciphers = array_flip(
109 4
                array_map('strtolower', openssl_get_cipher_methods(false)));
110
        }
111 38
        $method = $this->_cipherMethod();
112 38
        if (!isset($supported_ciphers[$method])) {
113 1
            throw new \RuntimeException(
114 1
                "Cipher method {$method} is not" .
115 1
                     ' supported by this version of OpenSSL.');
116
        }
117 37
        return $method;
118
    }
119
120
    /**
121
     * Check that key is valid.
122
     *
123
     * @throws \RuntimeException
124
     */
125 39
    final protected function _validateKey(string $key): void
126
    {
127 39
        if (strlen($key) !== $this->keySize()) {
128 1
            throw new \RuntimeException('Invalid key size.');
129
        }
130 38
    }
131
132
    /**
133
     * Check that IV is valid.
134
     *
135
     * @throws \RuntimeException
136
     */
137 38
    final protected function _validateIV(string $iv): void
138
    {
139 38
        $len = openssl_cipher_iv_length($this->_getCipherMethod());
140 37
        if ($len !== strlen($iv)) {
141 1
            throw new \RuntimeException('Invalid IV length.');
142
        }
143 36
    }
144
145
    /**
146
     * Get MAC key from CEK.
147
     */
148 36
    final protected function _macKey(string $key): string
149
    {
150 36
        return substr($key, 0, $this->_macKeyLen());
151
    }
152
153
    /**
154
     * Get encryption key from CEK.
155
     */
156 36
    final protected function _encKey(string $key): string
157
    {
158 36
        return substr($key, -$this->_encKeyLen());
159
    }
160
161
    /**
162
     * Compute AL value.
163
     *
164
     * @return string 64 bits
165
     */
166 36
    final protected function _aadLen(string $aad): string
167
    {
168
        // truncate on 32 bit hosts
169 36
        if (PHP_INT_SIZE < 8) {
170
            return "\0\0\0\0" . pack('N', strlen($aad) * 8);
171
        }
172 36
        return pack('J', strlen($aad) * 8);
173
    }
174
175
    /**
176
     * Compute authentication tag.
177
     *
178
     * @param string $key CEK
179
     */
180 36
    final protected function _computeAuthTag(string $data, string $key): string
181
    {
182 36
        $tag = hash_hmac($this->_hashAlgo(), $data, $this->_macKey($key), true);
183 36
        return substr($tag, 0, $this->_tagLen());
184
    }
185
186
    /**
187
     * Get last OpenSSL error message.
188
     */
189 1
    protected function _getLastOpenSSLError(): ?string
190
    {
191 1
        $msg = null;
192 1
        while (false !== ($err = openssl_error_string())) {
193 1
            $msg = $err;
194
        }
195 1
        return $msg;
196
    }
197
}
198