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.

OpenSSLCrypto::_checkCipherKeySize()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 7
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 3

Importance

Changes 0
Metric Value
eloc 5
dl 0
loc 7
ccs 6
cts 6
cp 1
rs 10
c 0
b 0
f 0
cc 3
nc 3
nop 2
crap 3
1
<?php
2
3
declare(strict_types = 1);
4
5
namespace Sop\CryptoBridge\Crypto;
6
7
use Sop\CryptoBridge\Crypto;
8
use Sop\CryptoTypes\AlgorithmIdentifier\AlgorithmIdentifier;
9
use Sop\CryptoTypes\AlgorithmIdentifier\Cipher\BlockCipherAlgorithmIdentifier;
10
use Sop\CryptoTypes\AlgorithmIdentifier\Cipher\CipherAlgorithmIdentifier;
11
use Sop\CryptoTypes\AlgorithmIdentifier\Cipher\RC2CBCAlgorithmIdentifier;
12
use Sop\CryptoTypes\AlgorithmIdentifier\Feature\SignatureAlgorithmIdentifier;
13
use Sop\CryptoTypes\Asymmetric\PrivateKeyInfo;
14
use Sop\CryptoTypes\Asymmetric\PublicKeyInfo;
15
use Sop\CryptoTypes\Signature\Signature;
16
17
/**
18
 * Crypto engine using OpenSSL extension.
19
 */
