PageRenderTime 46ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/administrator/components/com_jce/helpers/encrypt.php

https://bitbucket.org/taaas/dizi.lh
PHP | 242 lines | 130 code | 36 blank | 76 comment | 32 complexity | 6ac12ef43305160104c28634f5c993e6 MD5 | raw file
Possible License(s): LGPL-2.1, GPL-2.0, GPL-3.0, 0BSD, MIT
  1. <?php
  2. /**
  3. * @copyright Copyright (c)2009-2013 Nicholas K. Dionysopoulos
  4. * @copyright Copyright (c)2014 Ryan Demmer
  5. * @license GNU General Public License version 3, or later
  6. *
  7. * @since 2.4
  8. *
  9. * Modified for JCE by Ryan Demmer
  10. */
  11. // Protection against direct access
  12. defined('_JEXEC') or die();
  13. require_once dirname(dirname(__FILE__)).'/classes/encrypt.php';
  14. /**
  15. * Implements encrypted settings handling features.
  16. */
  17. class WFEncryptHelper
  18. {
  19. /**
  20. * PBKDF2 Implementation for deriving keys.
  21. *
  22. * @param string $p Password
  23. * @param string $s Salt
  24. * @param int $kl Key length
  25. * @param int $c Iteration count
  26. * @param string $a Hash algorithm
  27. *
  28. * @return string The derived key
  29. *
  30. * @see http://en.wikipedia.org/wiki/PBKDF2
  31. * @see http://www.ietf.org/rfc/rfc2898.txt
  32. *
  33. * @copyright Copyright (C) 2005 - 2011 Open Source Matters, Inc. All rights reserved
  34. */
  35. protected static function pbkdf2($p, $s, $kl, $c = 10000, $a = 'sha256')
  36. {
  37. // simple md5 version
  38. if (!function_exists('hash')) {
  39. $seed = $p.$s;
  40. $md5 = md5($seed);
  41. for ($i = 0; $i < $c; ++$i) {
  42. $md5 = md5($md5.md5(rand(0, 2147483647)));
  43. }
  44. return substr($md5, 0, $kl);
  45. }
  46. // Hash length.
  47. $hl = strlen(hash($a, null, true));
  48. // Key blocks to compute.
  49. $kb = ceil($kl / $hl);
  50. // Derived key.
  51. $dk = '';
  52. // Create the key.
  53. for ($block = 1; $block <= $kb; ++$block) {
  54. // Initial hash for this block.
  55. $ib = $b = hash_hmac($a, $s.pack('N', $block), $p, true);
  56. // Perform block iterations.
  57. for ($i = 1; $i < $c; ++$i) {
  58. $ib ^= ($b = hash_hmac($a, $b, $p, true));
  59. }
  60. // Append the iterated block.
  61. $dk .= $ib;
  62. }
  63. // Return derived key of correct length.
  64. return substr($dk, 0, $kl);
  65. }
  66. protected static function generateKey()
  67. {
  68. jimport('joomla.crypt.crypt');
  69. $key = JCrypt::genRandomBytes(32);
  70. $salt = md5_file(JPATH_SITE.'/configuration.php');
  71. $key = base64_encode(self::pbkdf2($key, $salt, 32));
  72. $filecontents = "<?php defined('WF_EDITOR') or die(); define('WF_SERVERKEY', '$key'); ?>";
  73. $filename = JPATH_COMPONENT_ADMINISTRATOR.'/serverkey.php';
  74. $result = JFile::write($filename, $filecontents);
  75. if (!$result) {
  76. return '';
  77. } else {
  78. return base64_decode($key);
  79. }
  80. }
  81. /**
  82. * Gets the configured server key, automatically loading the server key storage file
  83. * if required.
  84. *
  85. * @return string
  86. */
  87. public static function getKey()
  88. {
  89. if (defined('WF_SERVERKEY')) {
  90. return base64_decode(WF_SERVERKEY);
  91. }
  92. $filename = dirname(dirname(__FILE__)).'/serverkey.php';
  93. if (file_exists($filename)) {
  94. include_once $filename;
  95. if (defined('WF_SERVERKEY')) {
  96. return base64_decode(WF_SERVERKEY);
  97. }
  98. } else {
  99. return self::generateKey();
  100. }
  101. }
  102. /**
  103. * Do the server options allow us to use settings encryption?
  104. *
  105. * @return bool
  106. */
  107. public static function supportsEncryption()
  108. {
  109. // Do we have base64_encode/_decode required for encryption?
  110. if (!function_exists('base64_encode') || !function_exists('base64_decode')) {
  111. return false;
  112. }
  113. // Pre-requisites met. We can encrypt and decrypt!
  114. return true;
  115. }
  116. /**
  117. * Gets the preferred encryption mode. Currently, if mcrypt is installed and activated we will
  118. * use AES128.
  119. *
  120. * @return string
  121. */
  122. public static function preferredEncryption()
  123. {
  124. if (function_exists('mcrypt_module_open')) {
  125. return 'AES128';
  126. } else {
  127. return 'CTR128';
  128. }
  129. }
  130. /**
  131. * Encrypts the settings using the automatically detected preferred algorithm.
  132. *
  133. * @param $settingsINI string The raw settings INI string
  134. *
  135. * @return string The encrypted data to store in the database
  136. */
  137. public static function encrypt($data, $key = null)
  138. {
  139. // Do we really support encryption?
  140. if (!self::supportsEncryption()) {
  141. return $data;
  142. }
  143. // Does any of the preferred encryption engines exist?
  144. $encryption = self::preferredEncryption();
  145. if (empty($encryption)) {
  146. return $data;
  147. }
  148. // Do we have a non-empty key to begin with?
  149. if (empty($key)) {
  150. $key = self::getKey();
  151. }
  152. if (empty($key)) {
  153. return $data;
  154. }
  155. if ($encryption == 'AES128') {
  156. $encrypted = WFUtilEncrypt::AESEncryptCBC($data, $key, 128);
  157. if (empty($encrypted)) {
  158. $encryption = 'CTR128';
  159. } else {
  160. // Note: CBC returns the encrypted data as a binary string and requires Base 64 encoding
  161. $data = '###AES128###'.base64_encode($encrypted);
  162. }
  163. }
  164. if ($encryption == 'CTR128') {
  165. $encrypted = WFUtilEncrypt::AESEncryptCtr($settingsINI, $key, 128);
  166. if (empty($encrypted)) {
  167. $encryption = '';
  168. } else {
  169. // Note: CTR returns the encrypted data readily encoded in Base 64
  170. $data = '###CTR128###'.$encrypted;
  171. }
  172. }
  173. return $data;
  174. }
  175. /**
  176. * Decrypts the encrypted settings and returns the plaintext INI string.
  177. *
  178. * @param $encrypted string The encrypted data
  179. *
  180. * @return string The decrypted data
  181. */
  182. public static function decrypt($encrypted, $key = null)
  183. {
  184. if (substr($encrypted, 0, 12) == '###AES128###') {
  185. $mode = 'AES128';
  186. } elseif (substr($encrypted, 0, 12) == '###CTR128###') {
  187. $mode = 'CTR128';
  188. } else {
  189. return $encrypted;
  190. }
  191. if (empty($key)) {
  192. $key = self::getKey();
  193. }
  194. $encrypted = substr($encrypted, 12);
  195. switch ($mode) {
  196. case 'AES128':
  197. $encrypted = base64_decode($encrypted);
  198. $decrypted = WFUtilEncrypt::AESDecryptCBC($encrypted, $key, 128);
  199. break;
  200. case 'CTR128':
  201. $decrypted = WFUtilEncrypt::AESDecryptCtr($encrypted, $key, 128);
  202. break;
  203. }
  204. return rtrim($decrypted, "\0");
  205. }
  206. }