PageRenderTime 48ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/classes/crypt.php

https://github.com/KenjiOhtsuka/core
PHP | 227 lines | 126 code | 35 blank | 66 comment | 12 complexity | 200626a7814262ef07d03e51fb119acd MD5 | raw file
  1. <?php
  2. /**
  3. * Part of the Fuel framework.
  4. *
  5. * @package Fuel
  6. * @version 1.7
  7. * @author Fuel Development Team
  8. * @license MIT License
  9. * @copyright 2010 - 2014 Fuel Development Team
  10. * @link http://fuelphp.com
  11. */
  12. namespace Fuel\Core;
  13. use \PHPSecLib\Crypt_AES;
  14. use \PHPSecLib\Crypt_Hash;
  15. class Crypt
  16. {
  17. /*
  18. * Crypto object used to encrypt/decrypt
  19. *
  20. * @var object
  21. */
  22. private static $crypter = null;
  23. /*
  24. * Hash object used to generate hashes
  25. *
  26. * @var object
  27. */
  28. private static $hasher = null;
  29. /*
  30. * Crypto configuration
  31. *
  32. * @var array
  33. */
  34. private static $config = array();
  35. /*
  36. * initialisation and auto configuration
  37. */
  38. public static function _init()
  39. {
  40. static::$crypter = new Crypt_AES();
  41. static::$hasher = new Crypt_Hash('sha256');
  42. // load the config
  43. \Config::load('crypt', true);
  44. static::$config = \Config::get('crypt', array ());
  45. // generate random crypto keys if we don't have them or they are incorrect length
  46. $update = false;
  47. foreach(array('crypto_key', 'crypto_iv', 'crypto_hmac') as $key)
  48. {
  49. if ( empty(static::$config[$key]) or (strlen(static::$config[$key]) % 4) != 0)
  50. {
  51. $crypto = '';
  52. for ($i = 0; $i < 8; $i++)
  53. {
  54. $crypto .= static::safe_b64encode(pack('n', mt_rand(0, 0xFFFF)));
  55. }
  56. static::$config[$key] = $crypto;
  57. $update = true;
  58. }
  59. }
  60. // update the config if needed
  61. if ($update === true)
  62. {
  63. try
  64. {
  65. \Config::save('crypt', static::$config);
  66. }
  67. catch (\FileAccessException $e)
  68. {
  69. // failed to write the config file, inform the user
  70. echo \View::forge('errors/crypt_keys', array(
  71. 'keys' => static::$config
  72. ));
  73. die();
  74. }
  75. }
  76. static::$crypter->enableContinuousBuffer();
  77. static::$hasher->setKey(static::safe_b64decode(static::$config['crypto_hmac']));
  78. }
  79. // --------------------------------------------------------------------
  80. /*
  81. * encrypt a string value, optionally with a custom key
  82. *
  83. * @param string value to encrypt
  84. * @param string optional custom key to be used for this encryption
  85. * @param int optional key length
  86. * @access public
  87. * @return string encrypted value
  88. */
  89. public static function encode($value, $key = false, $keylength = false)
  90. {
  91. if ( ! $key)
  92. {
  93. $key = static::safe_b64decode(static::$config['crypto_key']);
  94. // Used for backwards compatibility with encrypted data prior
  95. // to FuelPHP 1.7.2, when phpseclib was updated, and became a
  96. // bit smarter about figuring out key lengths.
  97. $keylength = 128;
  98. }
  99. if ($keylength)
  100. {
  101. static::$crypter->setKeyLength($keylength);
  102. }
  103. static::$crypter->setKey($key);
  104. static::$crypter->setIV(static::safe_b64decode(static::$config['crypto_iv']));
  105. $value = static::$crypter->encrypt($value);
  106. return static::safe_b64encode(static::add_hmac($value));
  107. }
  108. // --------------------------------------------------------------------
  109. /*
  110. * decrypt a string value, optionally with a custom key
  111. *
  112. * @param string value to decrypt
  113. * @param string optional custom key to be used for this encryption
  114. * @param int optional key length
  115. * @access public
  116. * @return string encrypted value
  117. */
  118. public static function decode($value, $key = false, $keylength = false)
  119. {
  120. if ( ! $key)
  121. {
  122. $key = static::safe_b64decode(static::$config['crypto_key']);
  123. // Used for backwards compatibility with encrypted data prior
  124. // to FuelPHP 1.7.2, when phpseclib was updated, and became a
  125. // bit smarter about figuring out key lengths.
  126. $keylength = 128;
  127. }
  128. if ($keylength)
  129. {
  130. static::$crypter->setKeyLength($keylength);
  131. }
  132. static::$crypter->setKey($key);
  133. static::$crypter->setIV(static::safe_b64decode(static::$config['crypto_iv']));
  134. $value = static::safe_b64decode($value);
  135. if ($value = static::validate_hmac($value))
  136. {
  137. return static::$crypter->decrypt($value);
  138. }
  139. else
  140. {
  141. return false;
  142. }
  143. }
  144. // --------------------------------------------------------------------
  145. private static function safe_b64encode($value)
  146. {
  147. $data = base64_encode($value);
  148. $data = str_replace(array('+','/','='), array('-','_',''), $data);
  149. return $data;
  150. }
  151. private static function safe_b64decode($value)
  152. {
  153. $data = str_replace(array('-','_'), array('+','/'), $value);
  154. $mod4 = strlen($data) % 4;
  155. if ($mod4)
  156. {
  157. $data .= substr('====', $mod4);
  158. }
  159. return base64_decode($data);
  160. }
  161. private static function add_hmac($value)
  162. {
  163. // calculate the hmac-sha256 hash of this value
  164. $hmac = static::safe_b64encode(static::$hasher->hash($value));
  165. // append it and return the hmac protected string
  166. return $value.$hmac;
  167. }
  168. private static function validate_hmac($value)
  169. {
  170. // strip the hmac-sha256 hash from the value
  171. $hmac = substr($value, strlen($value)-43);
  172. // and remove it from the value
  173. $value = substr($value, 0, strlen($value)-43);
  174. // only return the value if it wasn't tampered with
  175. return (static::secure_compare(static::safe_b64encode(static::$hasher->hash($value)), $hmac)) ? $value : false;
  176. }
  177. private static function secure_compare($a, $b)
  178. {
  179. // make sure we're only comparing equal length strings
  180. if (strlen($a) !== strlen($b))
  181. {
  182. return false;
  183. }
  184. // and that all comparisons take equal time
  185. $result = 0;
  186. for ($i = 0; $i < strlen($a); $i++)
  187. {
  188. $result |= ord($a[$i]) ^ ord($b[$i]);
  189. }
  190. return $result === 0;
  191. }
  192. }