Subversion-Projekte lars-tiefland.ci

Revision

Revision 2049 | Revision 2242 | Zur aktuellen Revision | Details | Vergleich mit vorheriger | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
68 lars 1
<?php
2
/**
3
 * CodeIgniter
4
 *
5
 * An open source application development framework for PHP
6
 *
7
 * This content is released under the MIT License (MIT)
8
 *
2049 lars 9
 * Copyright (c) 2014 - 2017, British Columbia Institute of Technology
68 lars 10
 *
11
 * Permission is hereby granted, free of charge, to any person obtaining a copy
12
 * of this software and associated documentation files (the "Software"), to deal
13
 * in the Software without restriction, including without limitation the rights
14
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15
 * copies of the Software, and to permit persons to whom the Software is
16
 * furnished to do so, subject to the following conditions:
17
 *
18
 * The above copyright notice and this permission notice shall be included in
19
 * all copies or substantial portions of the Software.
20
 *
21
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27
 * THE SOFTWARE.
28
 *
29
 * @package	CodeIgniter
30
 * @author	EllisLab Dev Team
31
 * @copyright	Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/)
2049 lars 32
 * @copyright	Copyright (c) 2014 - 2017, British Columbia Institute of Technology (http://bcit.ca/)
68 lars 33
 * @license	http://opensource.org/licenses/MIT	MIT License
34
 * @link	https://codeigniter.com
35
 * @since	Version 1.0.0
36
 * @filesource
37
 */
38
defined('BASEPATH') OR exit('No direct script access allowed');
39
 
40
/**
41
 * CodeIgniter Encryption Class
42
 *
43
 * Provides two-way keyed encoding using Mcrypt
44
 *
45
 * @package		CodeIgniter
46
 * @subpackage	Libraries
47
 * @category	Libraries
48
 * @author		EllisLab Dev Team
49
 * @link		https://codeigniter.com/user_guide/libraries/encryption.html
50
 */
