Completed
Branch FET-9795-new-interfaces (793e2e)
by
unknown
121:05 queued 108:17
created

EE_Encryption::acme_decrypt()   C

Complexity

Conditions 7
Paths 7

Size

Total Lines 24
Code Lines 16

Duplication

Lines 4
Ratio 16.67 %

Importance

Changes 0
Metric Value
cc 7
eloc 16
nc 7
nop 1
dl 4
loc 24
rs 6.7272
c 0
b 0
f 0
1
<?php use EventEspresso\core\interfaces\InterminableInterface;
2
3
defined('EVENT_ESPRESSO_VERSION') || exit('No direct script access allowed');
4
5
6
7
/**
8
 * EE_Encryption class
9
 * class for applying low-grade string encryption/decryption
10
 * really only good for hiding content from simple bots and script kiddies
11
 * but better for solving encoding issues with databases
12
 *
13
 * @package    Event Espresso
14
 * @subpackage includes/functions
15
 * @author     Brent Christensen
16
 */
17
class EE_Encryption
18
{
19
20
    /**
21
     * key used for saving the encryption key to the wp_options table
22
     */
23
    const ENCRYPTION_OPTION_KEY = 'ee_encryption_key';
24
25
    /**
26
     * the OPENSSL cipher method used
27
     */
28
    const OPENSSL_CIPHER_METHOD = 'aes-256-ctr';
29
30
    /**
31
     * the OPENSSL digest method used
32
     */
33
    const OPENSSL_DIGEST_METHOD = 'sha512';
34
35
    /**
36
     * separates the encrypted text from the initialization vector
37
     */
38
    const OPENSSL_IV_DELIMITER = ':iv:';
39
40
    /**
41
     * appended to text encrypted using the acme encryption
42
     */
43
    const ACME_ENCRYPTION_FLAG = '::ae';
44
45
46
47
    /**
48
     * instance of the EE_Encryption object
49
     */
50
    protected static $_instance;
51
52
    /**
53
     * @var string $_encryption_key
54
     */
55
    protected $_encryption_key;
56
57
    /**
58
     * @var boolean $_use_openssl_encrypt
59
     */
60
    protected $_use_openssl_encrypt = false;
61
62
    /**
63
     * @var boolean $_use_mcrypt
64
     */
65
    protected $_use_mcrypt = false;
66
67
    /**
68
     * @var boolean $_use_base64_encode
69
     */
70
    protected $_use_base64_encode = false;
71
72
73
74
    /**
75
     * protected constructor to prevent direct creation
76
     */
77
    protected function __construct()
78
    {
79
        if (! defined('ESPRESSO_ENCRYPT')) {
80
            define('ESPRESSO_ENCRYPT', true);
81
        }
82
        if (extension_loaded('openssl')) {
83
            $this->_use_openssl_encrypt = true;
84
        } else if (extension_loaded('mcrypt')) {
85
            $this->_use_mcrypt = true;
86
        }
87
        if (function_exists('base64_encode')) {
88
            $this->_use_base64_encode = true;
89
        }
90
    }
91
92
93
94
    /**
95
     * singleton method used to instantiate class object
96
     *
97
     * @return EE_Encryption
98
     */
99
    public static function instance()
100
    {
101
        // check if class object is instantiated
102
        if (! self::$_instance instanceof EE_Encryption) {
103
            self::$_instance = new self();
104
        }
105
        return self::$_instance;
106
    }
107
108
109
110
    /**
111
     * get encryption key
112
     *
113
     * @return string
114
     */
115
    public function get_encryption_key()
116
    {
117
        // if encryption key has not been set
118
        if (empty($this->_encryption_key)) {
119
            // retrieve encryption_key from db
120
            $this->_encryption_key = get_option(EE_Encryption::ENCRYPTION_OPTION_KEY, '');
121
            // WHAT?? No encryption_key in the db ??
122
            if ($this->_encryption_key === '') {
123
                // let's make one. And md5 it to make it just the right size for a key
124
                $new_key = md5($this->generate_random_string());
125
                // now save it to the db for later
126
                add_option(EE_Encryption::ENCRYPTION_OPTION_KEY, $new_key);
127
                // here's the key - FINALLY !
128
                $this->_encryption_key = $new_key;
129
            }
130
        }
131
        return $this->_encryption_key;
132
    }
133
134
135
136
    /**
137
     * encrypts data
138
     *
139
     * @param string $text_string - the text to be encrypted
140
     * @return string
141
     * @throws RuntimeException
142
     */
143
    public function encrypt($text_string = '')
144
    {
145
        // you give me nothing??? GET OUT !
146
        if (empty($text_string)) {
147
            return $text_string;
148
        }
149
        if ($this->_use_openssl_encrypt) {
150
            $encrypted_text = $this->openssl_encrypt($text_string);
151
        } else {
152
            $encrypted_text = $this->acme_encrypt($text_string);
153
        }
154
        return $encrypted_text;
155
    }
156
157
158
159
    /**
160
     * decrypts data
161
     *
162
     * @param string $encrypted_text - the text to be decrypted
163
     * @return string
164
     * @throws RuntimeException
165
     */
166
    public function decrypt($encrypted_text = '')
167
    {
168
        // you give me nothing??? GET OUT !
169
        if (empty($encrypted_text)) {
170
            return $encrypted_text;
171
        }
172
        // if PHP's mcrypt functions are installed then we'll use them
173
        if ($this->_use_openssl_encrypt) {
174
            $decrypted_text = $this->openssl_decrypt($encrypted_text);
175
        } else {
176
            $decrypted_text = $this->acme_decrypt($encrypted_text);
177
        }
178
        return $decrypted_text;
179
    }
180
181
182
183
    /**
184
     * encodes string with PHP's base64 encoding
185
     *
186
     * @see http://php.net/manual/en/function.base64-encode.php
187
     * @param string $text_string the text to be encoded
188
     * @return string
189
     */
190
    public function base64_string_encode($text_string = '')
191
    {
192
        // you give me nothing??? GET OUT !
193
        if (empty($text_string) || ! $this->_use_base64_encode) {
194
            return $text_string;
195
        }
196
        // encode
197
        return base64_encode($text_string);
198
    }
199
200
201
202
    /**
203
     * decodes string that has been encoded with PHP's base64 encoding
204
     *
205
     * @see http://php.net/manual/en/function.base64-encode.php
206
     * @param string $encoded_string the text to be decoded
207
     * @return string
208
     */
209
    public function base64_string_decode($encoded_string = '')
210
    {
211
        // you give me nothing??? GET OUT !
212
        if (empty($encoded_string) || ! $this->valid_base_64($encoded_string)) {
213
            return $encoded_string;
214
        }
215
        // decode
216
        return base64_decode($encoded_string);
217
    }
218
219
220
221
    /**
222
     * encodes  url string with PHP's base64 encoding
223
     *
224
     * @see http://php.net/manual/en/function.base64-encode.php
225
     * @param string $text_string the text to be encoded
226
     * @return string
227
     */
228
    public function base64_url_encode($text_string = '')
229
    {
230
        // you give me nothing??? GET OUT !
231
        if (empty($text_string) || ! $this->_use_base64_encode) {
232
            return $text_string;
233
        }
234
        // encode
235
        $encoded_string = base64_encode($text_string);
236
        // remove chars to make encoding more URL friendly
237
        return strtr($encoded_string, '+/=', '-_,');
238
    }
239
240
241
242
    /**
243
     * decodes  url string that has been encoded with PHP's base64 encoding
244
     *
245
     * @see http://php.net/manual/en/function.base64-encode.php
246
     * @param string $encoded_string the text to be decoded
247
     * @return string
248
     */
249
    public function base64_url_decode($encoded_string = '')
250
    {
251
        // you give me nothing??? GET OUT !
252
        if (empty($encoded_string) || ! $this->valid_base_64($encoded_string)) {
253
            return $encoded_string;
254
        }
255
        // replace previously removed characters
256
        $encoded_string = strtr($encoded_string, '-_,', '+/=');
257
        // decode
258
        return base64_decode($encoded_string);
259
    }
260
261
262
263
    /**
264
     * encrypts data using PHP's openssl functions
265
     *
266
     * @param string $text_string the text to be encrypted
267
     * @return string
268
     * @throws RuntimeException
269
     */
270
    protected function openssl_encrypt($text_string = '')
271
    {
272
        // you give me nothing??? GET OUT !
273
        if (empty($text_string)) {
274
            return $text_string;
275
        }
276
        // get initialization vector size
277
        $iv_size = openssl_cipher_iv_length(EE_Encryption::OPENSSL_CIPHER_METHOD);
278
        // generate initialization vector
279
        $iv = openssl_random_pseudo_bytes($iv_size, $is_strong);
280
        if ($iv === false || $is_strong === false) {
281
            throw new RuntimeException(
282
                esc_html__('Failed to generate OpenSSL initialization vector.', 'event_espresso')
283
            );
284
        }
285
        // encrypt it
286
        $encrypted_text = openssl_encrypt(
287
            $text_string,
288
            EE_Encryption::OPENSSL_CIPHER_METHOD,
289
            openssl_digest($this->get_encryption_key(), EE_Encryption::OPENSSL_DIGEST_METHOD),
290
            0,
291
            $iv
292
        );
293
        // append the initialization vector
294
        $encrypted_text .= EE_Encryption::OPENSSL_IV_DELIMITER . $iv;
295
        // trim and maybe encode
296
        return $this->_use_base64_encode
297
            ? trim(base64_encode($encrypted_text))
298
            : trim($encrypted_text);
299
    }
300
301
302
303
    /**
304
     * decrypts data that has been encrypted with PHP's openssl functions
305
     *
306
     * @param string $encrypted_text the text to be decrypted
307
     * @return string
308
     * @throws RuntimeException
309
     */
310
    protected function openssl_decrypt($encrypted_text = '')
311
    {
312
        // you give me nothing??? GET OUT !
313
        if (empty($encrypted_text)) {
314
            return $encrypted_text;
315
        }
316
        // decode
317
        $encrypted_text = $this->valid_base_64($encrypted_text)
318
            ? base64_decode($encrypted_text)
319
            : $encrypted_text;
320
        $encrypted_components = explode(
321
            EE_Encryption::OPENSSL_IV_DELIMITER,
322
            $encrypted_text,
323
            2
324
        );
325
        // check that iv exists, and if not, maybe text was encoded using mcrypt?
326
        if (! isset($encrypted_components[1]) && $this->_use_mcrypt) {
327
            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...
328
        }
329
        // decrypt it
330
        $decrypted_text = openssl_decrypt(
331
            $encrypted_components[0],
332
            EE_Encryption::OPENSSL_CIPHER_METHOD,
333
            openssl_digest($this->get_encryption_key(), EE_Encryption::OPENSSL_DIGEST_METHOD),
334
            0,
335
            $encrypted_components[1]
336
        );
337
        $decrypted_text = trim($decrypted_text);
338
        return $decrypted_text;
339
    }
340
341
342
343
    /**
344
     * encrypts data for acme servers that didn't bother to install PHP mcrypt
345
     *
346
     * @see http://stackoverflow.com/questions/800922/how-to-encrypt-string-without-mcrypt-library-in-php
347
     * @param string $text_string the text to be decrypted
348
     * @return string
349
     */
350
    protected function acme_encrypt($text_string = '')
351
    {
352
        // you give me nothing??? GET OUT !
353
        if (empty($text_string)) {
354
            return $text_string;
355
        }
356
        $key_bits = str_split(
357
            str_pad('', strlen($text_string), $this->get_encryption_key(), STR_PAD_RIGHT)
358
        );
359
        $string_bits = str_split($text_string);
360 View Code Duplication
        foreach ($string_bits as $k => $v) {
361
            $temp = ord($v) + ord($key_bits[$k]);
362
            $string_bits[$k] = chr($temp > 255 ? ($temp - 256) : $temp);
363
        }
364
        $encrypted_text = implode('', $string_bits);
365
        $encrypted_text .= EE_Encryption::ACME_ENCRYPTION_FLAG;
366
        return $this->_use_base64_encode
367
            ? base64_encode($encrypted_text)
368
            : $encrypted_text;
369
    }
370
371
372
373
    /**
374
     * decrypts data for acme servers that didn't bother to install PHP mcrypt
375
     *
376
     * @see http://stackoverflow.com/questions/800922/how-to-encrypt-string-without-mcrypt-library-in-php
377
     * @param string $encrypted_text the text to be decrypted
378
     * @return string
379
     */
380
    protected function acme_decrypt($encrypted_text = '')
381
    {
382
        // you give me nothing??? GET OUT !
383
        if (empty($encrypted_text)) {
384
            return $encrypted_text;
385
        }
386
        // decode the data ?
387
        $encrypted_text = $this->valid_base_64($encrypted_text)
388
            ? base64_decode($encrypted_text)
389
            : $encrypted_text;
390
        if (strpos($encrypted_text, EE_Encryption::ACME_ENCRYPTION_FLAG) === false && $this->_use_mcrypt) {
391
            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...
392
        }
393
        $encrypted_text = substr($encrypted_text, 0, -4);
394
        $key_bits = str_split(
395
            str_pad('', strlen($encrypted_text), $this->get_encryption_key(), STR_PAD_RIGHT)
396
        );
397
        $string_bits = str_split($encrypted_text);
398 View Code Duplication
        foreach ($string_bits as $k => $v) {
399
            $temp = ord($v) - ord($key_bits[$k]);
400
            $string_bits[$k] = chr($temp < 0 ? ($temp + 256) : $temp);
401
        }
402
        return implode('', $string_bits);
403
    }
404
405
406
407
    /**
408
     * @see http://stackoverflow.com/questions/2556345/detect-base64-encoding-in-php#30231906
409
     * @param $string
410
     * @return bool
411
     */
412
    protected function valid_base_64($string)
413
    {
414
        // ensure data is a string
415
        if (! is_string($string) || ! $this->_use_base64_encode) {
416
            return false;
417
        }
418
        $decoded = base64_decode($string, true);
419
        // Check if there is no invalid character in string
420
        if (! preg_match('/^[a-zA-Z0-9\/\r\n+]*={0,2}$/', $string)) {
421
            return false;
422
        }
423
        // Decode the string in strict mode and send the response
424
        if (! base64_decode($string, true)) {
425
            return false;
426
        }
427
        // Encode and compare it to original one
428
        return base64_encode($decoded) === $string;
429
    }
430
431
432
433
    /**
434
     * generate random string
435
     *
436
     * @see http://stackoverflow.com/questions/637278/what-is-the-best-way-to-generate-a-random-key-within-php
437
     * @param int $length number of characters for random string
438
     * @return string
439
     */
440
    public function generate_random_string($length = 40)
441
    {
442
        $iterations = ceil($length / 40);
443
        $random_string = '';
444
        for ($i = 0; $i < $iterations; $i++) {
445
            $random_string .= sha1(microtime(true) . mt_rand(10000, 90000));
446
        }
447
        $random_string = substr($random_string, 0, $length);
448
        return $random_string;
449
    }
450
451
452
453
    /**
454
     * encrypts data using PHP's mcrypt functions
455
     *
456
     * @deprecated 4.9.39
457
     * @param string $text_string
458
     * @internal   param $string - the text to be encrypted
459
     * @return string
460
     * @throws RuntimeException
461
     */
462
    protected function m_encrypt($text_string = '')
463
    {
464
        // you give me nothing??? GET OUT !
465
        if (empty($text_string)) {
466
            return $text_string;
467
        }
468
        // get the initialization vector size
469
        $iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
470
        // initialization vector
471
        $iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
472
        if ($iv === false) {
473
            throw new RuntimeException(
474
                esc_html__('Failed to generate mcrypt initialization vector.', 'event_espresso')
475
            );
476
        }
477
        // encrypt it
478
        $encrypted_text = mcrypt_encrypt(
479
            MCRYPT_RIJNDAEL_256,
480
            $this->get_encryption_key(),
481
            $text_string,
482
            MCRYPT_MODE_ECB,
483
            $iv
484
        );
485
        // trim and maybe encode
486
        return $this->_use_base64_encode
487
            ? trim(base64_encode($encrypted_text))
488
            : trim($encrypted_text);
489
    }
490
491
492
493
    /**
494
     * decrypts data that has been encrypted with PHP's mcrypt functions
495
     *
496
     * @deprecated 4.9.39
497
     * @param string $encrypted_text the text to be decrypted
498
     * @return string
499
     * @throws RuntimeException
500
     */
501
    protected function m_decrypt($encrypted_text = '')
502
    {
503
        // you give me nothing??? GET OUT !
504
        if (empty($encrypted_text)) {
505
            return $encrypted_text;
506
        }
507
        // decode
508
        $encrypted_text = $this->valid_base_64($encrypted_text)
509
            ? base64_decode($encrypted_text)
510
            : $encrypted_text;
511
        // get the initialization vector size
512
        $iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
513
        $iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
514
        if ($iv === false) {
515
            throw new RuntimeException(
516
                esc_html__('Failed to generate mcrypt initialization vector.', 'event_espresso')
517
            );
518
        }
519
        // decrypt it
520
        $decrypted_text = mcrypt_decrypt(
521
            MCRYPT_RIJNDAEL_256,
522
            $this->get_encryption_key(),
523
            $encrypted_text,
524
            MCRYPT_MODE_ECB,
525
            $iv
526
        );
527
        $decrypted_text = trim($decrypted_text);
528
        return $decrypted_text;
529
    }
530
531
}
532
/* End of file EE_Encryption.class.php */
533
/* Location: /includes/core/EE_Encryption.core.php */