Completed
Pull Request — master (#237)
by
unknown
03:40
created

OpenSSL::isUsingWeakAlgorithm()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 3
c 0
b 0
f 0
nc 2
nop 0
dl 0
loc 7
rs 10
ccs 5
cts 5
cp 1
crap 2
1
<?php
2
namespace phpbu\App\Cli\Executable;
3
4
use phpbu\App\Cli\Executable;
5
use phpbu\App\Exception;
6
use SebastianFeldmann\Cli\CommandLine;
7
use SebastianFeldmann\Cli\Command\Executable as Cmd;
8
9
/**
10
 * OpenSSL executable class.
11
 *
12
 * @package    phpbu
13
 * @subpackage Backup
14
 * @author     Sebastian Feldmann <[email protected]>
15
 * @copyright  Sebastian Feldmann <[email protected]>
16
 * @license    https://opensource.org/licenses/MIT The MIT License (MIT)
17
 * @link       http://phpbu.de/
18
 * @since      Class available since Release 2.1.6
19
 */
20
class OpenSSL extends Abstraction implements Executable
21
{
22
    use OptionMasker;
23
24
    /**
25
     * Encryption modes
26
     */
27
    const MODE_CERT = 'smime';
28
    const MODE_PASS = 'enc';
29
30
    /**
31
     * Actions
32
     */
33
    const ACTION_ENCRYPT = 'e';
34
    const ACTION_DECRYPT = 'd';
35
36
    /**
37
     * Use password or key
38
     *
39
     * @var string
40
     */
41
    private $mode;
42
43
    /**
44
     * Encryption or decryption
45
     *
46
     * @var string
47
     */
48
    private $action;
49
50
    /**
51
     * File to encrypt
52
     *
53
     * @var string
54
     */
55
    private $sourceFile;
56
57
    /**
58
     * SSL Cert file
59
     *
60
     * @var string
61
     */
62
    private $certFile;
63
64
    /**
65
     * Password
66
     *
67
     * @var string
68
     */
69
    private $password;
70
71
    /**
72
     * Algorithm to use
73
     *
74
     * @var string
75
     */
76
    private $algorithm;
77
78
    /**
79
     * Use base64 encoding
80
     *
81
     * @var boolean
82
     */
83
    private $base64;
84
85
    /**
86
     * Path to the encrypted file
87
     *
88
     * @var string
89
     */
90
    private $targetFile;
91
92
    /**
93
     * List of available algorithms
94
     *
95
     * @var array
96
     */
97
    private $availableAlgorithms = [
98
        'enc'   => [
99
            'aes-128-cbc'  => true,
100
            'aes-128-ecb'  => true,
101
            'aes-192-cbc'  => true,
102
            'aes-192-ecb'  => true,
103
            'aes-256-cbc'  => true,
104
            'aes-256-ecb'  => true,
105
            'base64'       => true,
106
            'bf'           => true,
107
            'bf-cbc'       => true,
108
            'bf-cfb'       => true,
109
            'bf-ecb'       => true,
110
            'bf-ofb'       => true,
111
            'cast'         => true,
112
            'cast-cbc'     => true,
113
            'cast5-cbc'    => true,
114
            'cast5-cfb'    => true,
115
            'cast5-ecb'    => true,
116
            'cast5-ofb'    => true,
117
            'des'          => true,
118
            'des-cbc'      => true,
119
            'des-cfb'      => true,
120
            'des-ecb'      => true,
121
            'des-ede'      => true,
122
            'des-ede-cbc'  => true,
123
            'des-ede-cfb'  => true,
124
            'des-ede-ofb'  => true,
125
            'des-ede3'     => true,
126
            'des-ede3-cbc' => true,
127
            'des-ede3-cfb' => true,
128
            'des-ede3-ofb' => true,
129
            'des-ofb'      => true,
130
            'des3'         => true,
131
            'desx'         => true,
132
            'rc2'          => true,
133
            'rc2-40-cbc'   => true,
134
            'rc2-64-cbc'   => true,
135
            'rc2-cbc'      => true,
136
            'rc2-cfb'      => true,
137
            'rc2-ecb'      => true,
138
            'rc2-ofb'      => true,
139
            'rc4'          => true,
140
            'rc4-40'       => true,
141
            'rc5'          => true,
142
            'rc5-cbc'      => true,
143
            'rc5-cfb'      => true,
144
            'rc5-ecb'      => true,
145
            'rc5-ofb'      => true,
146
            'seed'         => true,
147
            'seed-cbc'     => true,
148
            'seed-cfb'     => true,
149
            'seed-ecb'     => true,
150
            'seed-ofb'     => true,
151
        ],
152
        'smime' => [
153
            'des3'    => true,
154
            'des'     => true,
155
            'seed'    => true,
156
            'rc2-40'  => true,
157
            'rc2-64'  => true,
158
            'rc2-128' => true,
159
            'aes128'  => true,
160
            'aes192'  => true,
161
            'aes256'  => true,
162
        ]
163
    ];
164
165
    private $weakAlgorithms = [
166
        'rc2'          => true,
167
        'rc2-40'       => true,
168
        'rc2-64'       => true,
169
        'rc2-128'      => true,
170
        'rc2-40-cbc'   => true,
171
        'rc2-64-cbc'   => true,
172
        'rc2-cbc'      => true,
173
        'rc2-cfb'      => true,
174
        'rc2-ecb'      => true,
175
        'rc2-ofb'      => true,
176
        'rc4'          => true,
177 19
        'rc4-40'       => true,
178
        'des'          => true,
179 19
        'des-cbc'      => true,
180 19
        'des-cfb'      => true,
181 19
        'des-ecb'      => true,
182
        'des-ede'      => true,
183
        'des-ede-cbc'  => true,
184
        'des-ede-cfb'  => true,
185
        'des-ede-ofb'  => true,
186
        'des-ede3'     => true,
187
        'des-ede3-cbc' => true,
188
        'des-ede3-cfb' => true,
189 11
        'des-ede3-ofb' => true,
190
        'des-ofb'      => true,
191 11
        'des3'         => true,
192 11
        'desx'         => true,
193 11
        'seed'         => true,
194 11
        'seed-cbc'     => true,
195
        'seed-cfb'     => true,
196
        'seed-ecb'     => true,
197
        'seed-ofb'     => true,
198
    ];
199
200
    /**
201
     * Keep the not encrypted file
202
     *
203 3
     * @var bool
204
     */
205 3
    private $deleteSource = true;
206 3
207 3
    /**
208 3
     * Constructor
209
     *
210
     * @param string $path
211
     */
212
    public function __construct(string $path = '')
213
    {
214
        $this->setup('openssl', $path);
215
        $this->setMaskCandidates(['password']);
216
    }
217 9
218
    /**
219 9
     * Encrypt a file
220 9
     *
221
     * @param  string $file
222
     * @return \phpbu\App\Cli\Executable\OpenSSL
223
     */
224
    public function encryptFile(string $file): OpenSSL
225
    {
226
        $this->action     = self::ACTION_ENCRYPT;
227
        $this->sourceFile = $file;
228
        $this->targetFile = $file . '.enc';
229
        return $this;
230 11
    }
231
232 11
    /**
233 1
     * Encrypt a file
234
     *
235 10
     * @param  string $file
236 10
     * @return \phpbu\App\Cli\Executable\OpenSSL
237 10
     */
238
    public function decryptFile(string $file): OpenSSL
239
    {
240
        $this->action     = self::ACTION_DECRYPT;
241
        $this->sourceFile = $file . '.enc';
242
        $this->targetFile = $file;
243
        return $this;
244
    }
245
246
    /**
247 14
     * Delete the uncrypted data
248
     *
249 14
     * @param  boolean $bool
250 1
     * @return \phpbu\App\Cli\Executable\OpenSSL
251
     */
252 13
    public function deleteSource(bool $bool): OpenSSL
253 1
    {
254
        $this->deleteSource = $bool;
255 12
        return $this;
256 12
    }
257
258
    /**
259
     * Password to use for encryption
260
     *
261
     * @param  string $password
262
     * @return \phpbu\App\Cli\Executable\OpenSSL
263
     * @throws \phpbu\App\Exception
264
     */
265 4
    public function usePassword(string $password): OpenSSL
266
    {
267 4
        if (self::MODE_CERT === $this->mode) {
268 4
            throw new Exception('Cert file already set');
269
        }
270
        $this->mode = self::MODE_PASS;
271
        $this->password = $password;
272
        return $this;
273
    }
274
275
    /**
276
     * Set algorithm to use
277
     *
278 7
     * @param  string $algorithm
279
     * @return \phpbu\App\Cli\Executable\OpenSSL
280 7
     * @throws \phpbu\App\Exception
281 1
     */
282
    public function useAlgorithm(string $algorithm): OpenSSL
283 6
    {
284 6
        if (null === $this->mode) {
285 6
            throw new Exception('choose mode first, password or cert');
286
        }
287
        if (!isset($this->availableAlgorithms[$this->mode][$algorithm])) {
288
            throw new Exception('invalid algorithm');
289
        }
290
        $this->algorithm = $algorithm;
291
        return $this;
292
    }
293
294 15
    public function isUsingWeakAlgorithm(): bool
295
    {
296 15
        if (null === $this->algorithm) {
297 1
            throw new Exception('algorithm is not set');
298
        }
299 14
300 1
        return isset($this->weakAlgorithms[$this->algorithm]);
301
    }
302 13
303 1
    /**
304
     * Use base64 encoding
305
     *
306 12
     * @param bool $encode
307 12
     * @return \phpbu\App\Cli\Executable\OpenSSL
308
     */
309 12
    public function encodeBase64(bool $encode): OpenSSL
310
    {
311 12
        $this->base64 = $encode;
312 12
        return $this;
313
    }
314 12
315
    /**
316
     * Public key to use
317
     *
318
     * @param  string $file
319
     * @return \phpbu\App\Cli\Executable\OpenSSL
320
     * @throws \phpbu\App\Exception
321
     */
322 12
    public function useSSLCert(string $file): OpenSSL
323
    {
324 12
        if (self::MODE_PASS === $this->mode) {
325 5
            throw new Exception('Password already set');
326
        }
327 7
        $this->mode = self::MODE_CERT;
328
        $this->certFile = $file;
329 12
        return $this;
330
    }
331
332
    /**
333
     * OpenSSL CommandLine generator
334
     *
335
     * @return \SebastianFeldmann\Cli\CommandLine
336 5
     * @throws \phpbu\App\Exception
337
     */
338 5
    protected function createCommandLine(): CommandLine
339 5
    {
340 5
        if (empty($this->sourceFile)) {
341 5
            throw new Exception('file is missing');
342 5
        }
343 5
        if (empty($this->mode)) {
344 5
            throw new Exception('one of \'password\' or \'cert\' is mandatory');
345 5
        }
346 5
        if (empty($this->algorithm)) {
347
            throw new Exception('no algorithm specified');
348
        }
349
350
        $process = new CommandLine();
351
        $cmd     = new Cmd($this->binary);
352
353 7
        $process->addCommand($cmd);
354
355 7
        $this->setOptions($cmd);
356
        $this->addDeleteCommand($process);
357 7
358 7
        return $process;
359 7
    }
360 7
361 7
    /**
362 7
     * Set the openssl command line options
363 7
     *
364 7
     * @param \SebastianFeldmann\Cli\Command\Executable $cmd
365
     */
366
    protected function setOptions(Cmd $cmd): void
367
    {
368
        if ($this->mode == self::MODE_CERT) {
369
            $this->setCertOptions($cmd);
370
        } else {
371 12
            $this->setPasswordOptions($cmd);
372
        }
373 12
    }
374 8
375 8
    /**
376 8
     * Set command line options for SSL cert encryption
377
     *
378 12
     * @param \SebastianFeldmann\Cli\Command\Executable $cmd
379
     */
380
    protected function setCertOptions(Cmd $cmd): void
381
    {
382
        $cmd->addOption('smime');
383
        $cmd->addOption('-' . ($this->action === 'e' ? 'encrypt' : 'decrypt'));
384
        $cmd->addOption('-' . $this->algorithm);
385
        $cmd->addOption('-binary');
386
        $cmd->addOption('-in', $this->sourceFile, ' ');
387
        $cmd->addOption('-out', $this->targetFile, ' ');
388
        $cmd->addOption('-outform DER');
389
        $cmd->addArgument($this->certFile);
390
    }
391
392
    /**
393
     * Set command line options for password encryption
394
     *
395
     * @param \SebastianFeldmann\Cli\Command\Executable $cmd
396
     */
397
    protected function setPasswordOptions(Cmd $cmd): void
398
    {
399
        $password = 'pass:' . $this->password;
400
401
        $cmd->addOption('enc');
402
        $cmd->addOption('-' . $this->action);
403
        $cmd->addOptionIfNotEmpty('-a', $this->base64, false);
404
        $cmd->addOption('-' . $this->algorithm);
405
        $cmd->addOption('-pass', $password, ' ');
406
        $cmd->addOption('-in', $this->sourceFile, ' ');
407
        $cmd->addOption('-out', $this->targetFile, ' ');
408
    }
409
410
    /**
411
     * Add the 'rm' command to remove the uncrypted file
412
     *
413
     * @param \SebastianFeldmann\Cli\CommandLine $process
414
     */
415
    protected function addDeleteCommand(CommandLine $process): void
416
    {
417
        if ($this->deleteSource) {
418
            $cmd = new Cmd('rm');
419
            $cmd->addArgument($this->sourceFile);
420
            $process->addCommand($cmd);
421
        }
422
    }
423
}
424