Completed
Branch FET-10724-event-editor-cleanup (955656)
by
unknown
149:38 queued 136:37
created

EE_Encryption::m_decrypt()   B

Complexity

Conditions 4
Paths 5

Size

Total Lines 29
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Importance

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