Completed
Push — master ( 604a9a...cf79ad )
by Tony Karavasilev (Тони
18:44
created

KeyPairTrait::validatePrivateKeyFormat()   A

Complexity

Conditions 5
Paths 7

Size

Total Lines 12
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 5

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 6
c 1
b 0
f 0
dl 0
loc 12
ccs 6
cts 6
cp 1
rs 9.6111
cc 5
nc 7
nop 1
crap 5
1
<?php
2
3
/**
4
 * Trait implementation of the public and private key pair capabilities for asymmetric encryption/signing algorithms.
5
 */
6
7
namespace CryptoManana\Core\Traits\MessageEncryption;
8
9
use \CryptoManana\Core\Interfaces\MessageEncryption\KeyPairInterface as KeyPairSpecification;
10
use \CryptoManana\Core\Traits\CommonValidations\KeyPairFormatValidationTrait as KeyFormatValidations;
11
use \CryptoManana\DataStructures\KeyPair as KeyPairStructure;
12
13
/**
14
 * Trait KeyPairTrait - Reusable implementation of `KeyPairInterface`.
15
 *
16
 * @see \CryptoManana\Core\Interfaces\MessageDigestion\KeyPairInterface The abstract specification.
17
 *
18
 * @package CryptoManana\Core\Traits\MessageEncryption
19
 *
20
 * @property string $privateKey The private key string property storage.
21
 * @property string $publicKey The public key string property storage.
22
 *
23
 * @mixin KeyPairSpecification
24
 * @mixin KeyFormatValidations
25
 */
26
trait KeyPairTrait
27
{
28
    /**
29
     * Asymmetric key pair format validations.
30
     *
31
     * {@internal Reusable implementation of the common key pair format validation. }}
32
     */
33
    use KeyFormatValidations;
34
35
    /**
36
     * Internal method for the validation of the private key resource.
37
     *
38
     * @param string $privateKey The private key input string.
39
     *
40
     * @return string The extracted public key string from the private key resource.
41
     * @throws \Exception Validation errors.
42
     *
43
     * @internal The parameter is passed via reference from the main logical method for performance reasons.
44
     *
45
     * @codeCoverageIgnore
46
     */
47
    protected function validatePrivateKeyResource(&$privateKey)
48
    {
49
        $privateKeyResource = openssl_pkey_get_private(base64_decode($privateKey));
50
51
        if ($privateKeyResource === false) {
52
            throw new \RuntimeException(
53
                'Failed to import the private key, probably because of ' .
54
                'a misconfigured OpenSSL library or an invalid key.'
55
            );
56
        }
57
58
        $privateKeyInformation = openssl_pkey_get_details($privateKeyResource);
59
60
        if ($privateKeyInformation === false) {
61
            throw new \RuntimeException(
62
                'Failed to export the key\'s information, probably because of a misconfigured ' .
63
                'OpenSSL library or an invalid private key.'
64
            );
65
        } elseif ($privateKeyInformation['bits'] !== static::KEY_SIZE) {
66
            throw new \DomainException('The private key is not of the correct size: `' . static::KEY_SIZE . '`.');
67
        }
68
69
        // Free the private key (resource cleanup)
70
        openssl_free_key($privateKeyResource);
71
        $privateKeyResource = null;
72
73
        return base64_encode((string)$privateKeyInformation['key']); // <- The extracted public key
74
    }
75
76
    /**
77
     * Internal method for the validation of the public key resource.
78
     *
79
     * @param string $publicKey The public key input string.
80
     *
81
     * @throws \Exception Validation errors.
82
     *
83
     * @internal The parameter is passed via reference from the main logical method for performance reasons.
84
     *
85
     * @codeCoverageIgnore
86
     */
87
    protected function validatePublicKeyResource(&$publicKey)
88
    {
89
        $publicKeyResource = openssl_pkey_get_public(base64_decode($publicKey));
90
91
        if ($publicKeyResource === false) {
92
            throw new \RuntimeException(
93
                'Failed to import the public key, probably because of ' .
94
                'a misconfigured OpenSSL library or an invalid key.'
95
            );
96
        }
97
98
        $publicKeyInformation = openssl_pkey_get_details($publicKeyResource);
99
100
        if ($publicKeyInformation === false) {
101
            throw new \RuntimeException(
102
                'Failed to export the key\'s information, probably because of a misconfigured ' .
103
                'OpenSSL library or an invalid public key.'
104
            );
105
        } elseif ($publicKeyInformation['bits'] !== static::KEY_SIZE) {
106
            throw new \DomainException('The public key is not of the correct size: `' . static::KEY_SIZE . '`.');
107
        }
108
109
        // Free the public key (resource cleanup)
110
        openssl_free_key($publicKeyResource);
111
        $publicKeyResource = null;
112
    }
113
114
    /**
115
     * Internal method for the validation of the private and public key pair string representations.
116
     *
117
     * @param string $privateKey The private key input string.
118
     * @param string $publicKey The public key input string.
119
     *
120
     * @throws \Exception Validation errors.
121
     */
122 560
    protected function validateKeyPair($privateKey, $publicKey)
123
    {
124 560
        $this->validatePrivateKeyFormat($privateKey);
125 560
        $this->validatePublicKeyFormat($publicKey);
126
127 560
        $extractedPublicKey = $this->validatePrivateKeyResource($privateKey);
128
129 560
        $this->validatePublicKeyResource($publicKey);
130
131
        // @codeCoverageIgnoreStart
132
        $thePairIsNotMatching = (
133
            strlen($extractedPublicKey) !== strlen($publicKey) ||
134
            substr($extractedPublicKey, -8) !== substr($extractedPublicKey, -8) ||
135
            hash('sha256', $extractedPublicKey) !== hash('sha256', $publicKey)
136
        );
137
138
        if ($thePairIsNotMatching) {
139
            throw new \RuntimeException('The private and public key pair are not matching and can not be used.');
140
        }
141
        // @codeCoverageIgnoreEnd
142 560
    }
143
144
    /**
145
     * Setter for the whole key pair as an array.
146
     *
147
     * @param KeyPairStructure $keyPair The private and public key pair as an object.
148
     *
149
     * @return $this The encryption/signature algorithm object.
150
     * @throws \Exception Validation errors.
151
     */
152 560
    public function setKeyPair(KeyPairStructure $keyPair)
153
    {
154 560
        $this->validateKeyPair($keyPair->private, $keyPair->public);
155
156
        // Set the key pair
157 560
        $this->privateKey = $keyPair->private;
158 560
        $this->publicKey = $keyPair->public;
159
160 560
        return $this;
161
    }
162
163
    /**
164
     * Getter for the whole key pair as an array.
165
     *
166
     * @return KeyPairStructure The private and public key pair as an object.
167
     */
168 16
    public function getKeyPair()
169
    {
170 16
        return new KeyPairStructure($this->privateKey, $this->publicKey);
171
    }
172
173
    /**
174
     * Setter for the private key string property.
175
     *
176
     * @param string $privateKey The private key string.
177
     *
178
     * @return $this The encryption/signature algorithm object.
179
     * @throws \Exception Validation errors.
180
     */
181 32
    public function setPrivateKey($privateKey)
182
    {
183 32
        $this->validatePrivateKeyFormat($privateKey);
184 16
        $this->validatePrivateKeyResource($privateKey);
185
186
        // Set the key pair
187 16
        $this->privateKey = $privateKey;
188
189 16
        return $this;
190
    }
191
192
    /**
193
     * Getter for the private key string property.
194
     *
195
     * @return string The private key string.
196
     */
197 32
    public function getPrivateKey()
198
    {
199 32
        return ($this->privateKey !== '') ? $this->privateKey : null;
200
    }
201
202
    /**
203
     * Setter for the public key string property.
204
     *
205
     * @param string $publicKey The public key string.
206
     *
207
     * @return $this The encryption/signature algorithm object.
208
     * @throws \Exception Validation errors.
209
     */
210 32
    public function setPublicKey($publicKey)
211
    {
212 32
        $this->validatePublicKeyFormat($publicKey);
213 16
        $this->validatePublicKeyResource($publicKey);
214
215
        // Set the key pair
216 16
        $this->publicKey = $publicKey;
217
218 16
        return $this;
219
    }
220
221
    /**
222
     * Getter for the public key string property.
223
     *
224
     * @return string The public key string.
225
     */
226 32
    public function getPublicKey()
227
    {
228 32
        return ($this->publicKey !== '') ? $this->publicKey : null;
229
    }
230
231
    /**
232
     * Checks if the private key is present.
233
     *
234
     * @throws \Exception If there is no private key set.
235
     */
236 264
    public function checkIfThePrivateKeyIsSet()
237
    {
238 264
        if ($this->privateKey === '') {
239 16
            throw new \RuntimeException('There is no private key set, please generate or import your key pair.');
240
        }
241 248
    }
242
243
    /**
244
     * Checks if the public key is present.
245
     *
246
     * @throws \Exception If there is no public key set.
247
     */
248 272
    public function checkIfThePublicKeyIsSet()
249
    {
250 272
        if ($this->publicKey === '') {
251 8
            throw new \RuntimeException('There is no public key set, please generate or import your key pair.');
252
        }
253 264
    }
254
}
255