1
|
|
|
<?php namespace Limoncello\Crypt; |
2
|
|
|
|
3
|
|
|
/** |
4
|
|
|
* Copyright 2015-2017 [email protected] |
5
|
|
|
* |
6
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
7
|
|
|
* you may not use this file except in compliance with the License. |
8
|
|
|
* You may obtain a copy of the License at |
9
|
|
|
* |
10
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0 |
11
|
|
|
* |
12
|
|
|
* Unless required by applicable law or agreed to in writing, software |
13
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS, |
14
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
15
|
|
|
* See the License for the specific language governing permissions and |
16
|
|
|
* limitations under the License. |
17
|
|
|
*/ |
18
|
|
|
|
19
|
|
|
use Limoncello\Crypt\Contracts\DecryptInterface; |
20
|
|
|
use Limoncello\Crypt\Contracts\EncryptInterface; |
21
|
|
|
use Limoncello\Crypt\Exceptions\CryptException; |
22
|
|
|
|
23
|
|
|
/** |
24
|
|
|
* @package Limoncello\Crypt |
25
|
|
|
* |
26
|
|
|
* @SuppressWarnings(PHPMD.ExcessiveClassComplexity) |
27
|
|
|
*/ |
28
|
|
|
class SymmetricCrypt extends BaseCrypt implements EncryptInterface, DecryptInterface |
29
|
|
|
{ |
30
|
|
|
/** |
31
|
|
|
* @var string |
32
|
|
|
*/ |
33
|
|
|
private $method; |
34
|
|
|
|
35
|
|
|
/** |
36
|
|
|
* @var string |
37
|
|
|
*/ |
38
|
|
|
private $password; |
39
|
|
|
|
40
|
|
|
/** |
41
|
|
|
* Such as OPENSSL_RAW_DATA, OPENSSL_ZERO_PADDING. |
42
|
|
|
* |
43
|
|
|
* @var int |
44
|
|
|
*/ |
45
|
|
|
private $options = 0; |
46
|
|
|
|
47
|
|
|
/** |
48
|
|
|
* @var string |
49
|
|
|
*/ |
50
|
|
|
private $initializationVector = ''; |
51
|
|
|
|
52
|
|
|
// Authenticated Encryption with Associated Data options (since PHP 7.1) |
53
|
3 |
|
|
54
|
|
|
/** |
55
|
3 |
|
* Use Authenticated Encryption with Associated Data (since PHP 7.1) |
56
|
3 |
|
* |
57
|
|
|
* @var bool |
58
|
|
|
*/ |
59
|
|
|
private $useAuthentication = false; |
60
|
|
|
|
61
|
1 |
|
/** |
62
|
|
|
* Additional authentication data. |
63
|
1 |
|
* |
64
|
|
|
* @var string |
65
|
1 |
|
*/ |
66
|
|
|
private $aad = ''; |
67
|
1 |
|
|
68
|
|
|
/** |
69
|
1 |
|
* The length of the authentication tag. Its value can be between 4 and 16 for GCM (Galois/Counter Mode) mode. |
70
|
1 |
|
* |
71
|
1 |
|
* @var int |
72
|
1 |
|
*/ |
73
|
|
|
private $tagLength = 16; |
74
|
|
|
|
75
|
1 |
|
/** |
76
|
|
|
* @param string $method |
77
|
1 |
|
* @param string $password |
78
|
|
|
*/ |
79
|
|
|
public function __construct(string $method, string $password) |
80
|
|
|
{ |
81
|
|
|
$this->setMethod($method)->setPassword($password)->asRaw(); |
82
|
|
|
} |
83
|
3 |
|
|
84
|
|
|
/** |
85
|
3 |
|
* @inheritdoc |
86
|
|
|
* |
87
|
3 |
|
* @SuppressWarnings(PHPMD.ElseExpression) |
88
|
|
|
*/ |
89
|
3 |
|
public function decrypt(string $data): string |
90
|
|
|
{ |
91
|
3 |
|
$this->clearErrors(); |
92
|
3 |
|
|
93
|
3 |
|
$vector = $this->getIV(); |
94
|
3 |
|
if (empty($vector) === true) { |
95
|
|
|
$ivLength = $this->openSslIvLength($this->getMethod()); |
96
|
|
|
$vector = $this->readIV($data, $ivLength); |
97
|
3 |
|
$data = $this->extractData($data, $ivLength); |
98
|
|
|
} |
99
|
2 |
|
|
100
|
|
|
if ($this->isUseAuthentication() === true) { |
101
|
|
|
$tagLength = $this->getTagLength(); |
102
|
|
|
$tag = $this->readTag($data, $tagLength); |
103
|
|
|
$data = $this->extractData($data, $tagLength); |
104
|
|
|
|
105
|
3 |
|
$decrypted = $this->openSslDecryptAuthenticated( |
106
|
|
|
$data, |
107
|
3 |
|
$this->getMethod(), |
108
|
|
|
$this->getPassword(), |
109
|
|
|
$this->getOptions(), |
110
|
|
|
$vector, |
111
|
|
|
$this->getAdditionalAuthenticationData(), |
112
|
|
|
$tag |
113
|
3 |
|
); |
114
|
|
|
} else { |
115
|
3 |
|
$decrypted = $this->openSslDecrypt( |
116
|
|
|
$data, |
117
|
|
|
$this->getMethod(), |
118
|
|
|
$this->getPassword(), |
119
|
|
|
$this->getOptions(), |
120
|
|
|
$vector |
121
|
|
|
); |
122
|
|
|
} |
123
|
3 |
|
|
124
|
|
|
return $decrypted; |
125
|
3 |
|
} |
126
|
|
|
|
127
|
3 |
|
/** |
128
|
|
|
* @inheritdoc |
129
|
3 |
|
* |
130
|
|
|
* @SuppressWarnings(PHPMD.ElseExpression) |
131
|
|
|
*/ |
132
|
|
|
public function encrypt(string $data): string |
133
|
|
|
{ |
134
|
|
|
$this->clearErrors(); |
135
|
|
|
|
136
|
|
|
$isAddIvToOutput = false; |
137
|
3 |
|
$vector = $this->getIV(); |
138
|
|
|
if (empty($vector) === true) { |
139
|
3 |
|
$vector = $this->generateIV(); |
140
|
|
|
$isAddIvToOutput = true; |
141
|
3 |
|
} |
142
|
|
|
|
143
|
3 |
|
if ($this->isUseAuthentication() === true) { |
144
|
|
|
$encrypted = $this->openSslEncryptAuthenticated( |
145
|
|
|
$data, |
146
|
|
|
$this->getMethod(), |
147
|
|
|
$this->getPassword(), |
148
|
|
|
$this->getOptions(), |
149
|
|
|
$vector, |
150
|
|
|
$this->getAdditionalAuthenticationData(), |
151
|
1 |
|
$tag, |
152
|
|
|
$this->getTagLength() |
153
|
1 |
|
); |
154
|
|
|
|
155
|
1 |
|
// Tag/Message authentication code should be sent with the encrypted message |
156
|
|
|
// otherwise it won't be possible to validate and encrypt the message. |
157
|
1 |
|
// Though https://tools.ietf.org/html/rfc5084 do not directly says it should |
158
|
|
|
// be passed along with the encrypted message adding it is one of the possible |
159
|
|
|
// solutions. |
160
|
|
|
$encrypted = $tag . $encrypted; |
161
|
|
|
} else { |
162
|
|
|
$encrypted = $this->openSslEncrypt( |
163
|
3 |
|
$data, |
164
|
|
|
$this->getMethod(), |
165
|
3 |
|
$this->getPassword(), |
166
|
2 |
|
$this->getOptions(), |
167
|
|
|
$vector |
168
|
|
|
); |
169
|
3 |
|
} |
170
|
|
|
|
171
|
|
|
// Add initialization vector (IV) if it was generated otherwise it won't be possible to encrypt the message. |
172
|
|
|
// |
173
|
|
|
// Also @see http://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38a.pdf |
174
|
|
|
// |
175
|
3 |
|
// Appendix C: Generation of Initialization Vectors |
176
|
|
|
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
177
|
3 |
|
// ... |
178
|
|
|
// The IV need not be secret, so the IV, or information sufficient to determine the IV, may be |
179
|
|
|
// transmitted with the ciphertext. |
180
|
|
|
// ... |
181
|
|
|
$result = $isAddIvToOutput === false ? $encrypted : $vector . $encrypted; |
182
|
|
|
|
183
|
1 |
|
return $result; |
184
|
|
|
} |
185
|
1 |
|
|
186
|
|
|
/** |
187
|
|
|
* @return string |
188
|
|
|
*/ |
189
|
|
|
public function getPassword(): string |
190
|
|
|
{ |
191
|
1 |
|
return $this->password; |
192
|
|
|
} |
193
|
1 |
|
|
194
|
|
|
/** |
195
|
|
|
* @return string |
196
|
|
|
*/ |
197
|
|
|
public function getMethod(): string |
198
|
|
|
{ |
199
|
3 |
|
return $this->method; |
200
|
|
|
} |
201
|
3 |
|
|
202
|
|
|
/** |
203
|
|
|
* @param string $method |
204
|
|
|
* |
205
|
|
|
* @return self |
206
|
|
|
*/ |
207
|
3 |
|
public function setMethod(string $method): self |
208
|
|
|
{ |
209
|
3 |
|
assert( |
210
|
|
|
($availableMethods = openssl_get_cipher_methods(true)) !== false && |
211
|
|
|
in_array($method, $availableMethods) === true |
212
|
|
|
); |
213
|
|
|
|
214
|
|
|
$this->method = $method; |
215
|
|
|
|
216
|
|
|
return $this; |
217
|
3 |
|
} |
218
|
|
|
|
219
|
3 |
|
/** |
220
|
|
|
* @param string $password |
221
|
3 |
|
* |
222
|
|
|
* @return self |
223
|
3 |
|
*/ |
224
|
|
|
public function setPassword(string $password): self |
225
|
|
|
{ |
226
|
|
|
assert(empty($password) === false); |
227
|
|
|
|
228
|
|
|
$this->password = $password; |
229
|
2 |
|
|
230
|
|
|
return $this; |
231
|
2 |
|
} |
232
|
|
|
|
233
|
2 |
|
/** |
234
|
|
|
* @param string $value |
235
|
|
|
* |
236
|
|
|
* @return self |
237
|
|
|
*/ |
238
|
|
|
public function setIV(string $value): self |
239
|
|
|
{ |
240
|
|
|
$this->initializationVector = $value; |
241
|
3 |
|
|
242
|
|
|
return $this; |
243
|
3 |
|
} |
244
|
|
|
|
245
|
3 |
|
/** |
246
|
|
|
* @return string |
247
|
3 |
|
*/ |
248
|
|
|
public function getIV(): string |
249
|
|
|
{ |
250
|
|
|
return $this->initializationVector; |
251
|
|
|
} |
252
|
|
|
|
253
|
|
|
/** |
254
|
|
|
* @return self |
255
|
3 |
|
*/ |
256
|
|
|
public function withZeroPadding(): self |
257
|
3 |
|
{ |
258
|
|
|
return $this->setOption(OPENSSL_ZERO_PADDING); |
259
|
3 |
|
} |
260
|
|
|
|
261
|
3 |
|
/** |
262
|
|
|
* @return self |
263
|
|
|
*/ |
264
|
|
|
public function withoutZeroPadding(): self |
265
|
|
|
{ |
266
|
|
|
return $this->clearOption(OPENSSL_ZERO_PADDING); |
267
|
|
|
} |
268
|
|
|
|
269
|
|
|
/** |
270
|
|
|
* @return bool |
271
|
|
|
*/ |
272
|
|
|
public function isUseAuthentication(): bool |
273
|
|
|
{ |
274
|
|
|
return $this->useAuthentication; |
275
|
1 |
|
} |
276
|
|
|
|
277
|
1 |
|
/** |
278
|
|
|
* Authenticated Encryption with Associated Data available for certain methods since PHP 7.1. |
279
|
|
|
* |
280
|
|
|
* @return self |
281
|
|
|
*/ |
282
|
|
|
public function enableAuthentication(): self |
283
|
|
|
{ |
284
|
|
|
$this->useAuthentication = true; |
285
|
|
|
|
286
|
|
|
return $this; |
287
|
|
|
} |
288
|
|
|
|
289
|
|
|
/** |
290
|
|
|
* Authenticated Encryption with Associated Data available for certain methods since PHP 7.1. |
291
|
2 |
|
* |
292
|
|
|
* @return self |
293
|
2 |
|
*/ |
294
|
|
|
public function disableAuthentication(): self |
295
|
|
|
{ |
296
|
|
|
$this->useAuthentication = false; |
297
|
|
|
|
298
|
|
|
return $this; |
299
|
|
|
} |
300
|
|
|
|
301
|
|
|
/** |
302
|
|
|
* @return string |
303
|
|
|
*/ |
304
|
|
|
public function getAdditionalAuthenticationData(): string |
305
|
|
|
{ |
306
|
|
|
return $this->aad; |
307
|
|
|
} |
308
|
|
|
|
309
|
|
|
/** |
310
|
|
|
* @param string $data |
311
|
|
|
* |
312
|
|
|
* @return self |
313
|
|
|
*/ |
314
|
|
|
public function setAdditionalAuthenticationData(string $data): self |
315
|
|
|
{ |
316
|
|
|
$this->aad = $data; |
317
|
|
|
|
318
|
|
|
return $this; |
319
|
|
|
} |
320
|
|
|
|
321
|
|
|
/** |
322
|
|
|
* @return int |
323
|
|
|
*/ |
324
|
|
|
public function getTagLength(): int |
325
|
|
|
{ |
326
|
|
|
return $this->tagLength; |
327
|
|
|
} |
328
|
|
|
|
329
|
|
|
/** |
330
|
|
|
* @param int $length |
331
|
|
|
* |
332
|
|
|
* @return self |
333
|
|
|
*/ |
334
|
|
|
public function setTagLength(int $length): self |
335
|
|
|
{ |
336
|
|
|
assert($this->isTagLengthMightBeValid($length)); |
337
|
|
|
|
338
|
|
|
$this->tagLength = $length; |
339
|
|
|
|
340
|
|
|
return $this; |
341
|
|
|
} |
342
|
|
|
|
343
|
|
|
/** |
344
|
|
|
* @return self |
345
|
|
|
*/ |
346
|
|
|
protected function asRaw(): self |
347
|
|
|
{ |
348
|
|
|
return $this->setOption(OPENSSL_RAW_DATA); |
349
|
|
|
} |
350
|
|
|
|
351
|
|
|
/** |
352
|
|
|
* @return int |
353
|
|
|
*/ |
354
|
|
|
protected function getOptions(): int |
355
|
|
|
{ |
356
|
|
|
return $this->options; |
357
|
|
|
} |
358
|
|
|
|
359
|
|
|
/** |
360
|
|
|
* @param int $options |
361
|
|
|
* |
362
|
|
|
* @return self |
363
|
|
|
*/ |
364
|
|
|
protected function setOptions(int $options): self |
365
|
|
|
{ |
366
|
|
|
$this->options = $options; |
367
|
|
|
|
368
|
|
|
return $this; |
369
|
|
|
} |
370
|
|
|
|
371
|
|
|
/** |
372
|
|
|
* @return string |
373
|
|
|
*/ |
374
|
|
|
protected function generateIV(): string |
375
|
|
|
{ |
376
|
|
|
$ivLength = $this->openSslIvLength($this->getMethod()); |
377
|
|
|
$ivLength !== false ?: $this->throwException(new CryptException($this->getErrorMessage())); |
378
|
|
|
|
379
|
|
|
$vector = openssl_random_pseudo_bytes($ivLength); |
380
|
|
|
|
381
|
|
|
return $vector; |
382
|
|
|
} |
383
|
|
|
|
384
|
|
|
/** |
385
|
|
|
* @param int $option |
386
|
|
|
* |
387
|
|
|
* @return self |
388
|
|
|
*/ |
389
|
|
|
protected function setOption(int $option): self |
390
|
|
|
{ |
391
|
|
|
$this->setOptions($this->getOptions() | $option); |
392
|
|
|
|
393
|
|
|
return $this; |
394
|
|
|
} |
395
|
|
|
|
396
|
|
|
/** |
397
|
|
|
* @param int $option |
398
|
|
|
* |
399
|
|
|
* @return self |
400
|
|
|
*/ |
401
|
|
|
protected function clearOption(int $option): self |
402
|
|
|
{ |
403
|
|
|
$this->setOptions($this->getOptions() & ~$option); |
404
|
|
|
|
405
|
|
|
return $this; |
406
|
|
|
} |
407
|
|
|
|
408
|
|
|
/** |
409
|
|
|
* @param string $data |
410
|
|
|
* @param int $ivLength |
411
|
|
|
* |
412
|
|
|
* @return string |
413
|
|
|
*/ |
414
|
|
View Code Duplication |
protected function readIV(string $data, int $ivLength): string |
|
|
|
|
415
|
|
|
{ |
416
|
|
|
$vector = substr($data, 0, $ivLength); |
417
|
|
|
$isOk = $vector !== false && strlen($vector) === $ivLength; |
418
|
|
|
|
419
|
|
|
$isOk === true ?: $this->throwException(new CryptException($this->getReadVectorErrorMessage())); |
420
|
|
|
|
421
|
|
|
return $vector; |
422
|
|
|
} |
423
|
|
|
|
424
|
|
|
/** |
425
|
|
|
* @param string $data |
426
|
|
|
* @param int $tagLength |
427
|
|
|
* |
428
|
|
|
* @return string |
429
|
|
|
*/ |
430
|
|
|
protected function readTag(string $data, int $tagLength): string |
431
|
|
|
{ |
432
|
|
|
$tag = substr($data, 0, $tagLength); |
433
|
|
|
$isOk = $tag !== false && strlen($tag) === $tagLength; |
434
|
|
|
|
435
|
|
|
$isOk === true ?: $this->throwException(new CryptException($this->getReadTagErrorMessage())); |
436
|
|
|
|
437
|
|
|
return $tag; |
438
|
|
|
} |
439
|
|
|
|
440
|
|
|
/** |
441
|
|
|
* @param string $data |
442
|
|
|
* @param int $ivLength |
443
|
|
|
* |
444
|
|
|
* @return string |
445
|
|
|
*/ |
446
|
|
View Code Duplication |
protected function extractData(string $data, int $ivLength): string |
|
|
|
|
447
|
|
|
{ |
448
|
|
|
$result = substr($data, $ivLength); |
449
|
|
|
|
450
|
|
|
$isOk = $result !== false && empty($result) === false; |
451
|
|
|
$isOk === true ?: $this->throwException(new CryptException($this->getExtractDataErrorMessage())); |
452
|
|
|
|
453
|
|
|
return $result; |
454
|
|
|
} |
455
|
|
|
|
456
|
|
|
/** |
457
|
|
|
* @param string $data |
458
|
|
|
* @param string $method |
459
|
|
|
* @param string $password |
460
|
|
|
* @param int $options |
461
|
|
|
* @param string $initializationVector |
462
|
|
|
* |
463
|
|
|
* @return string |
464
|
|
|
*/ |
465
|
|
View Code Duplication |
protected function openSslEncrypt( |
|
|
|
|
466
|
|
|
string $data, |
467
|
|
|
string $method, |
468
|
|
|
string $password, |
469
|
|
|
int $options, |
470
|
|
|
string $initializationVector |
471
|
|
|
): string { |
472
|
|
|
$encrypted = $this->openSslEncryptImpl($data, $method, $password, $options, $initializationVector); |
473
|
|
|
|
474
|
|
|
$message = $this->getErrorMessage(); |
475
|
|
|
$encrypted !== false ?: $this->throwException(new CryptException($message)); |
476
|
|
|
|
477
|
|
|
return $encrypted; |
478
|
|
|
} |
479
|
|
|
|
480
|
|
|
/** |
481
|
|
|
* @param string $data |
482
|
|
|
* @param string $method |
483
|
|
|
* @param string $password |
484
|
|
|
* @param int $options |
485
|
|
|
* @param string $initializationVector |
486
|
|
|
* |
487
|
|
|
* @return string |
488
|
|
|
*/ |
489
|
|
View Code Duplication |
protected function openSslDecrypt( |
|
|
|
|
490
|
|
|
string $data, |
491
|
|
|
string $method, |
492
|
|
|
string $password, |
493
|
|
|
int $options, |
494
|
|
|
string $initializationVector |
495
|
|
|
): string { |
496
|
|
|
$decrypted = $this->openSslDecryptImpl($data, $method, $password, $options, $initializationVector); |
497
|
|
|
|
498
|
|
|
$decrypted !== false ?: $this->throwException(new CryptException($this->getErrorMessage())); |
499
|
|
|
|
500
|
|
|
return $decrypted; |
501
|
|
|
} |
502
|
|
|
|
503
|
|
|
/** @noinspection PhpTooManyParametersInspection |
504
|
|
|
* @param string $data |
505
|
|
|
* @param string $method |
506
|
|
|
* @param string $password |
507
|
|
|
* @param int $options |
508
|
|
|
* @param string $initializationVector |
509
|
|
|
* @param string $aad |
510
|
|
|
* @param string|null &$tag |
511
|
|
|
* @param int $tagLength |
512
|
|
|
* |
513
|
|
|
* @return string |
514
|
|
|
*/ |
515
|
|
|
protected function openSslEncryptAuthenticated( |
516
|
|
|
string $data, |
517
|
|
|
string $method, |
518
|
|
|
string $password, |
519
|
|
|
int $options, |
520
|
|
|
string $initializationVector, |
521
|
|
|
string $aad, |
522
|
|
|
string &$tag = null, |
523
|
|
|
int $tagLength = 16 |
524
|
|
|
): string { |
525
|
|
|
$encrypted = $this->openSslEncryptAuthenticatedImpl( |
526
|
|
|
$data, |
527
|
|
|
$method, |
528
|
|
|
$password, |
529
|
|
|
$options, |
530
|
|
|
$initializationVector, |
531
|
|
|
$aad, |
532
|
|
|
$tag, |
533
|
|
|
$tagLength |
534
|
|
|
); |
535
|
|
|
|
536
|
|
|
$message = $this->getErrorMessage(); |
537
|
|
|
$encrypted !== false ?: $this->throwException(new CryptException($message)); |
538
|
|
|
|
539
|
|
|
return $encrypted; |
540
|
|
|
} |
541
|
|
|
|
542
|
|
|
/** |
543
|
|
|
* @param string $data |
544
|
|
|
* @param string $method |
545
|
|
|
* @param string $password |
546
|
|
|
* @param int $options |
547
|
|
|
* @param string $initializationVector |
548
|
|
|
* @param string $aad |
549
|
|
|
* @param string $tag |
550
|
|
|
* |
551
|
|
|
* @return string |
552
|
|
|
*/ |
553
|
|
View Code Duplication |
protected function openSslDecryptAuthenticated( |
|
|
|
|
554
|
|
|
string $data, |
555
|
|
|
string $method, |
556
|
|
|
string $password, |
557
|
|
|
int $options, |
558
|
|
|
string $initializationVector, |
559
|
|
|
string $aad, |
560
|
|
|
string $tag |
561
|
|
|
): string { |
562
|
|
|
$decrypted = $this |
563
|
|
|
->openSslDecryptAuthenticatedImpl($data, $method, $password, $options, $initializationVector, $aad, $tag); |
564
|
|
|
|
565
|
|
|
$decrypted !== false ?: $this->throwException(new CryptException($this->getErrorMessage())); |
566
|
|
|
|
567
|
|
|
return $decrypted; |
568
|
|
|
} |
569
|
|
|
|
570
|
|
|
/** |
571
|
|
|
* @param string $method |
572
|
|
|
* |
573
|
|
|
* @return int |
574
|
|
|
*/ |
575
|
|
|
protected function openSslIvLength(string $method): int |
576
|
|
|
{ |
577
|
|
|
$ivLength = $this->openSslIvLengthImpl($method); |
578
|
|
|
|
579
|
|
|
$ivLength !== false ?: $this->throwException(new CryptException($this->getErrorMessage())); |
580
|
|
|
|
581
|
|
|
return $ivLength; |
582
|
|
|
} |
583
|
|
|
|
584
|
|
|
/** |
585
|
|
|
* @return string |
586
|
|
|
*/ |
587
|
|
|
protected function getReadVectorErrorMessage(): string |
588
|
|
|
{ |
589
|
|
|
return 'Reading Initialization Vector (IV) failed'; |
590
|
|
|
} |
591
|
|
|
|
592
|
|
|
/** |
593
|
|
|
* @return string |
594
|
|
|
*/ |
595
|
|
|
protected function getReadTagErrorMessage(): string |
596
|
|
|
{ |
597
|
|
|
return 'Reading Authenticated Encryption Tag failed'; |
598
|
|
|
} |
599
|
|
|
|
600
|
|
|
/** |
601
|
|
|
* @return string |
602
|
|
|
*/ |
603
|
|
|
protected function getExtractDataErrorMessage(): string |
604
|
|
|
{ |
605
|
|
|
return 'Extracting ciphertext from input data failed'; |
606
|
|
|
} |
607
|
|
|
|
608
|
|
|
/** |
609
|
|
|
* We need this wrapper for testing purposes so we can mock system call to Open SSL. |
610
|
|
|
* |
611
|
|
|
* @param string $data |
612
|
|
|
* @param string $method |
613
|
|
|
* @param string $password |
614
|
|
|
* @param int $options |
615
|
|
|
* @param string $initializationVector |
616
|
|
|
* |
617
|
|
|
* @return string|false |
618
|
|
|
*/ |
619
|
|
|
protected function openSslEncryptImpl( |
620
|
|
|
string $data, |
621
|
|
|
string $method, |
622
|
|
|
string $password, |
623
|
|
|
int $options, |
624
|
|
|
string $initializationVector |
625
|
|
|
) { |
626
|
|
|
return openssl_encrypt($data, $method, $password, $options, $initializationVector); |
627
|
|
|
} |
628
|
|
|
|
629
|
|
|
/** |
630
|
|
|
* We need this wrapper for testing purposes so we can mock system call to Open SSL. |
631
|
|
|
* |
632
|
|
|
* @param string $data |
633
|
|
|
* @param string $method |
634
|
|
|
* @param string $password |
635
|
|
|
* @param int $options |
636
|
|
|
* @param string $initializationVector |
637
|
|
|
* |
638
|
|
|
* @return string|false |
639
|
|
|
*/ |
640
|
|
|
protected function openSslDecryptImpl( |
641
|
|
|
string $data, |
642
|
|
|
string $method, |
643
|
|
|
string $password, |
644
|
|
|
int $options, |
645
|
|
|
string $initializationVector |
646
|
|
|
) { |
647
|
|
|
return openssl_decrypt($data, $method, $password, $options, $initializationVector); |
648
|
|
|
} |
649
|
|
|
|
650
|
|
|
/** @noinspection PhpTooManyParametersInspection |
651
|
|
|
* We need this wrapper for testing purposes so we can mock system call to Open SSL. |
652
|
|
|
* |
653
|
|
|
* @param string $data |
654
|
|
|
* @param string $method |
655
|
|
|
* @param string $password |
656
|
|
|
* @param int $options |
657
|
|
|
* @param string $initializationVector |
658
|
|
|
* @param string $aad |
659
|
|
|
* @param string|null &$tag |
660
|
|
|
* @param int $tagLength |
661
|
|
|
* |
662
|
|
|
* @return false|string |
663
|
|
|
*/ |
664
|
|
|
protected function openSslEncryptAuthenticatedImpl( |
665
|
|
|
string $data, |
666
|
|
|
string $method, |
667
|
|
|
string $password, |
668
|
|
|
int $options, |
669
|
|
|
string $initializationVector, |
670
|
|
|
string $aad, |
671
|
|
|
string &$tag = null, |
672
|
|
|
int $tagLength = 16 |
673
|
|
|
) { |
674
|
|
|
assert(PHP_VERSION_ID >= 70100); |
675
|
|
|
assert($this->isTagLengthMightBeValid($tagLength)); |
676
|
|
|
|
677
|
|
|
$result = openssl_encrypt($data, $method, $password, $options, $initializationVector, $tag, $aad, $tagLength); |
678
|
|
|
|
679
|
|
|
return $result; |
680
|
|
|
} |
681
|
|
|
|
682
|
|
|
/** |
683
|
|
|
* We need this wrapper for testing purposes so we can mock system call to Open SSL. |
684
|
|
|
* |
685
|
|
|
* @param string $data |
686
|
|
|
* @param string $method |
687
|
|
|
* @param string $password |
688
|
|
|
* @param int $options |
689
|
|
|
* @param string $initializationVector |
690
|
|
|
* @param string $aad |
691
|
|
|
* @param string $tag |
692
|
|
|
* |
693
|
|
|
* @return false|string |
694
|
|
|
*/ |
695
|
|
|
protected function openSslDecryptAuthenticatedImpl( |
696
|
|
|
string $data, |
697
|
|
|
string $method, |
698
|
|
|
string $password, |
699
|
|
|
int $options, |
700
|
|
|
string $initializationVector, |
701
|
|
|
string $aad, |
702
|
|
|
string $tag |
703
|
|
|
) { |
704
|
|
|
assert(PHP_VERSION_ID >= 70100); |
705
|
|
|
|
706
|
|
|
return openssl_decrypt($data, $method, $password, $options, $initializationVector, $tag, $aad); |
707
|
|
|
} |
708
|
|
|
|
709
|
|
|
/** |
710
|
|
|
* We need this wrapper for testing purposes so we can mock system call to Open SSL. |
711
|
|
|
* |
712
|
|
|
* @param string $method |
713
|
|
|
* |
714
|
|
|
* @return int|false |
715
|
|
|
*/ |
716
|
|
|
protected function openSslIvLengthImpl(string $method) |
717
|
|
|
{ |
718
|
|
|
return openssl_cipher_iv_length($method); |
719
|
|
|
} |
720
|
|
|
|
721
|
|
|
/** |
722
|
|
|
* @param int $length |
723
|
|
|
* |
724
|
|
|
* @return bool |
725
|
|
|
*/ |
726
|
|
|
private function isTagLengthMightBeValid(int $length): bool |
727
|
|
|
{ |
728
|
|
|
// @link http://php.net/manual/en/function.openssl-encrypt.php |
729
|
|
|
|
730
|
|
|
return 4 <= $length && $length <= 16; |
731
|
|
|
} |
732
|
|
|
} |
733
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.