Completed
Push — master ( e2fc6a...8f4253 )
by Tony Karavasilev (Тони
18:35
created

AbstractDsaSignature::validatePlainData()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 2
c 1
b 0
f 0
dl 0
loc 4
ccs 3
cts 3
cp 1
rs 10
cc 2
nc 2
nop 1
crap 2
1
<?php
2
3
/**
4
 * The asymmetric DSA algorithm abstraction specification.
5
 */
6
7
namespace CryptoManana\Core\Abstractions\MessageEncryption;
8
9
use \CryptoManana\Core\Abstractions\MessageEncryption\AbstractAsymmetricEncryptionAlgorithm as AsymmetricAlgorithm;
10
use \CryptoManana\Core\Interfaces\MessageEncryption\DataSigningInterface as DigitalSignatureVerification;
11
use \CryptoManana\Core\Interfaces\MessageEncryption\SignatureDigestionInterface as SignatureDataDigestion;
12
use \CryptoManana\Core\Interfaces\MessageEncryption\ObjectSigningInterface as ObjectSigning;
13
use \CryptoManana\Core\Interfaces\MessageEncryption\FileSigningInterface as FileSigning;
14
use \CryptoManana\Core\Interfaces\MessageEncryption\SignatureDataFormatsInterface as SignatureDataFormatting;
15
use \CryptoManana\Core\Traits\MessageEncryption\SignatureDataFormatsTrait as SignatureDataFormats;
16
use \CryptoManana\Core\Traits\MessageEncryption\ObjectSigningTrait as SignAndVerifyObjects;
17
use \CryptoManana\Core\Traits\MessageEncryption\FileSigningTrait as SignAndVerifyFiles;
18
use \CryptoManana\Core\Traits\MessageEncryption\SignatureDigestionTrait as SignatureDigestionAlgorithms;
19
20
/**
21
 * Class AbstractDsaSignature - The DSA signature algorithm abstraction representation.
22
 *
23
 * @package CryptoManana\Core\Abstractions\MessageEncryption
24
 *
25
 * @mixin SignatureDigestionAlgorithms
26
 * @mixin SignAndVerifyObjects
27
 * @mixin SignAndVerifyFiles
28
 * @mixin SignatureDataFormats
29
 */
30
abstract class AbstractDsaSignature extends AsymmetricAlgorithm implements
31
    DigitalSignatureVerification,
32
    SignatureDataDigestion,
33
    ObjectSigning,
34
    FileSigning,
35
    SignatureDataFormatting
36
{
37
    /**
38
     * Signature digestion algorithms.
39
     *
40
     * {@internal Reusable implementation of `SignatureDigestionInterface`. }}
41
     */
42
    use SignatureDigestionAlgorithms;
43
44
    /**
45
     * Generating signatures for objects and verifying them.
46
     *
47
     * {@internal Reusable implementation of `ObjectSigningInterface`. }}
48
     */
49
    use SignAndVerifyObjects;
50
51
    /**
52
     * Generating signatures for file content and verifying them.
53
     *
54
     * {@internal Reusable implementation of `FileSigningInterface`. }}
55
     */
56
    use SignAndVerifyFiles;
57
58
    /**
59
     * Signature data outputting formats.
60
     *
61
     * {@internal Reusable implementation of `SignatureDataFormatsInterface`. }}
62
     */
63
    use SignatureDataFormats;
64
65
    /**
66
     * The internal name of the algorithm.
67
     */
68
    const ALGORITHM_NAME = OPENSSL_KEYTYPE_DSA;
69
70
    /**
71
     * The signature's internal digestion algorithm property.
72
     *
73
     * @var int The digestion algorithm integer code value.
74
     */
75
    protected $digestion = self::SHA2_384_SIGNING;
76
77
    /**
78
     * The output signature format property storage.
79
     *
80
     * @var int The output signature format integer code value.
81
     */
82
    protected $signatureFormat = self::SIGNATURE_OUTPUT_HEX_UPPER;
83
84
    /**
85
     * Internal method for the validation of plain data used at encryption/signing operations.
86
     *
87
     * @param string $plainData The plain input string.
88
     *
89
     * @throws \Exception Validation errors.
90
     */
91 152
    protected function validatePlainData($plainData)
92
    {
93 152
        if (!is_string($plainData)) {
94 16
            throw new \InvalidArgumentException('The data for signing must be a string or a binary string.');
95
        }
96 136
    }
97
98
    /**
99
     * Internal method for the validation of cipher/signature data used at decryption/verifying operations.
100
     *
101
     * @param string $cipherOrSignatureData The encrypted input string or a signature string.
102
     *
103
     * @throws \Exception Validation errors.
104
     */
105 88
    protected function validateCipherOrSignatureData($cipherOrSignatureData)
106
    {
107 88
        if (!is_string($cipherOrSignatureData)) {
108 8
            throw new \InvalidArgumentException('The signature data must be a string or a binary string.');
109 80
        } elseif ($cipherOrSignatureData === '') {
110 8
            throw new \InvalidArgumentException(
111 8
                'The signature string is empty and there is nothing to verify from it.'
112
            );
113
        }
114 72
    }
115
116
    /**
117
     * Generates a signature of the given plain data.
118
     *
119
     * @param string $plainData The plain input string.
120
     *
121
     * @return string The signature data.
122
     * @throws \Exception Validation errors.
123
     */
124 128
    public function signData($plainData)
125
    {
126 128
        $this->checkIfThePrivateKeyIsSet();
127 120
        $this->validatePlainData($plainData);
128
129 112
        $privateKeyResource = openssl_pkey_get_private(base64_decode($this->privateKey));
130
131
        // @codeCoverageIgnoreStart
132
        if ($privateKeyResource === false) {
133
            throw new \RuntimeException(
134
                'Failed to use the current private key, probably because of ' .
135
                'a misconfigured OpenSSL library or an invalid key.'
136
            );
137
        }
138
        // @codeCoverageIgnoreEnd
139
140 112
        $signatureData = '';
141 112
        openssl_sign($plainData, $signatureData, $privateKeyResource, $this->digestion);
142
143
        // Free the private key (resource cleanup)
144 112
        openssl_free_key($privateKeyResource);
145 112
        $privateKeyResource = null;
1 ignored issue
show
Unused Code introduced by
The assignment to $privateKeyResource is dead and can be removed.
Loading history...
146
147 112
        return $this->changeOutputFormat($signatureData, true);
148
    }
149
150
    /**
151
     * Verifies that the signature is correct for the given plain data.
152
     *
153
     * @param string $signatureData The signature input string.
154
     * @param string $plainData The plain input string.
155
     *
156
     * @return bool The verification result.
157
     * @throws \Exception Validation errors.
158
     */
159 96
    public function verifyDataSignature($signatureData, $plainData)
160
    {
161 96
        $this->checkIfThePublicKeyIsSet();
162 96
        $this->validatePlainData($plainData);
163 88
        $this->validateCipherOrSignatureData($signatureData);
164
165 72
        $signatureData = $this->changeOutputFormat($signatureData, false);
166 72
        $publicKeyResource = openssl_pkey_get_public(base64_decode($this->publicKey));
167
168
        // @codeCoverageIgnoreStart
169
        if ($publicKeyResource === false) {
170
            throw new \RuntimeException(
171
                'Failed to use the current public key, probably because of ' .
172
                'a misconfigured OpenSSL library or an invalid key.'
173
            );
174
        }
175
        // @codeCoverageIgnoreEnd
176
177 72
        $verified = (openssl_verify($plainData, $signatureData, $publicKeyResource, $this->digestion) === 1);
178
179
        // Free the public key (resource cleanup)
180 72
        openssl_free_key($publicKeyResource);
181 72
        $publicKeyResource = null;
182
183 72
        return $verified;
184
    }
185
186
    /**
187
     * DSA asymmetric algorithm constructor.
188
     */
189 288
    public function __construct()
190
    {
191 288
    }
192
193
    /**
194
     * Get debug information for the class instance.
195
     *
196
     * @return array Debug information.
197
     */
198 8
    public function __debugInfo()
199
    {
200
        return [
201 8
            'standard' => 'DSA/DSS',
202 8
            'type' => 'asymmetrical signing or digital signature algorithm',
203 8
            'key size in bits' => static::KEY_SIZE,
204 8
            'signature digestion algorithm' => $this->digestion,
205 8
            'private key' => $this->privateKey,
206 8
            'public key' => $this->publicKey,
207
        ];
208
    }
209
}
210