Completed
Branch BUG-10412-mcrypt-deprecated (7d81e0)
by
unknown
133:27 queued 121:15
created

EE_Encryption   C

Complexity

Total Complexity 65

Size/Duplication

Total Lines 514
Duplicated Lines 1.56 %

Coupling/Cohesion

Components 2
Dependencies 0

Importance

Changes 0
Metric Value
dl 8
loc 514
rs 5.7894
c 0
b 0
f 0
wmc 65
lcom 2
cbo 0

17 Methods

Rating   Name   Duplication   Size   Complexity  
B valid_base_64() 0 18 5
A generate_random_string() 0 10 2
B __construct() 0 14 5
A instance() 0 8 2
A get_encryption_key() 0 18 3
A encrypt() 0 13 3
A decrypt() 0 14 3
A base64_string_encode() 0 9 3
A base64_string_decode() 0 9 3
A base64_url_encode() 0 11 3
A base64_url_decode() 0 11 3
B openssl_encrypt() 0 30 5
B openssl_decrypt() 0 30 5
B acme_encrypt() 4 20 5
C acme_decrypt() 4 23 7
B m_encrypt() 0 28 4
B m_decrypt() 0 29 4

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like EE_Encryption often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use EE_Encryption, and based on these observations, apply Extract Interface, too.

1
<?php
2
defined('EVENT_ESPRESSO_VERSION') || exit('No direct script access allowed');
3
4
5
6
/**
7
 * EE_Encryption class
8
 * class for applying low-grade string encryption/decryption
9
 * really only good for hiding content from simple bots and script kiddies
10
 * but better for solving encoding issues with databases
11
 *
12
 * @package    Event Espresso
13
 * @subpackage includes/functions
14
 * @author     Brent Christensen
15
 */
