source: sourcecode/system/libraries/Encrypt.php @ 1

Last change on this file since 1 was 1, checked in by dungnv, 11 years ago
File size: 11.3 KB
Line 
1<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
2/**
3 * CodeIgniter
4 *
5 * An open source application development framework for PHP 5.1.6 or newer
6 *
7 * @package             CodeIgniter
8 * @author              ExpressionEngine Dev Team
9 * @copyright   Copyright (c) 2008 - 2011, EllisLab, Inc.
10 * @license             http://codeigniter.com/user_guide/license.html
11 * @link                http://codeigniter.com
12 * @since               Version 1.0
13 * @filesource
14 */
15
16// ------------------------------------------------------------------------
17
18/**
19 * CodeIgniter Encryption Class
20 *
21 * Provides two-way keyed encoding using XOR Hashing and Mcrypt
22 *
23 * @package             CodeIgniter
24 * @subpackage  Libraries
25 * @category    Libraries
26 * @author              ExpressionEngine Dev Team
27 * @link                http://codeigniter.com/user_guide/libraries/encryption.html
28 */
29class CI_Encrypt {
30
31        var $CI;
32        var $encryption_key     = '';
33        var $_hash_type = 'sha1';
34        var $_mcrypt_exists = FALSE;
35        var $_mcrypt_cipher;
36        var $_mcrypt_mode;
37
38        /**
39         * Constructor
40         *
41         * Simply determines whether the mcrypt library exists.
42         *
43         */
44        public function __construct()
45        {
46                $this->CI =& get_instance();
47                $this->_mcrypt_exists = ( ! function_exists('mcrypt_encrypt')) ? FALSE : TRUE;
48                log_message('debug', "Encrypt Class Initialized");
49        }
50
51        // --------------------------------------------------------------------
52
53        /**
54         * Fetch the encryption key
55         *
56         * Returns it as MD5 in order to have an exact-length 128 bit key.
57         * Mcrypt is sensitive to keys that are not the correct length
58         *
59         * @access      public
60         * @param       string
61         * @return      string
62         */
63        function get_key($key = '')
64        {
65                if ($key == '')
66                {
67                        if ($this->encryption_key != '')
68                        {
69                                return $this->encryption_key;
70                        }
71
72                        $CI =& get_instance();
73                        $key = $CI->config->item('encryption_key');
74
75                        if ($key == FALSE)
76                        {
77                                show_error('In order to use the encryption class requires that you set an encryption key in your config file.');
78                        }
79                }
80
81                return md5($key);
82        }
83
84        // --------------------------------------------------------------------
85
86        /**
87         * Set the encryption key
88         *
89         * @access      public
90         * @param       string
91         * @return      void
92         */
93        function set_key($key = '')
94        {
95                $this->encryption_key = $key;
96        }
97
98        // --------------------------------------------------------------------
99
100        /**
101         * Encode
102         *
103         * Encodes the message string using bitwise XOR encoding.
104         * The key is combined with a random hash, and then it
105         * too gets converted using XOR. The whole thing is then run
106         * through mcrypt (if supported) using the randomized key.
107         * The end result is a double-encrypted message string
108         * that is randomized with each call to this function,
109         * even if the supplied message and key are the same.
110         *
111         * @access      public
112         * @param       string  the string to encode
113         * @param       string  the key
114         * @return      string
115         */
116        function encode($string, $key = '')
117        {
118                $key = $this->get_key($key);
119
120                if ($this->_mcrypt_exists === TRUE)
121                {
122                        $enc = $this->mcrypt_encode($string, $key);
123                }
124                else
125                {
126                        $enc = $this->_xor_encode($string, $key);
127                }
128
129                return base64_encode($enc);
130        }
131
132        // --------------------------------------------------------------------
133
134        /**
135         * Decode
136         *
137         * Reverses the above process
138         *
139         * @access      public
140         * @param       string
141         * @param       string
142         * @return      string
143         */
144        function decode($string, $key = '')
145        {
146                $key = $this->get_key($key);
147
148                if (preg_match('/[^a-zA-Z0-9\/\+=]/', $string))
149                {
150                        return FALSE;
151                }
152
153                $dec = base64_decode($string);
154
155                if ($this->_mcrypt_exists === TRUE)
156                {
157                        if (($dec = $this->mcrypt_decode($dec, $key)) === FALSE)
158                        {
159                                return FALSE;
160                        }
161                }
162                else
163                {
164                        $dec = $this->_xor_decode($dec, $key);
165                }
166
167                return $dec;
168        }
169
170        // --------------------------------------------------------------------
171
172        /**
173         * Encode from Legacy
174         *
175         * Takes an encoded string from the original Encryption class algorithms and
176         * returns a newly encoded string using the improved method added in 2.0.0
177         * This allows for backwards compatibility and a method to transition to the
178         * new encryption algorithms.
179         *
180         * For more details, see http://codeigniter.com/user_guide/installation/upgrade_200.html#encryption
181         *
182         * @access      public
183         * @param       string
184         * @param       int             (mcrypt mode constant)
185         * @param       string
186         * @return      string
187         */
188        function encode_from_legacy($string, $legacy_mode = MCRYPT_MODE_ECB, $key = '')
189        {
190                if ($this->_mcrypt_exists === FALSE)
191                {
192                        log_message('error', 'Encoding from legacy is available only when Mcrypt is in use.');
193                        return FALSE;
194                }
195
196                // decode it first
197                // set mode temporarily to what it was when string was encoded with the legacy
198                // algorithm - typically MCRYPT_MODE_ECB
199                $current_mode = $this->_get_mode();
200                $this->set_mode($legacy_mode);
201
202                $key = $this->get_key($key);
203
204                if (preg_match('/[^a-zA-Z0-9\/\+=]/', $string))
205                {
206                        return FALSE;
207                }
208
209                $dec = base64_decode($string);
210
211                if (($dec = $this->mcrypt_decode($dec, $key)) === FALSE)
212                {
213                        return FALSE;
214                }
215
216                $dec = $this->_xor_decode($dec, $key);
217
218                // set the mcrypt mode back to what it should be, typically MCRYPT_MODE_CBC
219                $this->set_mode($current_mode);
220
221                // and re-encode
222                return base64_encode($this->mcrypt_encode($dec, $key));
223        }
224
225        // --------------------------------------------------------------------
226
227        /**
228         * XOR Encode
229         *
230         * Takes a plain-text string and key as input and generates an
231         * encoded bit-string using XOR
232         *
233         * @access      private
234         * @param       string
235         * @param       string
236         * @return      string
237         */
238        function _xor_encode($string, $key)
239        {
240                $rand = '';
241                while (strlen($rand) < 32)
242                {
243                        $rand .= mt_rand(0, mt_getrandmax());
244                }
245
246                $rand = $this->hash($rand);
247
248                $enc = '';
249                for ($i = 0; $i < strlen($string); $i++)
250                {
251                        $enc .= substr($rand, ($i % strlen($rand)), 1).(substr($rand, ($i % strlen($rand)), 1) ^ substr($string, $i, 1));
252                }
253
254                return $this->_xor_merge($enc, $key);
255        }
256
257        // --------------------------------------------------------------------
258
259        /**
260         * XOR Decode
261         *
262         * Takes an encoded string and key as input and generates the
263         * plain-text original message
264         *
265         * @access      private
266         * @param       string
267         * @param       string
268         * @return      string
269         */
270        function _xor_decode($string, $key)
271        {
272                $string = $this->_xor_merge($string, $key);
273
274                $dec = '';
275                for ($i = 0; $i < strlen($string); $i++)
276                {
277                        $dec .= (substr($string, $i++, 1) ^ substr($string, $i, 1));
278                }
279
280                return $dec;
281        }
282
283        // --------------------------------------------------------------------
284
285        /**
286         * XOR key + string Combiner
287         *
288         * Takes a string and key as input and computes the difference using XOR
289         *
290         * @access      private
291         * @param       string
292         * @param       string
293         * @return      string
294         */
295        function _xor_merge($string, $key)
296        {
297                $hash = $this->hash($key);
298                $str = '';
299                for ($i = 0; $i < strlen($string); $i++)
300                {
301                        $str .= substr($string, $i, 1) ^ substr($hash, ($i % strlen($hash)), 1);
302                }
303
304                return $str;
305        }
306
307        // --------------------------------------------------------------------
308
309        /**
310         * Encrypt using Mcrypt
311         *
312         * @access      public
313         * @param       string
314         * @param       string
315         * @return      string
316         */
317        function mcrypt_encode($data, $key)
318        {
319                $init_size = mcrypt_get_iv_size($this->_get_cipher(), $this->_get_mode());
320                $init_vect = mcrypt_create_iv($init_size, MCRYPT_RAND);
321                return $this->_add_cipher_noise($init_vect.mcrypt_encrypt($this->_get_cipher(), $key, $data, $this->_get_mode(), $init_vect), $key);
322        }
323
324        // --------------------------------------------------------------------
325
326        /**
327         * Decrypt using Mcrypt
328         *
329         * @access      public
330         * @param       string
331         * @param       string
332         * @return      string
333         */
334        function mcrypt_decode($data, $key)
335        {
336                $data = $this->_remove_cipher_noise($data, $key);
337                $init_size = mcrypt_get_iv_size($this->_get_cipher(), $this->_get_mode());
338
339                if ($init_size > strlen($data))
340                {
341                        return FALSE;
342                }
343
344                $init_vect = substr($data, 0, $init_size);
345                $data = substr($data, $init_size);
346                return rtrim(mcrypt_decrypt($this->_get_cipher(), $key, $data, $this->_get_mode(), $init_vect), "\0");
347        }
348
349        // --------------------------------------------------------------------
350
351        /**
352         * Adds permuted noise to the IV + encrypted data to protect
353         * against Man-in-the-middle attacks on CBC mode ciphers
354         * http://www.ciphersbyritter.com/GLOSSARY.HTM#IV
355         *
356         * Function description
357         *
358         * @access      private
359         * @param       string
360         * @param       string
361         * @return      string
362         */
363        function _add_cipher_noise($data, $key)
364        {
365                $keyhash = $this->hash($key);
366                $keylen = strlen($keyhash);
367                $str = '';
368
369                for ($i = 0, $j = 0, $len = strlen($data); $i < $len; ++$i, ++$j)
370                {
371                        if ($j >= $keylen)
372                        {
373                                $j = 0;
374                        }
375
376                        $str .= chr((ord($data[$i]) + ord($keyhash[$j])) % 256);
377                }
378
379                return $str;
380        }
381
382        // --------------------------------------------------------------------
383
384        /**
385         * Removes permuted noise from the IV + encrypted data, reversing
386         * _add_cipher_noise()
387         *
388         * Function description
389         *
390         * @access      public
391         * @param       type
392         * @return      type
393         */
394        function _remove_cipher_noise($data, $key)
395        {
396                $keyhash = $this->hash($key);
397                $keylen = strlen($keyhash);
398                $str = '';
399
400                for ($i = 0, $j = 0, $len = strlen($data); $i < $len; ++$i, ++$j)
401                {
402                        if ($j >= $keylen)
403                        {
404                                $j = 0;
405                        }
406
407                        $temp = ord($data[$i]) - ord($keyhash[$j]);
408
409                        if ($temp < 0)
410                        {
411                                $temp = $temp + 256;
412                        }
413
414                        $str .= chr($temp);
415                }
416
417                return $str;
418        }
419
420        // --------------------------------------------------------------------
421
422        /**
423         * Set the Mcrypt Cipher
424         *
425         * @access      public
426         * @param       constant
427         * @return      string
428         */
429        function set_cipher($cipher)
430        {
431                $this->_mcrypt_cipher = $cipher;
432        }
433
434        // --------------------------------------------------------------------
435
436        /**
437         * Set the Mcrypt Mode
438         *
439         * @access      public
440         * @param       constant
441         * @return      string
442         */
443        function set_mode($mode)
444        {
445                $this->_mcrypt_mode = $mode;
446        }
447
448        // --------------------------------------------------------------------
449
450        /**
451         * Get Mcrypt cipher Value
452         *
453         * @access      private
454         * @return      string
455         */
456        function _get_cipher()
457        {
458                if ($this->_mcrypt_cipher == '')
459                {
460                        $this->_mcrypt_cipher = MCRYPT_RIJNDAEL_256;
461                }
462
463                return $this->_mcrypt_cipher;
464        }
465
466        // --------------------------------------------------------------------
467
468        /**
469         * Get Mcrypt Mode Value
470         *
471         * @access      private
472         * @return      string
473         */
474        function _get_mode()
475        {
476                if ($this->_mcrypt_mode == '')
477                {
478                        $this->_mcrypt_mode = MCRYPT_MODE_CBC;
479                }
480
481                return $this->_mcrypt_mode;
482        }
483
484        // --------------------------------------------------------------------
485
486        /**
487         * Set the Hash type
488         *
489         * @access      public
490         * @param       string
491         * @return      string
492         */
493        function set_hash($type = 'sha1')
494        {
495                $this->_hash_type = ($type != 'sha1' AND $type != 'md5') ? 'sha1' : $type;
496        }
497
498        // --------------------------------------------------------------------
499
500        /**
501         * Hash encode a string
502         *
503         * @access      public
504         * @param       string
505         * @return      string
506         */
507        function hash($str)
508        {
509                return ($this->_hash_type == 'sha1') ? $this->sha1($str) : md5($str);
510        }
511
512        // --------------------------------------------------------------------
513
514        /**
515         * Generate an SHA1 Hash
516         *
517         * @access      public
518         * @param       string
519         * @return      string
520         */
521        function sha1($str)
522        {
523                if ( ! function_exists('sha1'))
524                {
525                        if ( ! function_exists('mhash'))
526                        {
527                                require_once(BASEPATH.'libraries/Sha1.php');
528                                $SH = new CI_SHA;
529                                return $SH->generate($str);
530                        }
531                        else
532                        {
533                                return bin2hex(mhash(MHASH_SHA1, $str));
534                        }
535                }
536                else
537                {
538                        return sha1($str);
539                }
540        }
541
542}
543
544// END CI_Encrypt class
545
546/* End of file Encrypt.php */
547/* Location: ./system/libraries/Encrypt.php */
Note: See TracBrowser for help on using the repository browser.