PageRenderTime 31ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

/libraries/Encrypt.php

https://bitbucket.org/redmallorca/ci2_system
PHP | 508 lines | 214 code | 77 blank | 217 comment | 30 complexity | df892509d57853d7e01dd293f7148efd MD5 | raw file
  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. * NOTICE OF LICENSE
  8. *
  9. * Licensed under the Open Software License version 3.0
  10. *
  11. * This source file is subject to the Open Software License (OSL 3.0) that is
  12. * bundled with this package in the files license.txt / license.rst. It is
  13. * also available through the world wide web at this URL:
  14. * http://opensource.org/licenses/OSL-3.0
  15. * If you did not receive a copy of the license and are unable to obtain it
  16. * through the world wide web, please send an email to
  17. * licensing@ellislab.com so we can send you a copy immediately.
  18. *
  19. * @package CodeIgniter
  20. * @author EllisLab Dev Team
  21. * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/)
  22. * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
  23. * @link http://codeigniter.com
  24. * @since Version 1.0
  25. * @filesource
  26. */
  27. // ------------------------------------------------------------------------
  28. /**
  29. * CodeIgniter Encryption Class
  30. *
  31. * Provides two-way keyed encoding using XOR Hashing and Mcrypt
  32. *
  33. * @package CodeIgniter
  34. * @subpackage Libraries
  35. * @category Libraries
  36. * @author EllisLab Dev Team
  37. * @link http://codeigniter.com/user_guide/libraries/encryption.html
  38. */
  39. class CI_Encrypt {
  40. public $encryption_key = '';
  41. protected $_hash_type = 'sha1';
  42. protected $_mcrypt_exists = FALSE;
  43. protected $_mcrypt_cipher;
  44. protected $_mcrypt_mode;
  45. /**
  46. * Constructor
  47. *
  48. * Simply determines whether the mcrypt library exists.
  49. */
  50. public function __construct()
  51. {
  52. $this->_mcrypt_exists = ( ! function_exists('mcrypt_encrypt')) ? FALSE : TRUE;
  53. log_message('debug', "Encrypt Class Initialized");
  54. }
  55. // --------------------------------------------------------------------
  56. /**
  57. * Fetch the encryption key
  58. *
  59. * Returns it as MD5 in order to have an exact-length 128 bit key.
  60. * Mcrypt is sensitive to keys that are not the correct length
  61. *
  62. * @param string
  63. * @return string
  64. */
  65. public function get_key($key = '')
  66. {
  67. if ($key == '')
  68. {
  69. if ($this->encryption_key != '')
  70. {
  71. return $this->encryption_key;
  72. }
  73. $CI =& get_instance();
  74. $key = $CI->config->item('encryption_key');
  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. return md5($key);
  81. }
  82. // --------------------------------------------------------------------
  83. /**
  84. * Set the encryption key
  85. *
  86. * @param string
  87. * @return void
  88. */
  89. public function set_key($key = '')
  90. {
  91. $this->encryption_key = $key;
  92. return $this;
  93. }
  94. // --------------------------------------------------------------------
  95. /**
  96. * Encode
  97. *
  98. * Encodes the message string using bitwise XOR encoding.
  99. * The key is combined with a random hash, and then it
  100. * too gets converted using XOR. The whole thing is then run
  101. * through mcrypt (if supported) using the randomized key.
  102. * The end result is a double-encrypted message string
  103. * that is randomized with each call to this function,
  104. * even if the supplied message and key are the same.
  105. *
  106. * @param string the string to encode
  107. * @param string the key
  108. * @return string
  109. */
  110. public function encode($string, $key = '')
  111. {
  112. $key = $this->get_key($key);
  113. if ($this->_mcrypt_exists === TRUE)
  114. {
  115. $enc = $this->mcrypt_encode($string, $key);
  116. }
  117. else
  118. {
  119. $enc = $this->_xor_encode($string, $key);
  120. }
  121. return base64_encode($enc);
  122. }
  123. // --------------------------------------------------------------------
  124. /**
  125. * Decode
  126. *
  127. * Reverses the above process
  128. *
  129. * @param string
  130. * @param string
  131. * @return string
  132. */
  133. public function decode($string, $key = '')
  134. {
  135. $key = $this->get_key($key);
  136. if (preg_match('/[^a-zA-Z0-9\/\+=]/', $string))
  137. {
  138. return FALSE;
  139. }
  140. $dec = base64_decode($string);
  141. if ($this->_mcrypt_exists === TRUE)
  142. {
  143. if (($dec = $this->mcrypt_decode($dec, $key)) === FALSE)
  144. {
  145. return FALSE;
  146. }
  147. }
  148. else
  149. {
  150. $dec = $this->_xor_decode($dec, $key);
  151. }
  152. return $dec;
  153. }
  154. // --------------------------------------------------------------------
  155. /**
  156. * Encode from Legacy
  157. *
  158. * Takes an encoded string from the original Encryption class algorithms and
  159. * returns a newly encoded string using the improved method added in 2.0.0
  160. * This allows for backwards compatibility and a method to transition to the
  161. * new encryption algorithms.
  162. *
  163. * For more details, see http://codeigniter.com/user_guide/installation/upgrade_200.html#encryption
  164. *
  165. * @param string
  166. * @param int (mcrypt mode constant)
  167. * @param string
  168. * @return string
  169. */
  170. public function encode_from_legacy($string, $legacy_mode = MCRYPT_MODE_ECB, $key = '')
  171. {
  172. if ($this->_mcrypt_exists === FALSE)
  173. {
  174. log_message('error', 'Encoding from legacy is available only when Mcrypt is in use.');
  175. return FALSE;
  176. }
  177. // decode it first
  178. // set mode temporarily to what it was when string was encoded with the legacy
  179. // algorithm - typically MCRYPT_MODE_ECB
  180. $current_mode = $this->_get_mode();
  181. $this->set_mode($legacy_mode);
  182. $key = $this->get_key($key);
  183. if (preg_match('/[^a-zA-Z0-9\/\+=]/', $string))
  184. {
  185. return FALSE;
  186. }
  187. $dec = base64_decode($string);
  188. if (($dec = $this->mcrypt_decode($dec, $key)) === FALSE)
  189. {
  190. return FALSE;
  191. }
  192. $dec = $this->_xor_decode($dec, $key);
  193. // set the mcrypt mode back to what it should be, typically MCRYPT_MODE_CBC
  194. $this->set_mode($current_mode);
  195. // and re-encode
  196. return base64_encode($this->mcrypt_encode($dec, $key));
  197. }
  198. // --------------------------------------------------------------------
  199. /**
  200. * XOR Encode
  201. *
  202. * Takes a plain-text string and key as input and generates an
  203. * encoded bit-string using XOR
  204. *
  205. * @param string
  206. * @param string
  207. * @return string
  208. */
  209. protected function _xor_encode($string, $key)
  210. {
  211. $rand = '';
  212. while (strlen($rand) < 32)
  213. {
  214. $rand .= mt_rand(0, mt_getrandmax());
  215. }
  216. $rand = $this->hash($rand);
  217. $enc = '';
  218. for ($i = 0; $i < strlen($string); $i++)
  219. {
  220. $enc .= substr($rand, ($i % strlen($rand)), 1).(substr($rand, ($i % strlen($rand)), 1) ^ substr($string, $i, 1));
  221. }
  222. return $this->_xor_merge($enc, $key);
  223. }
  224. // --------------------------------------------------------------------
  225. /**
  226. * XOR Decode
  227. *
  228. * Takes an encoded string and key as input and generates the
  229. * plain-text original message
  230. *
  231. * @param string
  232. * @param string
  233. * @return string
  234. */
  235. protected function _xor_decode($string, $key)
  236. {
  237. $string = $this->_xor_merge($string, $key);
  238. $dec = '';
  239. for ($i = 0; $i < strlen($string); $i++)
  240. {
  241. $dec .= (substr($string, $i++, 1) ^ substr($string, $i, 1));
  242. }
  243. return $dec;
  244. }
  245. // --------------------------------------------------------------------
  246. /**
  247. * XOR key + string Combiner
  248. *
  249. * Takes a string and key as input and computes the difference using XOR
  250. *
  251. * @param string
  252. * @param string
  253. * @return string
  254. */
  255. protected function _xor_merge($string, $key)
  256. {
  257. $hash = $this->hash($key);
  258. $str = '';
  259. for ($i = 0; $i < strlen($string); $i++)
  260. {
  261. $str .= substr($string, $i, 1) ^ substr($hash, ($i % strlen($hash)), 1);
  262. }
  263. return $str;
  264. }
  265. // --------------------------------------------------------------------
  266. /**
  267. * Encrypt using Mcrypt
  268. *
  269. * @param string
  270. * @param string
  271. * @return string
  272. */
  273. public function mcrypt_encode($data, $key)
  274. {
  275. $init_size = mcrypt_get_iv_size($this->_get_cipher(), $this->_get_mode());
  276. $init_vect = mcrypt_create_iv($init_size, MCRYPT_RAND);
  277. return $this->_add_cipher_noise($init_vect.mcrypt_encrypt($this->_get_cipher(), $key, $data, $this->_get_mode(), $init_vect), $key);
  278. }
  279. // --------------------------------------------------------------------
  280. /**
  281. * Decrypt using Mcrypt
  282. *
  283. * @param string
  284. * @param string
  285. * @return string
  286. */
  287. public function mcrypt_decode($data, $key)
  288. {
  289. $data = $this->_remove_cipher_noise($data, $key);
  290. $init_size = mcrypt_get_iv_size($this->_get_cipher(), $this->_get_mode());
  291. if ($init_size > strlen($data))
  292. {
  293. return FALSE;
  294. }
  295. $init_vect = substr($data, 0, $init_size);
  296. $data = substr($data, $init_size);
  297. return rtrim(mcrypt_decrypt($this->_get_cipher(), $key, $data, $this->_get_mode(), $init_vect), "\0");
  298. }
  299. // --------------------------------------------------------------------
  300. /**
  301. * Adds permuted noise to the IV + encrypted data to protect
  302. * against Man-in-the-middle attacks on CBC mode ciphers
  303. * http://www.ciphersbyritter.com/GLOSSARY.HTM#IV
  304. *
  305. * @param string
  306. * @param string
  307. * @return string
  308. */
  309. protected function _add_cipher_noise($data, $key)
  310. {
  311. $keyhash = $this->hash($key);
  312. $keylen = strlen($keyhash);
  313. $str = '';
  314. for ($i = 0, $j = 0, $len = strlen($data); $i < $len; ++$i, ++$j)
  315. {
  316. if ($j >= $keylen)
  317. {
  318. $j = 0;
  319. }
  320. $str .= chr((ord($data[$i]) + ord($keyhash[$j])) % 256);
  321. }
  322. return $str;
  323. }
  324. // --------------------------------------------------------------------
  325. /**
  326. * Removes permuted noise from the IV + encrypted data, reversing
  327. * _add_cipher_noise()
  328. *
  329. * Function description
  330. *
  331. * @param type
  332. * @return type
  333. */
  334. protected function _remove_cipher_noise($data, $key)
  335. {
  336. $keyhash = $this->hash($key);
  337. $keylen = strlen($keyhash);
  338. $str = '';
  339. for ($i = 0, $j = 0, $len = strlen($data); $i < $len; ++$i, ++$j)
  340. {
  341. if ($j >= $keylen)
  342. {
  343. $j = 0;
  344. }
  345. $temp = ord($data[$i]) - ord($keyhash[$j]);
  346. if ($temp < 0)
  347. {
  348. $temp = $temp + 256;
  349. }
  350. $str .= chr($temp);
  351. }
  352. return $str;
  353. }
  354. // --------------------------------------------------------------------
  355. /**
  356. * Set the Mcrypt Cipher
  357. *
  358. * @param constant
  359. * @return string
  360. */
  361. public function set_cipher($cipher)
  362. {
  363. $this->_mcrypt_cipher = $cipher;
  364. return $this;
  365. }
  366. // --------------------------------------------------------------------
  367. /**
  368. * Set the Mcrypt Mode
  369. *
  370. * @param constant
  371. * @return string
  372. */
  373. function set_mode($mode)
  374. {
  375. $this->_mcrypt_mode = $mode;
  376. return $this;
  377. }
  378. // --------------------------------------------------------------------
  379. /**
  380. * Get Mcrypt cipher Value
  381. *
  382. * @return string
  383. */
  384. protected function _get_cipher()
  385. {
  386. if ($this->_mcrypt_cipher == '')
  387. {
  388. $this->_mcrypt_cipher = MCRYPT_RIJNDAEL_256;
  389. }
  390. return $this->_mcrypt_cipher;
  391. }
  392. // --------------------------------------------------------------------
  393. /**
  394. * Get Mcrypt Mode Value
  395. *
  396. * @return string
  397. */
  398. protected function _get_mode()
  399. {
  400. if ($this->_mcrypt_mode == '')
  401. {
  402. $this->_mcrypt_mode = MCRYPT_MODE_CBC;
  403. }
  404. return $this->_mcrypt_mode;
  405. }
  406. // --------------------------------------------------------------------
  407. /**
  408. * Set the Hash type
  409. *
  410. * @param string
  411. * @return string
  412. */
  413. public function set_hash($type = 'sha1')
  414. {
  415. $this->_hash_type = ($type != 'sha1' AND $type != 'md5') ? 'sha1' : $type;
  416. }
  417. // --------------------------------------------------------------------
  418. /**
  419. * Hash encode a string
  420. *
  421. * @param string
  422. * @return string
  423. */
  424. public function hash($str)
  425. {
  426. return ($this->_hash_type == 'sha1') ? sha1($str) : md5($str);
  427. }
  428. }
  429. // END CI_Encrypt class
  430. /* End of file Encrypt.php */
  431. /* Location: ./system/libraries/Encrypt.php */