16
class EE_Encryption
17
{
18
19
    /**
20
     * key used for saving the encryption key to the wp_options table
21
     */
22
    const ENCRYPTION_OPTION_KEY = 'ee_encryption_key';
23
24
    /**
25
     * the OPENSSL cipher method used
26
     */
27
    const OPENSSL_CIPHER_METHOD = 'aes-256-ctr';
28
29
    /**
30
     * the OPENSSL digest method used
31
     */
32
    const OPENSSL_DIGEST_METHOD = 'sha512';
33
34
    /**
35
     * separates the encrypted text from the initialization vector
36
     */
37
    const OPENSSL_IV_DELIMITER = ':iv:';
38
39
    /**
40
     * appended to text encrypted using the acme encryption
41
     */
42
    const ACME_ENCRYPTION_FLAG = '::ae';
43
44
45
46
    /**
47
     * instance of the EE_Encryption object
48
     */
49
    protected static $_instance;
50
51
    /**
52
     * @var string $_encryption_key
53
     */
54
    protected $_encryption_key;
55
56
    /**
57
     * @var boolean $_use_openssl_encrypt
58
     */
59
    protected $_use_openssl_encrypt = false;
60
61
    /**
62
     * @var boolean $_use_mcrypt
63
     */
64
    protected $_use_mcrypt = false;
65
66
    /**
67
     * @var boolean $_use_base64_encode
68
     */
69
    protected $_use_base64_encode = false;
70
71
72
73
    /**
74
     * protected constructor to prevent direct creation
75
     */
76
    protected function __construct()
77
    {
78
        if (! defined('ESPRESSO_ENCRYPT')) {
79
            define('ESPRESSO_ENCRYPT', true);
80
        }
81
        if (extension_loaded('openssl')) {
82
            $this->_use_openssl_encrypt = true;
83
        } else if (extension_loaded('mcrypt')) {
84
            $this->_use_mcrypt = true;
85
        }
86
        if (function_exists('base64_encode')) {
87
            $this->_use_base64_encode = true;
88
        }
89
    }
90
91
92
93
    /**
94
     * singleton method used to instantiate class object
95
     *
96
     * @return EE_Encryption
97
     */
98
    public static function instance()
99
    {
100
        // check if class object is instantiated
101
        if (! self::$_instance instanceof EE_Encryption) {
102
            self::$_instance = new self();
103
        }
104
        return self::$_instance;
105
    }
106
107
108
109
    /**
110
     * get encryption key
111
     *
112
     * @return string
113
     */
114
    public function get_encryption_key()
115
    {
116
        // if encryption key has not been set
117
        if (empty($this->_encryption_key)) {
118
            // retrieve encryption_key from db
119
            $this->_encryption_key = get_option(EE_Encryption::ENCRYPTION_OPTION_KEY, '');
120
            // WHAT?? No encryption_key in the db ??
121
            if ($this->_encryption_key === '') {
122
                // let's make one. And md5 it to make it just the right size for a key
123
                $new_key = md5($this->generate_random_string());
124
                // now save it to the db for later
125
                add_option(EE_Encryption::ENCRYPTION_OPTION_KEY, $new_key);
126
                // here's the key - FINALLY !
127
                $this->_encryption_key = $new_key;
128
            }
129
        }
130
        return $this->_encryption_key;
131
    }
132
133
134
135
    /**
136
     * encrypts data
137
     *
138
     * @param string $text_string - the text to be encrypted
139
     * @return string
140
     * @throws RuntimeException
141
     */
142
    public function encrypt($text_string = '')
143
    {
144
        // you give me nothing??? GET OUT !
145
        if (empty($text_string)) {
146
            return $text_string;
147
        }
148
        if ($this->_use_openssl_encrypt) {
149
            $encrypted_text = $this->openssl_encrypt($text_string);
150
        } else {
151
            $encrypted_text = $this->acme_encrypt($text_string);
152
        }
153
        return $encrypted_text;
154
    }
155
156
157
158
    /**
159
     * decrypts data
160
     *
161
     * @param string $encrypted_text - the text to be decrypted
162
     * @return string
163
     * @throws RuntimeException
164
     */
165
    public function decrypt($encrypted_text = '')
166
    {
167
        // you give me nothing??? GET OUT !
168
        if (empty($encrypted_text)) {
169
            return $encrypted_text;
170
        }
171
        // if PHP's mcrypt functions are installed then we'll use them
172
        if ($this->_use_openssl_encrypt) {
173
            $decrypted_text = $this->openssl_decrypt($encrypted_text);
174
        } else {
175
            $decrypted_text = $this->acme_decrypt($encrypted_text);
176
        }
177
        return $decrypted_text;
178
    }
179
180
181
182
    /**
183
     * encodes string with PHP's base64 encoding
184
     *
185
     * @see http://php.net/manual/en/function.base64-encode.php
186
     * @param string $text_string the text to be encoded
187
     * @return string
188
     */
189
    public function base64_string_encode($text_string = '')
190
    {
191
        // you give me nothing??? GET OUT !
192
        if (empty($text_string) || ! $this->_use_base64_encode) {
193
            return $text_string;
194
        }
195
        // encode
196
        return base64_encode($text_string);
197
    }
198
199
200
201
    /**
202
     * decodes string that has been encoded with PHP's base64 encoding
203
     *
204
     * @see http://php.net/manual/en/function.base64-encode.php
205
     * @param string $encoded_string the text to be decoded
206
     * @return string
207
     */
208
    public function base64_string_decode($encoded_string = '')
209
    {
210
        // you give me nothing??? GET OUT !
211
        if (empty($encoded_string) || ! $this->valid_base_64($encoded_string)) {
212
            return $encoded_string;
213
        }
214
        // decode
215
        return base64_decode($encoded_string);
216
    }
217
218
219
220
    /**
221
     * encodes  url string with PHP's base64 encoding
222
     *
223
     * @see http://php.net/manual/en/function.base64-encode.php
224
     * @param string $text_string the text to be encoded
225
     * @return string
226
     */
227
    public function base64_url_encode($text_string = '')
228
    {
229
        // you give me nothing??? GET OUT !
230
        if (empty($text_string) || ! $this->_use_base64_encode) {
231
            return $text_string;
232
        }
233
        // encode
234
        $encoded_string = base64_encode($text_string);
235
        // remove chars to make encoding more URL friendly
236
        return strtr($encoded_string, '+/=', '-_,');
237
    }
238
239
240
241
    /**
242
     * decodes  url string that has been encoded with PHP's base64 encoding
243
     *
244
     * @see http://php.net/manual/en/function.base64-encode.php
245
     * @param string $encoded_string the text to be decoded
246
     * @return string
247
     */
248
    public function base64_url_decode($encoded_string = '')
249
    {
250
        // you give me nothing??? GET OUT !
251
        if (empty($encoded_string) || ! $this->valid_base_64($encoded_string)) {
252
            return $encoded_string;
253
        }
254
        // replace previously removed characters
255
        $encoded_string = strtr($encoded_string, '-_,', '+/=');
256
        // decode
257
        return base64_decode($encoded_string);
258
    }
259
260
261
262
    /**
263
     * encrypts data using PHP's openssl functions
264
     *
265
     * @param string $text_string the text to be encrypted
266
     * @return string
267
     * @throws RuntimeException
268
     */
269
    protected function openssl_encrypt($text_string = '')
270
    {
271
        // you give me nothing??? GET OUT !
272
        if (empty($text_string)) {
273
            return $text_string;
274
        }
275
        // get initialization vector size
276
        $iv_size = openssl_cipher_iv_length(EE_Encryption::OPENSSL_CIPHER_METHOD);
277
        // generate initialization vector
278
        $iv = openssl_random_pseudo_bytes($iv_size, $is_strong);
279
        if ($iv === false || $is_strong === false) {
280
            throw new RuntimeException(
281
                esc_html__('Failed to generate OpenSSL initialization vector.', 'event_espresso')
282
            );
283
        }
284
        // encrypt it
285
        $encrypted_text = openssl_encrypt(
286
            $text_string,
287
            EE_Encryption::OPENSSL_CIPHER_METHOD,
288
            openssl_digest($this->get_encryption_key(), EE_Encryption::OPENSSL_DIGEST_METHOD),
289
            0,
290
            $iv
291
        );
292
        // append the initialization vector
293
        $encrypted_text .= EE_Encryption::OPENSSL_IV_DELIMITER . $iv;
294
        // trim and maybe encode
295
        return $this->_use_base64_encode
296
            ? trim(base64_encode($encrypted_text))
297
            : trim($encrypted_text);
298
    }
299
300
301
302
    /**
303
     * decrypts data that has been encrypted with PHP's openssl functions
304
     *
305
     * @param string $encrypted_text the text to be decrypted
306
     * @return string
307
     * @throws RuntimeException
308
     */
309
    protected function openssl_decrypt($encrypted_text = '')
310
    {
311
        // you give me nothing??? GET OUT !
312
        if (empty($encrypted_text)) {
313
            return $encrypted_text;
314
        }
315
        // decode
316
        $encrypted_text = $this->valid_base_64($encrypted_text)
317
            ? base64_decode($encrypted_text)
318
            : $encrypted_text;
319
        $encrypted_components = explode(
320
            EE_Encryption::OPENSSL_IV_DELIMITER,
321
            $encrypted_text,
322
            2
323
        );
324
        // check that iv exists, and if not, maybe text was encoded using mcrypt?
325
        if (! isset($encrypted_components[1]) && $this->_use_mcrypt) {
326
            return $this->m_decrypt($encrypted_text);
0 ignored issues
show
Deprecated Code introduced by
The method EE_Encryption::m_decrypt() has been deprecated with message: 4.9.39

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
327
        }
328
        // decrypt it
329
        $decrypted_text = openssl_decrypt(
330
            $encrypted_components[0],
331
            EE_Encryption::OPENSSL_CIPHER_METHOD,
332
            openssl_digest($this->get_encryption_key(), EE_Encryption::OPENSSL_DIGEST_METHOD),
333
            0,
334
            $encrypted_components[1]
335
        );
336
        $decrypted_text = trim($decrypted_text);
337
        return $decrypted_text;
338
    }
339
340
341
342
    /**
343
     * encrypts data for acme servers that didn't bother to install PHP mcrypt
344
     *
345
     * @see http://stackoverflow.com/questions/800922/how-to-encrypt-string-without-mcrypt-library-in-php
346
     * @param string $text_string the text to be decrypted
347
     * @return string
348
     */
349
    protected function acme_encrypt($text_string = '')
350
    {
351
        // you give me nothing??? GET OUT !
352
        if (empty($text_string)) {
353
            return $text_string;
354
        }
355
        $key_bits = str_split(
356
            str_pad('', strlen($text_string), $this->get_encryption_key(), STR_PAD_RIGHT)
357
        );
358
        $string_bits = str_split($text_string);
359 View Code Duplication
        foreach ($string_bits as $k => $v) {
360
            $temp = ord($v) + ord($key_bits[$k]);
361
            $string_bits[$k] = chr($temp > 255 ? ($temp - 256) : $temp);
362
        }
363
        $encrypted_text = implode('', $string_bits);
364
        $encrypted_text .= EE_Encryption::ACME_ENCRYPTION_FLAG;
365
        return $this->_use_base64_encode
366
            ? base64_encode($encrypted_text)
367
            : $encrypted_text;
368
    }
369
370
371
372
    /**
373
     * decrypts data for acme servers that didn't bother to install PHP mcrypt
374
     *
375
     * @see http://stackoverflow.com/questions/800922/how-to-encrypt-string-without-mcrypt-library-in-php
376
     * @param string $encrypted_text the text to be decrypted
377
     * @return string
378
     */
379
    protected function acme_decrypt($encrypted_text = '')
380
    {
381
        // you give me nothing??? GET OUT !
382
        if (empty($encrypted_text)) {
383
            return $encrypted_text;
384
        }
385
        // decode the data ?
386
        $encrypted_text = $this->valid_base_64($encrypted_text)
387
            ? base64_decode($encrypted_text)
388
            : $encrypted_text;
389
        if (strpos($encrypted_text, EE_Encryption::ACME_ENCRYPTION_FLAG) === false && $this->_use_mcrypt) {
390
            return $this->m_decrypt($encrypted_text);
0 ignored issues
show
Deprecated Code introduced by
The method EE_Encryption::m_decrypt() has been deprecated with message: 4.9.39

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
391
        }
392
        $key_bits = str_split(
393
            str_pad('', strlen($encrypted_text), $this->get_encryption_key(), STR_PAD_RIGHT)
394
        );
395
        $string_bits = str_split($encrypted_text);
396 View Code Duplication
        foreach ($string_bits as $k => $v) {
397
            $temp = ord($v) - ord($key_bits[$k]);
398
            $string_bits[$k] = chr($temp < 0 ? ($temp + 256) : $temp);
399
        }
400
        return implode('', $string_bits);
401
    }
402
403
404
405
    /**
406
     * @see http://stackoverflow.com/questions/2556345/detect-base64-encoding-in-php#30231906
407
     * @param $string
408
     * @return bool
409
     */
410
    protected function valid_base_64($string)
411
    {
412
        // ensure data is a string
413
        if (! is_string($string) || ! $this->_use_base64_encode) {
414
            return false;
415
        }
416
        $decoded = base64_decode($string, true);
417
        // Check if there is no invalid character in string
418
        if (! preg_match('/^[a-zA-Z0-9\/\r\n+]*={0,2}$/', $string)) {
419
            return false;
420
        }
421
        // Decode the string in strict mode and send the response
422
        if (! base64_decode($string, true)) {
423
            return false;
424
        }
425
        // Encode and compare it to original one
426
        return base64_encode($decoded) === $string;
427
    }
428
429
430
431
    /**
432
     * generate random string
433
     *
434
     * @see http://stackoverflow.com/questions/637278/what-is-the-best-way-to-generate-a-random-key-within-php
435
     * @param int $length number of characters for random string
436
     * @return string
437
     */
438
    public function generate_random_string($length = 40)
439
    {
440
        $iterations = ceil($length / 40);
441
        $random_string = '';
442
        for ($i = 0; $i < $iterations; $i++) {
443
            $random_string .= sha1(microtime(true) . mt_rand(10000, 90000));
444
        }
445
        $random_string = substr($random_string, 0, $length);
446
        return $random_string;
447
    }
448
449
450
451
    /**
452
     * encrypts data using PHP's mcrypt functions
453
     *
454
     * @deprecated 4.9.39
455
     * @param string $text_string
456
     * @internal   param $string - the text to be encrypted
457
     * @return string
458
     * @throws RuntimeException
459
     */
460
    protected function m_encrypt($text_string = '')
461
    {
462
        // you give me nothing??? GET OUT !
463
        if (empty($text_string)) {
464
            return $text_string;
465
        }
466
        // get the initialization vector size
467
        $iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
468
        // initialization vector
469
        $iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
470
        if ($iv === false) {
471
            throw new RuntimeException(
472
                esc_html__('Failed to generate mcrypt initialization vector.', 'event_espresso')
473
            );
474
        }
475
        // encrypt it
476
        $encrypted_text = mcrypt_encrypt(
477
            MCRYPT_RIJNDAEL_256,
478
            $this->get_encryption_key(),
479
            $text_string,
480
            MCRYPT_MODE_ECB,
481
            $iv
482
        );
483
        // trim and maybe encode
484
        return $this->_use_base64_encode
485
            ? trim(base64_encode($encrypted_text))
486
            : trim($encrypted_text);
487
    }
488
489
490
491
    /**
492
     * decrypts data that has been encrypted with PHP's mcrypt functions
493
     *
494
     * @deprecated 4.9.39
495
     * @param string $encrypted_text the text to be decrypted
496
     * @return string
497
     * @throws RuntimeException
498
     */
499
    protected function m_decrypt($encrypted_text = '')
500
    {
501
        // you give me nothing??? GET OUT !
502
        if (empty($encrypted_text)) {
503
            return $encrypted_text;
504
        }
505
        // decode
506
        $encrypted_text = $this->valid_base_64($encrypted_text)
507
            ? base64_decode($encrypted_text)
508
            : $encrypted_text;
509
        // get the initialization vector size
510
        $iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
511
        $iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
512
        if ($iv === false) {
513
            throw new RuntimeException(
514
                esc_html__('Failed to generate mcrypt initialization vector.', 'event_espresso')
515
            );
516
        }
517
        // decrypt it
518
        $decrypted_text = mcrypt_decrypt(
519
            MCRYPT_RIJNDAEL_256,
520
            $this->get_encryption_key(),
521
            $encrypted_text,
522
            MCRYPT_MODE_ECB,
523
            $iv
524
        );
525
        $decrypted_text = trim($decrypted_text);
526
        return $decrypted_text;
527
    }
528
529
}
530
/* End of file EE_Encryption.class.php */
531
/* Location: /includes/core/EE_Encryption.core.php */