Encrypt.php 10 KB

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