Advertisement
Guest User

Untitled

a guest
Mar 26th, 2017
56
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 12.66 KB | None | 0 0
  1. <?php
  2. /**
  3. * A Compatibility library with PHP 5.5's simplified password hashing API.
  4. *
  5. * @author Anthony Ferrara <ircmaxell@php.net>
  6. * @license http://www.opensource.org/licenses/mit-license.html MIT License
  7. * @copyright 2012 The Authors
  8. */
  9.  
  10. namespace {
  11.  
  12. if (!defined('PASSWORD_BCRYPT')) {
  13. /**
  14. * PHPUnit Process isolation caches constants, but not function declarations.
  15. * So we need to check if the constants are defined separately from
  16. * the functions to enable supporting process isolation in userland
  17. * code.
  18. */
  19. define('PASSWORD_BCRYPT', 1);
  20. define('PASSWORD_DEFAULT', PASSWORD_BCRYPT);
  21. define('PASSWORD_BCRYPT_DEFAULT_COST', 10);
  22. }
  23.  
  24. if (!function_exists('password_hash')) {
  25.  
  26. /**
  27. * Hash the password using the specified algorithm
  28. *
  29. * @param string $password The password to hash
  30. * @param int $algo The algorithm to use (Defined by PASSWORD_* constants)
  31. * @param array $options The options for the algorithm to use
  32. *
  33. * @return string|false The hashed password, or false on error.
  34. */
  35. function password_hash($password, $algo, array $options = array()) {
  36. if (!function_exists('crypt')) {
  37. trigger_error("Crypt must be loaded for password_hash to function", E_USER_WARNING);
  38. return null;
  39. }
  40. if (is_null($password) || is_int($password)) {
  41. $password = (string) $password;
  42. }
  43. if (!is_string($password)) {
  44. trigger_error("password_hash(): Password must be a string", E_USER_WARNING);
  45. return null;
  46. }
  47. if (!is_int($algo)) {
  48. trigger_error("password_hash() expects parameter 2 to be long, " . gettype($algo) . " given", E_USER_WARNING);
  49. return null;
  50. }
  51. $resultLength = 0;
  52. switch ($algo) {
  53. case PASSWORD_BCRYPT:
  54. $cost = PASSWORD_BCRYPT_DEFAULT_COST;
  55. if (isset($options['cost'])) {
  56. $cost = (int) $options['cost'];
  57. if ($cost < 4 || $cost > 31) {
  58. trigger_error(sprintf("password_hash(): Invalid bcrypt cost parameter specified: %d", $cost), E_USER_WARNING);
  59. return null;
  60. }
  61. }
  62. // The length of salt to generate
  63. $raw_salt_len = 16;
  64. // The length required in the final serialization
  65. $required_salt_len = 22;
  66. $hash_format = sprintf("$2y$%02d$", $cost);
  67. // The expected length of the final crypt() output
  68. $resultLength = 60;
  69. break;
  70. default:
  71. trigger_error(sprintf("password_hash(): Unknown password hashing algorithm: %s", $algo), E_USER_WARNING);
  72. return null;
  73. }
  74. $salt_req_encoding = false;
  75. if (isset($options['salt'])) {
  76. switch (gettype($options['salt'])) {
  77. case 'NULL':
  78. case 'boolean':
  79. case 'integer':
  80. case 'double':
  81. case 'string':
  82. $salt = (string) $options['salt'];
  83. break;
  84. case 'object':
  85. if (method_exists($options['salt'], '__tostring')) {
  86. $salt = (string) $options['salt'];
  87. break;
  88. }
  89. case 'array':
  90. case 'resource':
  91. default:
  92. trigger_error('password_hash(): Non-string salt parameter supplied', E_USER_WARNING);
  93. return null;
  94. }
  95. if (PasswordCompat\binary\_strlen($salt) < $required_salt_len) {
  96. trigger_error(sprintf("password_hash(): Provided salt is too short: %d expecting %d", PasswordCompat\binary\_strlen($salt), $required_salt_len), E_USER_WARNING);
  97. return null;
  98. } elseif (0 == preg_match('#^[a-zA-Z0-9./]+$#D', $salt)) {
  99. $salt_req_encoding = true;
  100. }
  101. } else {
  102. $buffer = '';
  103. $buffer_valid = false;
  104. if (function_exists('mcrypt_create_iv') && !defined('PHALANGER')) {
  105. $buffer = mcrypt_create_iv($raw_salt_len, MCRYPT_DEV_URANDOM);
  106. if ($buffer) {
  107. $buffer_valid = true;
  108. }
  109. }
  110. if (!$buffer_valid && function_exists('openssl_random_pseudo_bytes')) {
  111. $strong = false;
  112. $buffer = openssl_random_pseudo_bytes($raw_salt_len, $strong);
  113. if ($buffer && $strong) {
  114. $buffer_valid = true;
  115. }
  116. }
  117. if (!$buffer_valid && @is_readable('/dev/urandom')) {
  118. $file = fopen('/dev/urandom', 'r');
  119. $read = 0;
  120. $local_buffer = '';
  121. while ($read < $raw_salt_len) {
  122. $local_buffer .= fread($file, $raw_salt_len - $read);
  123. $read = PasswordCompat\binary\_strlen($local_buffer);
  124. }
  125. fclose($file);
  126. if ($read >= $raw_salt_len) {
  127. $buffer_valid = true;
  128. }
  129. $buffer = str_pad($buffer, $raw_salt_len, "\0") ^ str_pad($local_buffer, $raw_salt_len, "\0");
  130. }
  131. if (!$buffer_valid || PasswordCompat\binary\_strlen($buffer) < $raw_salt_len) {
  132. $buffer_length = PasswordCompat\binary\_strlen($buffer);
  133. for ($i = 0; $i < $raw_salt_len; $i++) {
  134. if ($i < $buffer_length) {
  135. $buffer[$i] = $buffer[$i] ^ chr(mt_rand(0, 255));
  136. } else {
  137. $buffer .= chr(mt_rand(0, 255));
  138. }
  139. }
  140. }
  141. $salt = $buffer;
  142. $salt_req_encoding = true;
  143. }
  144. if ($salt_req_encoding) {
  145. // encode string with the Base64 variant used by crypt
  146. $base64_digits =
  147. 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
  148. $bcrypt64_digits =
  149. './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
  150.  
  151. $base64_string = base64_encode($salt);
  152. $salt = strtr(rtrim($base64_string, '='), $base64_digits, $bcrypt64_digits);
  153. }
  154. $salt = PasswordCompat\binary\_substr($salt, 0, $required_salt_len);
  155.  
  156. $hash = $hash_format . $salt;
  157.  
  158. $ret = crypt($password, $hash);
  159.  
  160. if (!is_string($ret) || PasswordCompat\binary\_strlen($ret) != $resultLength) {
  161. return false;
  162. }
  163.  
  164. return $ret;
  165. }
  166.  
  167. /**
  168. * Get information about the password hash. Returns an array of the information
  169. * that was used to generate the password hash.
  170. *
  171. * array(
  172. * 'algo' => 1,
  173. * 'algoName' => 'bcrypt',
  174. * 'options' => array(
  175. * 'cost' => PASSWORD_BCRYPT_DEFAULT_COST,
  176. * ),
  177. * )
  178. *
  179. * @param string $hash The password hash to extract info from
  180. *
  181. * @return array The array of information about the hash.
  182. */
  183. function password_get_info($hash) {
  184. $return = array(
  185. 'algo' => 0,
  186. 'algoName' => 'unknown',
  187. 'options' => array(),
  188. );
  189. if (PasswordCompat\binary\_substr($hash, 0, 4) == '$2y$' && PasswordCompat\binary\_strlen($hash) == 60) {
  190. $return['algo'] = PASSWORD_BCRYPT;
  191. $return['algoName'] = 'bcrypt';
  192. list($cost) = sscanf($hash, "$2y$%d$");
  193. $return['options']['cost'] = $cost;
  194. }
  195. return $return;
  196. }
  197.  
  198. /**
  199. * Determine if the password hash needs to be rehashed according to the options provided
  200. *
  201. * If the answer is true, after validating the password using password_verify, rehash it.
  202. *
  203. * @param string $hash The hash to test
  204. * @param int $algo The algorithm used for new password hashes
  205. * @param array $options The options array passed to password_hash
  206. *
  207. * @return boolean True if the password needs to be rehashed.
  208. */
  209. function password_needs_rehash($hash, $algo, array $options = array()) {
  210. $info = password_get_info($hash);
  211. if ($info['algo'] !== (int) $algo) {
  212. return true;
  213. }
  214. switch ($algo) {
  215. case PASSWORD_BCRYPT:
  216. $cost = isset($options['cost']) ? (int) $options['cost'] : PASSWORD_BCRYPT_DEFAULT_COST;
  217. if ($cost !== $info['options']['cost']) {
  218. return true;
  219. }
  220. break;
  221. }
  222. return false;
  223. }
  224.  
  225. /**
  226. * Verify a password against a hash using a timing attack resistant approach
  227. *
  228. * @param string $password The password to verify
  229. * @param string $hash The hash to verify against
  230. *
  231. * @return boolean If the password matches the hash
  232. */
  233. function password_verify($password, $hash) {
  234. if (!function_exists('crypt')) {
  235. trigger_error("Crypt must be loaded for password_verify to function", E_USER_WARNING);
  236. return false;
  237. }
  238. $ret = crypt($password, $hash);
  239. if (!is_string($ret) || PasswordCompat\binary\_strlen($ret) != PasswordCompat\binary\_strlen($hash) || PasswordCompat\binary\_strlen($ret) <= 13) {
  240. return false;
  241. }
  242.  
  243. $status = 0;
  244. for ($i = 0; $i < PasswordCompat\binary\_strlen($ret); $i++) {
  245. $status |= (ord($ret[$i]) ^ ord($hash[$i]));
  246. }
  247.  
  248. return $status === 0;
  249. }
  250. }
  251.  
  252. }
  253.  
  254. namespace PasswordCompat\binary {
  255.  
  256. if (!function_exists('PasswordCompat\\binary\\_strlen')) {
  257.  
  258. /**
  259. * Count the number of bytes in a string
  260. *
  261. * We cannot simply use strlen() for this, because it might be overwritten by the mbstring extension.
  262. * In this case, strlen() will count the number of *characters* based on the internal encoding. A
  263. * sequence of bytes might be regarded as a single multibyte character.
  264. *
  265. * @param string $binary_string The input string
  266. *
  267. * @internal
  268. * @return int The number of bytes
  269. */
  270. function _strlen($binary_string) {
  271. if (function_exists('mb_strlen')) {
  272. return mb_strlen($binary_string, '8bit');
  273. }
  274. return strlen($binary_string);
  275. }
  276.  
  277. /**
  278. * Get a substring based on byte limits
  279. *
  280. * @see _strlen()
  281. *
  282. * @param string $binary_string The input string
  283. * @param int $start
  284. * @param int $length
  285. *
  286. * @internal
  287. * @return string The substring
  288. */
  289. function _substr($binary_string, $start, $length) {
  290. if (function_exists('mb_substr')) {
  291. return mb_substr($binary_string, $start, $length, '8bit');
  292. }
  293. return substr($binary_string, $start, $length);
  294. }
  295.  
  296. /**
  297. * Check if current PHP version is compatible with the library
  298. *
  299. * @return boolean the check result
  300. */
  301. function check() {
  302. static $pass = NULL;
  303.  
  304. if (is_null($pass)) {
  305. if (function_exists('crypt')) {
  306. $hash = '$2y$04$usesomesillystringfore7hnbRJHxXVLeakoG8K30oukPsA.ztMG';
  307. $test = crypt("password", $hash);
  308. $pass = $test == $hash;
  309. } else {
  310. $pass = false;
  311. }
  312. }
  313. return $pass;
  314. }
  315.  
  316. }
  317. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement