DefuseCryptoCore

The WooCommerce Germanized Defuse Crypto Core class.

Defined (1)

The class is defined in the following location(s).

/includes/gateways/direct-debit/libraries/php-encryption/Core.php  
  1. final class Core 
  2. const HEADER_VERSION_SIZE = 4; 
  3. const MINIMUM_CIPHERTEXT_SIZE = 84; 
  4.  
  5. const CURRENT_VERSION = "\xDE\xF5\x02\x00"; 
  6.  
  7. const CIPHER_METHOD = 'aes-256-ctr'; 
  8. const BLOCK_BYTE_SIZE = 16; 
  9. const KEY_BYTE_SIZE = 32; 
  10. const SALT_BYTE_SIZE = 32; 
  11. const MAC_BYTE_SIZE = 32; 
  12. const HASH_FUNCTION_NAME = 'sha256'; 
  13. const ENCRYPTION_INFO_STRING = 'DefusePHP|V2|KeyForEncryption'; 
  14. const AUTHENTICATION_INFO_STRING = 'DefusePHP|V2|KeyForAuthentication'; 
  15. const BUFFER_BYTE_SIZE = 1048576; 
  16.  
  17. const LEGACY_CIPHER_METHOD = 'aes-128-cbc'; 
  18. const LEGACY_BLOCK_BYTE_SIZE = 16; 
  19. const LEGACY_KEY_BYTE_SIZE = 16; 
  20. const LEGACY_HASH_FUNCTION_NAME = 'sha256'; 
  21. const LEGACY_MAC_BYTE_SIZE = 32; 
  22. const LEGACY_ENCRYPTION_INFO_STRING = 'DefusePHP|KeyForEncryption'; 
  23. const LEGACY_AUTHENTICATION_INFO_STRING = 'DefusePHP|KeyForAuthentication'; 
  24.  
  25. /** 
  26. * V2.0 Format: VERSION (4 bytes) || SALT (32 bytes) || IV (16 bytes) || 
  27. * CIPHERTEXT (varies) || HMAC (32 bytes) 
  28. * V1.0 Format: HMAC (32 bytes) || IV (16 bytes) || CIPHERTEXT (varies). 
  29. */ 
  30.  
  31. /** 
  32. * Adds an integer to a block-sized counter. 
  33. * @param string $ctr 
  34. * @param int $inc 
  35. * @throws \Defuse\Crypto\Exception\EnvironmentIsBrokenException 
  36. * @return string 
  37. */ 
  38. public static function incrementCounter($ctr, $inc) 
  39. if (Core::ourStrlen($ctr) !== Core::BLOCK_BYTE_SIZE) { 
  40. throw new Ex\EnvironmentIsBrokenException( 
  41. 'Trying to increment a nonce of the wrong size.' 
  42. ); 
  43.  
  44. if (! \is_int($inc)) { 
  45. throw new Ex\EnvironmentIsBrokenException( 
  46. 'Trying to increment nonce by a non-integer.' 
  47. ); 
  48.  
  49. if ($inc < 0) { 
  50. throw new Ex\EnvironmentIsBrokenException( 
  51. 'Trying to increment nonce by a negative amount.' 
  52. ); 
  53.  
  54. if ($inc > PHP_INT_MAX - 255) { 
  55. throw new Ex\EnvironmentIsBrokenException( 
  56. 'Integer overflow may occur.' 
  57. ); 
  58.  
  59. /** 
  60. * We start at the rightmost byte (big-endian) 
  61. * So, too, does OpenSSL: http://stackoverflow.com/a/3146214/2224584 
  62. */ 
  63. for ($i = Core::BLOCK_BYTE_SIZE - 1; $i >= 0; --$i) { 
  64. $sum = \ord($ctr[$i]) + $inc; 
  65.  
  66. /** Detect integer overflow and fail. */ 
  67. if (! \is_int($sum)) { 
  68. throw new Ex\EnvironmentIsBrokenException( 
  69. 'Integer overflow in CTR mode nonce increment.' 
  70. ); 
  71.  
  72. $ctr[$i] = \pack('C', $sum & 0xFF); 
  73. $inc = $sum >> 8; 
  74. return $ctr; 
  75.  
  76. /** 
  77. * Returns a random byte string of the specified length. 
  78. * @param int $octets 
  79. * @throws Defuse\Crypto\Exception\EnvironmentIsBrokenException 
  80. * @return string 
  81. */ 
  82. public static function secureRandom($octets) 
  83. self::ensureFunctionExists('random_bytes'); 
  84. try { 
  85. return \random_bytes($octets); 
  86. } catch (Exception $ex) { 
  87. throw new Ex\EnvironmentIsBrokenException( 
  88. 'Your system does not have a secure random number generator.' 
  89. ); 
  90.  
  91. /** 
  92. * Computes the HKDF key derivation function specified in 
  93. * http://tools.ietf.org/html/rfc5869. 
  94. * @param string $hash Hash Function 
  95. * @param string $ikm Initial Keying Material 
  96. * @param int $length How many bytes? 
  97. * @param string $info What sort of key are we deriving? 
  98. * @param string $salt 
  99. * @throws Defuse\Crypto\Exception\EnvironmentIsBrokenException 
  100. * @return string 
  101. */ 
  102. public static function HKDF($hash, $ikm, $length, $info = '', $salt = null) 
  103. $digest_length = Core::ourStrlen(\hash_hmac($hash, '', '', true)); 
  104.  
  105. // Sanity-check the desired output length. 
  106. if (empty($length) || ! \is_int($length) || 
  107. $length < 0 || $length > 255 * $digest_length) { 
  108. throw new Ex\EnvironmentIsBrokenException( 
  109. 'Bad output length requested of HKDF.' 
  110. ); 
  111.  
  112. // "if [salt] not provided, is set to a string of HashLen zeroes." 
  113. if (\is_null($salt)) { 
  114. $salt = \str_repeat("\x00", $digest_length); 
  115.  
  116. // HKDF-Extract: 
  117. // PRK = HMAC-Hash(salt, IKM) 
  118. // The salt is the HMAC key. 
  119. $prk = \hash_hmac($hash, $ikm, $salt, true); 
  120.  
  121. // HKDF-Expand: 
  122.  
  123. // This check is useless, but it serves as a reminder to the spec. 
  124. if (Core::ourStrlen($prk) < $digest_length) { 
  125. throw new Ex\EnvironmentIsBrokenException(); 
  126.  
  127. // T(0) = '' 
  128. $t = ''; 
  129. $last_block = ''; 
  130. for ($block_index = 1; Core::ourStrlen($t) < $length; ++$block_index) { 
  131. // T(i) = HMAC-Hash(PRK, T(i-1) | info | 0x??) 
  132. $last_block = \hash_hmac( 
  133. $hash,  
  134. $last_block . $info . \chr($block_index),  
  135. $prk,  
  136. true 
  137. ); 
  138. // T = T(1) | T(2) | T(3) | ... | T(N) 
  139. $t .= $last_block; 
  140.  
  141. // ORM = first L octets of T 
  142. $orm = Core::ourSubstr($t, 0, $length); 
  143. if ($orm === false) { 
  144. throw new Ex\EnvironmentIsBrokenException(); 
  145. return $orm; 
  146.  
  147. /** 
  148. * Checks if two equal-length strings are the same without leaking 
  149. * information through side channels. 
  150. * @param string $expected 
  151. * @param string $given 
  152. * @throws Defuse\Crypto\Exception\EnvironmentIsBrokenException 
  153. * @return bool 
  154. */ 
  155. public static function hashEquals($expected, $given) 
  156. static $native = null; 
  157. if ($native === null) { 
  158. $native = \function_exists('hash_equals'); 
  159. if ($native) { 
  160. return \hash_equals($expected, $given); 
  161.  
  162. // We can't just compare the strings with '==', since it would make 
  163. // timing attacks possible. We could use the XOR-OR constant-time 
  164. // comparison algorithm, but that may not be a reliable defense in an 
  165. // interpreted language. So we use the approach of HMACing both strings 
  166. // with a random key and comparing the HMACs. 
  167.  
  168. // We're not attempting to make variable-length string comparison 
  169. // secure, as that's very difficult. Make sure the strings are the same 
  170. // length. 
  171. if (Core::ourStrlen($expected) !== Core::ourStrlen($given)) { 
  172. throw new Ex\EnvironmentIsBrokenException(); 
  173.  
  174. $blind = Core::secureRandom(32); 
  175. $message_compare = \hash_hmac(Core::HASH_FUNCTION_NAME, $given, $blind); 
  176. $correct_compare = \hash_hmac(Core::HASH_FUNCTION_NAME, $expected, $blind); 
  177. return $correct_compare === $message_compare; 
  178. /** 
  179. * Throws an exception if the constant doesn't exist. 
  180. * @param string $name 
  181. * @throws Defuse\Crypto\Exception\EnvironmentIsBrokenException 
  182. */ 
  183. public static function ensureConstantExists($name) 
  184. if (! \defined($name)) { 
  185. throw new Ex\EnvironmentIsBrokenException(); 
  186.  
  187. /** 
  188. * Throws an exception if the function doesn't exist. 
  189. * @param string $name 
  190. * @throws Defuse\Crypto\Exception\EnvironmentIsBrokenException 
  191. */ 
  192. public static function ensureFunctionExists($name) 
  193. if (! \function_exists($name)) { 
  194. throw new Ex\EnvironmentIsBrokenException(); 
  195.  
  196. /** 
  197. * We need these strlen() and substr() functions because when 
  198. * 'mbstring.func_overload' is set in php.ini, the standard strlen() and 
  199. * substr() are replaced by mb_strlen() and mb_substr(). 
  200. */ 
  201.  
  202. /** 
  203. * Computes the length of a string in bytes. 
  204. * @param string $str 
  205. * @throws Defuse\Crypto\Exception\EnvironmentIsBrokenException 
  206. * @return int 
  207. */ 
  208. public static function ourStrlen($str) 
  209. static $exists = null; 
  210. if ($exists === null) { 
  211. $exists = \function_exists('mb_strlen'); 
  212. if ($exists) { 
  213. $length = \mb_strlen($str, '8bit'); 
  214. if ($length === false) { 
  215. throw new Ex\EnvironmentIsBrokenException(); 
  216. return $length; 
  217. } else { 
  218. return \strlen($str); 
  219.  
  220. /** 
  221. * Behaves roughly like the function substr() in PHP 7 does. 
  222. * @param string $str 
  223. * @param int $start 
  224. * @param int $length 
  225. * @throws Defuse\Crypto\Exception\EnvironmentIsBrokenException 
  226. * @return string 
  227. */ 
  228. public static function ourSubstr($str, $start, $length = null) 
  229. static $exists = null; 
  230. if ($exists === null) { 
  231. $exists = \function_exists('mb_substr'); 
  232.  
  233. if ($exists) { 
  234. // mb_substr($str, 0, NULL, '8bit') returns an empty string on PHP 
  235. // 5.3, so we have to find the length ourselves. 
  236. if (! isset($length)) { 
  237. if ($start >= 0) { 
  238. $length = Core::ourStrlen($str) - $start; 
  239. } else { 
  240. $length = -$start; 
  241.  
  242. // This is required to make mb_substr behavior identical to substr. 
  243. // Without this, mb_substr() would return false, contra to what the 
  244. // PHP documentation says (it doesn't say it can return false.) 
  245. if ($start === Core::ourStrlen($str) && $length === 0) { 
  246. return ''; 
  247.  
  248. if ($start > Core::ourStrlen($str)) { 
  249. return false; 
  250.  
  251. $substr = \mb_substr($str, $start, $length, '8bit'); 
  252. if (Core::ourStrlen($substr) !== $length) { 
  253. throw new EnvironmentIsBrokenException( 
  254. 'Your version of PHP has bug #66797. Its implementation of 
  255. mb_substr() is incorrect. See the details here: 
  256. https://bugs.php.net/bug.php?id=66797' 
  257. ); 
  258. return $substr; 
  259.  
  260. // Unlike mb_substr(), substr() doesn't accept NULL for length 
  261. if (isset($length)) { 
  262. return \substr($str, $start, $length); 
  263. } else { 
  264. return \substr($str, $start); 
  265.  
  266. /** 
  267. * Computes the PBKDF2 password-based key derivation function. 
  268. * The PBKDF2 function is defined in RFC 2898. Test vectors can be found in 
  269. * RFC 6070. This implementation of PBKDF2 was originally created by Taylor 
  270. * Hornby, with improvements from http://www.variations-of-shadow.com/. 
  271. * @param string $algorithm The hash algorithm to use. Recommended: SHA256 
  272. * @param string $password The password. 
  273. * @param string $salt A salt that is unique to the password. 
  274. * @param int $count Iteration count. Higher is better, but slower. Recommended: At least 1000. 
  275. * @param int $key_length The length of the derived key in bytes. 
  276. * @param bool $raw_output If true, the key is returned in raw binary format. Hex encoded otherwise. 
  277. * @throws \Defuse\Crypto\Exception\EnvironmentIsBrokenException 
  278. * @return string A $key_length-byte key derived from the password and salt. 
  279. */ 
  280. public static function pbkdf2($algorithm, $password, $salt, $count, $key_length, $raw_output = false) 
  281. // Type checks: 
  282. if (! \is_string($algorithm)) { 
  283. throw new \InvalidArgumentException( 
  284. 'pbkdf2(): algorithm must be a string' 
  285. ); 
  286. if (! \is_string($password)) { 
  287. throw new \InvalidArgumentException( 
  288. 'pbkdf2(): password must be a string' 
  289. ); 
  290. if (! \is_string($salt)) { 
  291. throw new \InvalidArgumentException( 
  292. 'pbkdf2(): salt must be a string' 
  293. ); 
  294. // Coerce strings to integers with no information loss or overflow 
  295. $count += 0; 
  296. $key_length += 0; 
  297.  
  298. $algorithm = \strtolower($algorithm); 
  299. if (! \in_array($algorithm, \hash_algos(), true)) { 
  300. throw new Ex\EnvironmentIsBrokenException( 
  301. 'Invalid or unsupported hash algorithm.' 
  302. ); 
  303.  
  304. // Whitelist, or we could end up with people using CRC32. 
  305. $ok_algorithms = [ 
  306. 'sha1', 'sha224', 'sha256', 'sha384', 'sha512',  
  307. 'ripemd160', 'ripemd256', 'ripemd320', 'whirlpool',  
  308. ]; 
  309. if (! \in_array($algorithm, $ok_algorithms, true)) { 
  310. throw new Ex\EnvironmentIsBrokenException( 
  311. 'Algorithm is not a secure cryptographic hash function.' 
  312. ); 
  313.  
  314. if ($count <= 0 || $key_length <= 0) { 
  315. throw new Ex\EnvironmentIsBrokenException( 
  316. 'Invalid PBKDF2 parameters.' 
  317. ); 
  318.  
  319. if (\function_exists('hash_pbkdf2')) { 
  320. // The output length is in NIBBLES (4-bits) if $raw_output is false! 
  321. if (! $raw_output) { 
  322. $key_length = $key_length * 2; 
  323. return \hash_pbkdf2($algorithm, $password, $salt, $count, $key_length, $raw_output); 
  324.  
  325. $hash_length = Core::ourStrlen(\hash($algorithm, '', true)); 
  326. $block_count = \ceil($key_length / $hash_length); 
  327.  
  328. $output = ''; 
  329. for ($i = 1; $i <= $block_count; $i++) { 
  330. // $i encoded as 4 bytes, big endian. 
  331. $last = $salt . \pack('N', $i); 
  332. // first iteration 
  333. $last = $xorsum = \hash_hmac($algorithm, $last, $password, true); 
  334. // perform the other $count - 1 iterations 
  335. for ($j = 1; $j < $count; $j++) { 
  336. $xorsum ^= ($last = \hash_hmac($algorithm, $last, $password, true)); 
  337. $output .= $xorsum; 
  338.  
  339. if ($raw_output) { 
  340. return Core::ourSubstr($output, 0, $key_length); 
  341. } else { 
  342. return Encoding::binToHex(Core::ourSubstr($output, 0, $key_length));