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

PBES2Algorithm   A

Complexity

Total Complexity 14

Size/Duplication

Total Lines 200
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 9

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 14
lcom 1
cbo 9
dl 0
loc 200
ccs 43
cts 43
cp 1
rs 10
c 0
b 0
f 0

10 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 5 1
A fromJWK() 0 17 4
A salt() 0 4 1
A headerParameters() 0 6 1
A fromPassword() 0 5 1
A saltInput() 0 3 1
A iterationCount() 0 3 1
A _encryptKey() 0 3 1
A _derivedKey() 0 8 2
A _decryptKey() 0 3 1
1
<?php
2
3
declare(strict_types = 1);
4
5
namespace Sop\JWX\JWE\KeyAlgorithm;
6
7
use Sop\AESKW\AESKeyWrapAlgorithm;
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\PBES2CountParameter;
16
use Sop\JWX\JWT\Parameter\PBES2SaltInputParameter;
17
18
/**
19
 * Base class for algorithms implementing PBES2 key encryption.
20
 *
21
 * @see https://tools.ietf.org/html/rfc7518#section-4.8
22
 */
23
abstract class PBES2Algorithm 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
    const MAP_ALGO_TO_CLASS = [
35
        JWA::ALGO_PBES2_HS256_A128KW => PBES2HS256A128KWAlgorithm::class,
36
        JWA::ALGO_PBES2_HS384_A192KW => PBES2HS384A192KWAlgorithm::class,
37
        JWA::ALGO_PBES2_HS512_A256KW => PBES2HS512A256KWAlgorithm::class,
38
    ];
39
40
    /**
41
     * Password.
42
     *
43
     * @var string
44
     */
45
    protected $_password;
46
47
    /**
48
     * Salt input.
49
     *
50
     * @var string
51
     */
52
    protected $_saltInput;
53
54
    /**
55
     * Iteration count.
56
     *
57
     * @var int
58
     */
59
    protected $_count;
60
61
    /**
62
     * Derived key.
63
     *
64
     * @var string
65
     */
66
    private $_derivedKey;
67
68
    /**
69
     * Constructor.
70
     *
71
     * @param string $password   Password
72
     * @param string $salt_input Salt input
73
     * @param int    $count      Iteration count
74
     */
75 10
    public function __construct(string $password, string $salt_input, int $count)
76
    {
77 10
        $this->_password = $password;
78 10
        $this->_saltInput = $salt_input;
79 10
        $this->_count = $count;
80 10
    }
81
82
    /**
83
     * Initialize from JWK.
84
     *
85
     * @param JWK    $jwk
86
     * @param Header $header
87
     *
88
     * @throws \UnexpectedValueException
89
     *
90
     * @return self
91
     */
92 7
    public static function fromJWK(JWK $jwk, Header $header): KeyManagementAlgorithm
93
    {
94 7
        $jwk = SymmetricKeyJWK::fromJWK($jwk);
95 7
        if (!$header->hasPBES2SaltInput()) {
96 1
            throw new \UnexpectedValueException('No salt input.');
97
        }
98 6
        $salt_input = $header->PBES2SaltInput()->saltInput();
99 6
        if (!$header->hasPBES2Count()) {
100 1
            throw new \UnexpectedValueException('No iteration count.');
101
        }
102 5
        $count = $header->PBES2Count()->value();
103 5
        $alg = JWA::deriveAlgorithmName($header, $jwk);
104 5
        if (!array_key_exists($alg, self::MAP_ALGO_TO_CLASS)) {
105 1
            throw new \UnexpectedValueException("Unsupported algorithm '{$alg}'.");
106
        }
107 4
        $cls = self::MAP_ALGO_TO_CLASS[$alg];
108 4
        return new $cls($jwk->key(), $salt_input, $count);
109
    }
110
111
    /**
112
     * Initialize from a password with random salt and default iteration count.
113
     *
114
     * @param string $password   Password
115
     * @param int    $count      Optional user defined iteration count
116
     * @param int    $salt_bytes Optional user defined salt length
117
     *
118
     * @return self
119
     */
120 1
    public static function fromPassword(string $password, int $count = 64000,
121
        int $salt_bytes = 8): self
122
    {
123 1
        $salt_input = openssl_random_pseudo_bytes($salt_bytes);
124 1
        return new static($password, $salt_input, $count);
125
    }
126
127
    /**
128
     * Get salt input.
129
     *
130
     * @return string
131
     */
132 1
    public function saltInput(): string
133
    {
134 1
        return $this->_saltInput;
135
    }
136
137
    /**
138
     * Get computed salt.
139
     *
140
     * @return string
141
     */
142 9
    public function salt(): string
143
    {
144 9
        return PBES2SaltInputParameter::fromString($this->_saltInput)->salt(
145 9
            AlgorithmParameter::fromAlgorithm($this));
146
    }
147
148
    /**
149
     * Get iteration count.
150
     *
151
     * @return int
152
     */
153 1
    public function iterationCount(): int
154
    {
155 1
        return $this->_count;
156
    }
157
158
    /**
159
     * {@inheritdoc}
160
     */
161 3
    public function headerParameters(): array
162
    {
163 3
        return array_merge(parent::headerParameters(),
164 3
            [AlgorithmParameter::fromAlgorithm($this),
165 3
                PBES2SaltInputParameter::fromString($this->_saltInput),
166 3
                new PBES2CountParameter($this->_count), ]);
167
    }
168
169
    /**
170
     * Get hash algorithm for hash_pbkdf2.
171
     *
172
     * @return string
173
     */
174
    abstract protected function _hashAlgo(): string;
175
176
    /**
177
     * Get derived key length.
178
     *
179
     * @return int
180
     */
181
    abstract protected function _keyLength(): int;
182
183
    /**
184
     * Get key wrapping algoritym.
185
     *
186
     * @return AESKeyWrapAlgorithm
187
     */
188
    abstract protected function _kwAlgo(): AESKeyWrapAlgorithm;
189
190
    /**
191
     * Get derived key.
192
     *
193
     * @return string
194
     */
195 11
    protected function _derivedKey(): string
196
    {
197 11
        if (!isset($this->_derivedKey)) {
198 8
            $this->_derivedKey = hash_pbkdf2($this->_hashAlgo(),
199 8
                $this->_password, $this->salt(), $this->_count,
200 8
                $this->_keyLength(), true);
201
        }
202 11
        return $this->_derivedKey;
203
    }
204
205
    /**
206
     * {@inheritdoc}
207
     */
208 7
    protected function _encryptKey(string $key, Header &$header): string
209
    {
210 7
        return $this->_kwAlgo()->wrap($key, $this->_derivedKey());
211
    }
212
213
    /**
214
     * {@inheritdoc}
215
     */
216 4
    protected function _decryptKey(string $ciphertext, Header $header): string
217
    {
218 4
        return $this->_kwAlgo()->unwrap($ciphertext, $this->_derivedKey());
219
    }
220
}
221