20
class OpenSSLCrypto extends Crypto
21
{
22
    /**
23
     * Mapping from algorithm OID to OpenSSL signature method identifier.
24
     *
25
     * @internal
26
     *
27
     * @var array
28
     */
29
    const MAP_DIGEST_OID = [
30
        AlgorithmIdentifier::OID_MD4_WITH_RSA_ENCRYPTION => OPENSSL_ALGO_MD4,
31
        AlgorithmIdentifier::OID_MD5_WITH_RSA_ENCRYPTION => OPENSSL_ALGO_MD5,
32
        AlgorithmIdentifier::OID_SHA1_WITH_RSA_ENCRYPTION => OPENSSL_ALGO_SHA1,
33
        AlgorithmIdentifier::OID_SHA224_WITH_RSA_ENCRYPTION => OPENSSL_ALGO_SHA224,
34
        AlgorithmIdentifier::OID_SHA256_WITH_RSA_ENCRYPTION => OPENSSL_ALGO_SHA256,
35
        AlgorithmIdentifier::OID_SHA384_WITH_RSA_ENCRYPTION => OPENSSL_ALGO_SHA384,
36
        AlgorithmIdentifier::OID_SHA512_WITH_RSA_ENCRYPTION => OPENSSL_ALGO_SHA512,
37
        AlgorithmIdentifier::OID_ECDSA_WITH_SHA1 => OPENSSL_ALGO_SHA1,
38
        AlgorithmIdentifier::OID_ECDSA_WITH_SHA224 => OPENSSL_ALGO_SHA224,
39
        AlgorithmIdentifier::OID_ECDSA_WITH_SHA256 => OPENSSL_ALGO_SHA256,
40
        AlgorithmIdentifier::OID_ECDSA_WITH_SHA384 => OPENSSL_ALGO_SHA384,
41
        AlgorithmIdentifier::OID_ECDSA_WITH_SHA512 => OPENSSL_ALGO_SHA512,
42
    ];
43
44
    /**
45
     * Mapping from algorithm OID to OpenSSL cipher method name.
46
     *
47
     * @internal
48
     *
49
     * @var array
50
     */
51
    const MAP_CIPHER_OID = [
52
        AlgorithmIdentifier::OID_DES_CBC => 'des-cbc',
53
        AlgorithmIdentifier::OID_DES_EDE3_CBC => 'des-ede3-cbc',
54
        AlgorithmIdentifier::OID_AES_128_CBC => 'aes-128-cbc',
55
        AlgorithmIdentifier::OID_AES_192_CBC => 'aes-192-cbc',
56
        AlgorithmIdentifier::OID_AES_256_CBC => 'aes-256-cbc',
57
    ];
58
59
    /**
60
     * {@inheritdoc}
61
     */
62 22
    public function sign(string $data, PrivateKeyInfo $privkey_info,
63
        SignatureAlgorithmIdentifier $algo): Signature
64
    {
65 22
        $this->_checkSignatureAlgoAndKey($algo, $privkey_info->algorithmIdentifier());
66 22
        $result = openssl_sign($data, $signature, $privkey_info->toPEM(),
67 22
            $this->_algoToDigest($algo));
68 21
        if (false === $result) {
69 1
            throw new \RuntimeException('openssl_sign() failed: ' .
70 1
                $this->_getLastError());
71
        }
72 20
        return Signature::fromSignatureData($signature, $algo);
73
    }
74
75
    /**
76
     * {@inheritdoc}
77
     */
78 22
    public function verify(string $data, Signature $signature,
79
        PublicKeyInfo $pubkey_info, SignatureAlgorithmIdentifier $algo): bool
80
    {
81 22
        $this->_checkSignatureAlgoAndKey($algo, $pubkey_info->algorithmIdentifier());
82 21
        $result = openssl_verify($data, $signature->bitString()->string(),
83 21
            $pubkey_info->toPEM(), $this->_algoToDigest($algo));
84 21
        if (-1 == $result) {
85 1
            throw new \RuntimeException('openssl_verify() failed: ' .
86 1
                $this->_getLastError());
87
        }
88 20
        return 1 == $result ? true : false;
89
    }
90
91
    /**
92
     * {@inheritdoc}
93
     */
94 13
    public function encrypt(string $data, string $key,
95
        CipherAlgorithmIdentifier $algo): string
96
    {
97 13
        $this->_checkCipherKeySize($algo, $key);
98 12
        $iv = $algo->initializationVector();
99 12
        $result = openssl_encrypt($data, $this->_algoToCipher($algo), $key,
100 9
            OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $iv);
101 9
        if (false === $result) {
102 1
            throw new \RuntimeException('openssl_encrypt() failed: ' .
103 1
                $this->_getLastError());
104
        }
105 8
        return $result;
106
    }
107
108
    /**
109
     * {@inheritdoc}
110
     */
111 9
    public function decrypt(string $data, string $key,
112
        CipherAlgorithmIdentifier $algo): string
113
    {
114 9
        $this->_checkCipherKeySize($algo, $key);
115 9
        $iv = $algo->initializationVector();
116 9
        $result = openssl_decrypt($data, $this->_algoToCipher($algo), $key,
117 9
            OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $iv);
118 9
        if (false === $result) {
119 1
            throw new \RuntimeException('openssl_decrypt() failed: ' .
120 1
                $this->_getLastError());
121
        }
122 8
        return $result;
123
    }
124
125
    /**
126
     * Validate cipher algorithm key size.
127
     *
128
     * @param CipherAlgorithmIdentifier $algo
129
     * @param string                    $key
130
     *
131
     * @throws \UnexpectedValueException
132
     */
133 14
    protected function _checkCipherKeySize(CipherAlgorithmIdentifier $algo, string $key): void
134
    {
135 14
        if ($algo instanceof BlockCipherAlgorithmIdentifier) {
136 12
            if (strlen($key) !== $algo->keySize()) {
137 1
                throw new \UnexpectedValueException(
138 1
                    sprintf('Key length for %s must be %d, %d given.',
139 1
                        $algo->name(), $algo->keySize(), strlen($key)));
140
            }
141
        }
142 13
    }
143
144
    /**
145
     * Get last OpenSSL error message.
146
     *
147
     * @return null|string
148
     */
149 4
    protected function _getLastError(): ?string
150
    {
151
        // pump error message queue
152 4
        $msg = null;
153 4
        while (false !== ($err = openssl_error_string())) {
154 4
            $msg = $err;
155
        }
156 4
        return $msg;
157
    }
158
159
    /**
160
     * Check that given signature algorithm supports key of given type.
161
     *
162
     * @param SignatureAlgorithmIdentifier $sig_algo Signature algorithm
163
     * @param AlgorithmIdentifier          $key_algo Key algorithm
164
     *
165
     * @throws \UnexpectedValueException If key is not supported
166
     */
167 24
    protected function _checkSignatureAlgoAndKey(
168
        SignatureAlgorithmIdentifier $sig_algo,
169
        AlgorithmIdentifier $key_algo): void
170
    {
171 24
        if (!$sig_algo->supportsKeyAlgorithm($key_algo)) {
172 1
            throw new \UnexpectedValueException(
173 1
                sprintf('Signature algorithm %s does not support key algorithm %s.',
174 1
                    $sig_algo->name(), $key_algo->name()));
175
        }
176 23
    }
177
178
    /**
179
     * Get OpenSSL digest method for given signature algorithm identifier.
180
     *
181
     * @param SignatureAlgorithmIdentifier $algo
182
     *
183
     * @throws \UnexpectedValueException If digest method is not supported
184
     *
185
     * @return int
186
     */
187 23
    protected function _algoToDigest(SignatureAlgorithmIdentifier $algo): int
188
    {
189 23
        $oid = $algo->oid();
190 23
        if (!array_key_exists($oid, self::MAP_DIGEST_OID)) {
191 1
            throw new \UnexpectedValueException(
192 1
                sprintf('Digest method %s not supported.', $algo->name()));
193
        }
194 22
        return self::MAP_DIGEST_OID[$oid];
195
    }
196
197
    /**
198
     * Get OpenSSL cipher method for given cipher algorithm identifier.
199
     *
200
     * @param CipherAlgorithmIdentifier $algo
201
     *
202
     * @throws \UnexpectedValueException If cipher method is not supported
203
     *
204
     * @return string
205
     */
206 13
    protected function _algoToCipher(CipherAlgorithmIdentifier $algo): string
207
    {
208 13
        $oid = $algo->oid();
209 13
        if (array_key_exists($oid, self::MAP_CIPHER_OID)) {
210 7
            return self::MAP_CIPHER_OID[$oid];
211
        }
212 6
        if (AlgorithmIdentifier::OID_RC2_CBC === $oid) {
213 5
            if (!$algo instanceof RC2CBCAlgorithmIdentifier) {
214 1
                throw new \UnexpectedValueException('Not an RC2-CBC algorithm.');
215
            }
216 4
            return $this->_rc2AlgoToCipher($algo);
217
        }
218 1
        throw new \UnexpectedValueException(
219 1
            sprintf('Cipher method %s not supported.', $algo->name()));
220
    }
221
222
    /**
223
     * Get OpenSSL cipher method for given RC2 algorithm identifier.
224
     *
225
     * @param RC2CBCAlgorithmIdentifier $algo
226
     *
227
     * @throws \UnexpectedValueException If cipher's key size is not supported
228
     *
229
     * @return string
230
     */
231 4
    protected function _rc2AlgoToCipher(RC2CBCAlgorithmIdentifier $algo): string
232
    {
233 4
        switch ($algo->effectiveKeyBits()) {
234 4
            case 128:
235 1
                return 'rc2-cbc';
236 3
            case 64:
237 1
                return 'rc2-64-cbc';
238 2
            case 40:
239 1
                return 'rc2-40-cbc';
240
        }
241 1
        throw new \UnexpectedValueException(
242 1
            $algo->effectiveKeyBits() . ' bit RC2 not supported.');
243
    }
244
}
245