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