51
class CI_Encrypt {
52
 
53
	/**
54
	 * Reference to the user's encryption key
55
	 *
56
	 * @var string
57
	 */
58
	public $encryption_key		= '';
59
 
60
	/**
61
	 * Type of hash operation
62
	 *
63
	 * @var string
64
	 */
65
	protected $_hash_type		= 'sha1';
66
 
67
	/**
68
	 * Flag for the existence of mcrypt
69
	 *
70
	 * @var bool
71
	 */
72
	protected $_mcrypt_exists	= FALSE;
73
 
74
	/**
75
	 * Current cipher to be used with mcrypt
76
	 *
77
	 * @var string
78
	 */
79
	protected $_mcrypt_cipher;
80
 
81
	/**
82
	 * Method for encrypting/decrypting data
83
	 *
84
	 * @var int
85
	 */
86
	protected $_mcrypt_mode;
87
 
88
	/**
89
	 * Initialize Encryption class
90
	 *
91
	 * @return	void
92
	 */
93
	public function __construct()
94
	{
95
		if (($this->_mcrypt_exists = function_exists('mcrypt_encrypt')) === FALSE)
96
		{
97
			show_error('The Encrypt library requires the Mcrypt extension.');
98
		}
99
 
100
		log_message('info', 'Encrypt Class Initialized');
101
	}
102
 
103
	// --------------------------------------------------------------------
104
 
105
	/**
106
	 * Fetch the encryption key
107
	 *
108
	 * Returns it as MD5 in order to have an exact-length 128 bit key.
109
	 * Mcrypt is sensitive to keys that are not the correct length
110
	 *
111
	 * @param	string
112
	 * @return	string
113
	 */
114
	public function get_key($key = '')
115
	{
116
		if ($key === '')
117
		{
118
			if ($this->encryption_key !== '')
119
			{
120
				return $this->encryption_key;
121
			}
122
 
123
			$key = config_item('encryption_key');
124
 
2107 lars 125
			if ( ! self::strlen($key))
68 lars 126
			{
127
				show_error('In order to use the encryption class requires that you set an encryption key in your config file.');
128
			}
129
		}
130
 
131
		return md5($key);
132
	}
133
 
134
	// --------------------------------------------------------------------
135
 
136
	/**
137
	 * Set the encryption key
138
	 *
139
	 * @param	string
140
	 * @return	CI_Encrypt
141
	 */
142
	public function set_key($key = '')
143
	{
144
		$this->encryption_key = $key;
145
		return $this;
146
	}
147
 
148
	// --------------------------------------------------------------------
149
 
150
	/**
151
	 * Encode
152
	 *
153
	 * Encodes the message string using bitwise XOR encoding.
154
	 * The key is combined with a random hash, and then it
155
	 * too gets converted using XOR. The whole thing is then run
156
	 * through mcrypt using the randomized key. The end result
157
	 * is a double-encrypted message string that is randomized
158
	 * with each call to this function, even if the supplied
159
	 * message and key are the same.
160
	 *
161
	 * @param	string	the string to encode
162
	 * @param	string	the key
163
	 * @return	string
164
	 */
165
	public function encode($string, $key = '')
166
	{
167
		return base64_encode($this->mcrypt_encode($string, $this->get_key($key)));
168
	}
169
 
170
	// --------------------------------------------------------------------
171
 
172
	/**
173
	 * Decode
174
	 *
175
	 * Reverses the above process
176
	 *
177
	 * @param	string
178
	 * @param	string
179
	 * @return	string
180
	 */
181
	public function decode($string, $key = '')
182
	{
183
		if (preg_match('/[^a-zA-Z0-9\/\+=]/', $string) OR base64_encode(base64_decode($string)) !== $string)
184
		{
185
			return FALSE;
186
		}
187
 
188
		return $this->mcrypt_decode(base64_decode($string), $this->get_key($key));
189
	}
190
 
191
	// --------------------------------------------------------------------
192
 
193
	/**
194
	 * Encode from Legacy
195
	 *
196
	 * Takes an encoded string from the original Encryption class algorithms and
197
	 * returns a newly encoded string using the improved method added in 2.0.0
198
	 * This allows for backwards compatibility and a method to transition to the
199
	 * new encryption algorithms.
200
	 *
201
	 * For more details, see https://codeigniter.com/user_guide/installation/upgrade_200.html#encryption
202
	 *
203
	 * @param	string
204
	 * @param	int		(mcrypt mode constant)
205
	 * @param	string
206
	 * @return	string
207
	 */
208
	public function encode_from_legacy($string, $legacy_mode = MCRYPT_MODE_ECB, $key = '')
209
	{
210
		if (preg_match('/[^a-zA-Z0-9\/\+=]/', $string))
211
		{
212
			return FALSE;
213
		}
214
 
215
		// decode it first
216
		// set mode temporarily to what it was when string was encoded with the legacy
217
		// algorithm - typically MCRYPT_MODE_ECB
218
		$current_mode = $this->_get_mode();
219
		$this->set_mode($legacy_mode);
220
 
221
		$key = $this->get_key($key);
222
		$dec = base64_decode($string);
223
		if (($dec = $this->mcrypt_decode($dec, $key)) === FALSE)
224
		{
225
			$this->set_mode($current_mode);
226
			return FALSE;
227
		}
228
 
229
		$dec = $this->_xor_decode($dec, $key);
230
 
231
		// set the mcrypt mode back to what it should be, typically MCRYPT_MODE_CBC
232
		$this->set_mode($current_mode);
233
 
234
		// and re-encode
235
		return base64_encode($this->mcrypt_encode($dec, $key));
236
	}
237
 
238
	// --------------------------------------------------------------------
239
 
240
	/**
241
	 * XOR Decode
242
	 *
243
	 * Takes an encoded string and key as input and generates the
244
	 * plain-text original message
245
	 *
246
	 * @param	string
247
	 * @param	string
248
	 * @return	string
249
	 */
250
	protected function _xor_decode($string, $key)
251
	{
252
		$string = $this->_xor_merge($string, $key);
253
 
254
		$dec = '';
2107 lars 255
		for ($i = 0, $l = self::strlen($string); $i < $l; $i++)
68 lars 256
		{
257
			$dec .= ($string[$i++] ^ $string[$i]);
258
		}
259
 
260
		return $dec;
261
	}
262
 
263
	// --------------------------------------------------------------------
264
 
265
	/**
266
	 * XOR key + string Combiner
267
	 *
268
	 * Takes a string and key as input and computes the difference using XOR
269
	 *
270
	 * @param	string
271
	 * @param	string
272
	 * @return	string
273
	 */
274
	protected function _xor_merge($string, $key)
275
	{
276
		$hash = $this->hash($key);
277
		$str = '';
2107 lars 278
 
279
		for ($i = 0, $ls = self::strlen($string), $lh = self::strlen($hash); $i < $ls; $i++)
68 lars 280
		{
281
			$str .= $string[$i] ^ $hash[($i % $lh)];
282
		}
283
 
284
		return $str;
285
	}
286
 
287
	// --------------------------------------------------------------------
288
 
289
	/**
290
	 * Encrypt using Mcrypt
291
	 *
292
	 * @param	string
293
	 * @param	string
294
	 * @return	string
295
	 */
296
	public function mcrypt_encode($data, $key)
297
	{
298
		$init_size = mcrypt_get_iv_size($this->_get_cipher(), $this->_get_mode());
2107 lars 299
		$init_vect = mcrypt_create_iv($init_size, MCRYPT_DEV_URANDOM);
68 lars 300
		return $this->_add_cipher_noise($init_vect.mcrypt_encrypt($this->_get_cipher(), $key, $data, $this->_get_mode(), $init_vect), $key);
301
	}
302
 
303
	// --------------------------------------------------------------------
304
 
305
	/**
306
	 * Decrypt using Mcrypt
307
	 *
308
	 * @param	string
309
	 * @param	string
310
	 * @return	string
311
	 */
312
	public function mcrypt_decode($data, $key)
313
	{
314
		$data = $this->_remove_cipher_noise($data, $key);
315
		$init_size = mcrypt_get_iv_size($this->_get_cipher(), $this->_get_mode());
316
 
2107 lars 317
		if ($init_size > self::strlen($data))
68 lars 318
		{
319
			return FALSE;
320
		}
321
 
2107 lars 322
		$init_vect = self::substr($data, 0, $init_size);
323
		$data      = self::substr($data, $init_size);
324
 
68 lars 325
		return rtrim(mcrypt_decrypt($this->_get_cipher(), $key, $data, $this->_get_mode(), $init_vect), "\0");
326
	}
327
 
328
	// --------------------------------------------------------------------
329
 
330
	/**
331
	 * Adds permuted noise to the IV + encrypted data to protect
332
	 * against Man-in-the-middle attacks on CBC mode ciphers
333
	 * http://www.ciphersbyritter.com/GLOSSARY.HTM#IV
334
	 *
335
	 * @param	string
336
	 * @param	string
337
	 * @return	string
338
	 */
339
	protected function _add_cipher_noise($data, $key)
340
	{
341
		$key = $this->hash($key);
342
		$str = '';
343
 
2107 lars 344
		for ($i = 0, $j = 0, $ld = self::strlen($data), $lk = self::strlen($key); $i < $ld; ++$i, ++$j)
68 lars 345
		{
346
			if ($j >= $lk)
347
			{
348
				$j = 0;
349
			}
350
 
351
			$str .= chr((ord($data[$i]) + ord($key[$j])) % 256);
352
		}
353
 
354
		return $str;
355
	}
356
 
357
	// --------------------------------------------------------------------
358
 
359
	/**
360
	 * Removes permuted noise from the IV + encrypted data, reversing
361
	 * _add_cipher_noise()
362
	 *
363
	 * Function description
364
	 *
365
	 * @param	string	$data
366
	 * @param	string	$key
367
	 * @return	string
368
	 */
369
	protected function _remove_cipher_noise($data, $key)
370
	{
371
		$key = $this->hash($key);
372
		$str = '';
373
 
2107 lars 374
		for ($i = 0, $j = 0, $ld = self::strlen($data), $lk = self::strlen($key); $i < $ld; ++$i, ++$j)
68 lars 375
		{
376
			if ($j >= $lk)
377
			{
378
				$j = 0;
379
			}
380
 
381
			$temp = ord($data[$i]) - ord($key[$j]);
382
 
383
			if ($temp < 0)
384
			{
385
				$temp += 256;
386
			}
387
 
388
			$str .= chr($temp);
389
		}
390
 
391
		return $str;
392
	}
393
 
394
	// --------------------------------------------------------------------
395
 
396
	/**
397
	 * Set the Mcrypt Cipher
398
	 *
399
	 * @param	int
400
	 * @return	CI_Encrypt
401
	 */
402
	public function set_cipher($cipher)
403
	{
404
		$this->_mcrypt_cipher = $cipher;
405
		return $this;
406
	}
407
 
408
	// --------------------------------------------------------------------
409
 
410
	/**
411
	 * Set the Mcrypt Mode
412
	 *
413
	 * @param	int
414
	 * @return	CI_Encrypt
415
	 */
416
	public function set_mode($mode)
417
	{
418
		$this->_mcrypt_mode = $mode;
419
		return $this;
420
	}
421
 
422
	// --------------------------------------------------------------------
423
 
424
	/**
425
	 * Get Mcrypt cipher Value
426
	 *
427
	 * @return	int
428
	 */
429
	protected function _get_cipher()
430
	{
431
		if ($this->_mcrypt_cipher === NULL)
432
		{
433
			return $this->_mcrypt_cipher = MCRYPT_RIJNDAEL_256;
434
		}
435
 
436
		return $this->_mcrypt_cipher;
437
	}
438
 
439
	// --------------------------------------------------------------------
440
 
441
	/**
442
	 * Get Mcrypt Mode Value
443
	 *
444
	 * @return	int
445
	 */
446
	protected function _get_mode()
447
	{
448
		if ($this->_mcrypt_mode === NULL)
449
		{
450
			return $this->_mcrypt_mode = MCRYPT_MODE_CBC;
451
		}
452
 
453
		return $this->_mcrypt_mode;
454
	}
455
 
456
	// --------------------------------------------------------------------
457
 
458
	/**
459
	 * Set the Hash type
460
	 *
461
	 * @param	string
462
	 * @return	void
463
	 */
464
	public function set_hash($type = 'sha1')
465
	{
466
		$this->_hash_type = in_array($type, hash_algos()) ? $type : 'sha1';
467
	}
468
 
469
	// --------------------------------------------------------------------
470
 
471
	/**
472
	 * Hash encode a string
473
	 *
474
	 * @param	string
475
	 * @return	string
476
	 */
477
	public function hash($str)
478
	{
479
		return hash($this->_hash_type, $str);
480
	}
481
 
2107 lars 482
	// --------------------------------------------------------------------
483
 
484
	/**
485
	 * Byte-safe strlen()
486
	 *
487
	 * @param	string	$str
488
	 * @return	int
489
	 */
490
	protected static function strlen($str)
491
	{
492
		return defined('MB_OVERLOAD_STRING')
493
			? mb_strlen($str, '8bit')
494
			: strlen($str);
495
	}
496
 
497
	// --------------------------------------------------------------------
498
 
499
	/**
500
	 * Byte-safe substr()
501
	 *
502
	 * @param	string	$str
503
	 * @param	int	$start
504
	 * @param	int	$length
505
	 * @return	string
506
	 */
507
	protected static function substr($str, $start, $length = NULL)
508
	{
509
		if (defined('MB_OVERLOAD_STRING'))
510
		{
511
			// mb_substr($str, $start, null, '8bit') returns an empty
512
			// string on PHP 5.3
513
			isset($length) OR $length = ($start >= 0 ? self::strlen($str) - $start : -$start);
514
			return mb_substr($str, $start, $length, '8bit');
515
		}
516
 
517
		return isset($length)
518
			? substr($str, $start, $length)
519
			: substr($str, $start);
520
	}
68 lars 521
}