OSDN Git Service

Add files via upload
authorJoshua Thomas Przyborowski <joshua.przyborowski@gmail.com>
Thu, 14 Dec 2017 00:23:00 +0000 (18:23 -0600)
committerGitHub <noreply@github.com>
Thu, 14 Dec 2017 00:23:00 +0000 (18:23 -0600)
inc/misc/password.php [new file with mode: 0644]

diff --git a/inc/misc/password.php b/inc/misc/password.php
new file mode 100644 (file)
index 0000000..28c8cad
--- /dev/null
@@ -0,0 +1,318 @@
+<?php\r
+/**\r
+ * A Compatibility library with PHP 5.5's simplified password hashing API.\r
+ *\r
+ * @author Anthony Ferrara <ircmaxell@php.net>\r
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License\r
+ * @copyright 2012 The Authors\r
+ */\r
+\r
+namespace {\r
+\r
+    if (!defined('PASSWORD_BCRYPT')) {\r
+        /**\r
+         * PHPUnit Process isolation caches constants, but not function declarations.\r
+         * So we need to check if the constants are defined separately from \r
+         * the functions to enable supporting process isolation in userland\r
+         * code.\r
+         */\r
+        define('PASSWORD_BCRYPT', 1);\r
+        define('PASSWORD_DEFAULT', PASSWORD_BCRYPT);\r
+        define('PASSWORD_BCRYPT_DEFAULT_COST', 10);\r
+    }\r
+\r
+    if (!function_exists('password_hash')) {\r
+\r
+        /**\r
+         * Hash the password using the specified algorithm\r
+         *\r
+         * @param string $password The password to hash\r
+         * @param int    $algo     The algorithm to use (Defined by PASSWORD_* constants)\r
+         * @param array  $options  The options for the algorithm to use\r
+         *\r
+         * @return string|false The hashed password, or false on error.\r
+         */\r
+        function password_hash($password, $algo, array $options = array()) {\r
+            if (!function_exists('crypt')) {\r
+                trigger_error("Crypt must be loaded for password_hash to function", E_USER_WARNING);\r
+                return null;\r
+            }\r
+            if (is_null($password) || is_int($password)) {\r
+                $password = (string) $password;\r
+            }\r
+            if (!is_string($password)) {\r
+                trigger_error("password_hash(): Password must be a string", E_USER_WARNING);\r
+                return null;\r
+            }\r
+            if (!is_int($algo)) {\r
+                trigger_error("password_hash() expects parameter 2 to be long, " . gettype($algo) . " given", E_USER_WARNING);\r
+                return null;\r
+            }\r
+            $resultLength = 0;\r
+            switch ($algo) {\r
+                case PASSWORD_BCRYPT:\r
+                    $cost = PASSWORD_BCRYPT_DEFAULT_COST;\r
+                    if (isset($options['cost'])) {\r
+                        $cost = (int) $options['cost'];\r
+                        if ($cost < 4 || $cost > 31) {\r
+                            trigger_error(sprintf("password_hash(): Invalid bcrypt cost parameter specified: %d", $cost), E_USER_WARNING);\r
+                            return null;\r
+                        }\r
+                    }\r
+                    // The length of salt to generate\r
+                    $raw_salt_len = 16;\r
+                    // The length required in the final serialization\r
+                    $required_salt_len = 22;\r
+                    $hash_format = sprintf("$2y$%02d$", $cost);\r
+                    // The expected length of the final crypt() output\r
+                    $resultLength = 60;\r
+                    break;\r
+                default:\r
+                    trigger_error(sprintf("password_hash(): Unknown password hashing algorithm: %s", $algo), E_USER_WARNING);\r
+                    return null;\r
+            }\r
+            $salt_req_encoding = false;\r
+            if (isset($options['salt'])) {\r
+                switch (gettype($options['salt'])) {\r
+                    case 'NULL':\r
+                    case 'boolean':\r
+                    case 'integer':\r
+                    case 'double':\r
+                    case 'string':\r
+                        $salt = (string) $options['salt'];\r
+                        break;\r
+                    case 'object':\r
+                        if (method_exists($options['salt'], '__tostring')) {\r
+                            $salt = (string) $options['salt'];\r
+                            break;\r
+                        }\r
+                    case 'array':\r
+                    case 'resource':\r
+                    default:\r
+                        trigger_error('password_hash(): Non-string salt parameter supplied', E_USER_WARNING);\r
+                        return null;\r
+                }\r
+                if (PasswordCompat\binary\_strlen($salt) < $required_salt_len) {\r
+                    trigger_error(sprintf("password_hash(): Provided salt is too short: %d expecting %d", PasswordCompat\binary\_strlen($salt), $required_salt_len), E_USER_WARNING);\r
+                    return null;\r
+                } elseif (0 == preg_match('#^[a-zA-Z0-9./]+$#D', $salt)) {\r
+                    $salt_req_encoding = true;\r
+                }\r
+            } else {\r
+                $buffer = '';\r
+                $buffer_valid = false;\r
+                if (function_exists('mcrypt_create_iv') && !defined('PHALANGER')) {\r
+                    $buffer = mcrypt_create_iv($raw_salt_len, MCRYPT_DEV_URANDOM);\r
+                    if ($buffer) {\r
+                        $buffer_valid = true;\r
+                    }\r
+                }\r
+                if (!$buffer_valid && function_exists('openssl_random_pseudo_bytes')) {\r
+                    $strong = false;\r
+                    $buffer = openssl_random_pseudo_bytes($raw_salt_len, $strong);\r
+                    if ($buffer && $strong) {\r
+                        $buffer_valid = true;\r
+                    }\r
+                }\r
+                if (!$buffer_valid && @is_readable('/dev/urandom')) {\r
+                    $file = fopen('/dev/urandom', 'r');\r
+                    $read = 0;\r
+                    $local_buffer = '';\r
+                    while ($read < $raw_salt_len) {\r
+                        $local_buffer .= fread($file, $raw_salt_len - $read);\r
+                        $read = PasswordCompat\binary\_strlen($local_buffer);\r
+                    }\r
+                    fclose($file);\r
+                    if ($read >= $raw_salt_len) {\r
+                        $buffer_valid = true;\r
+                    }\r
+                    $buffer = str_pad($buffer, $raw_salt_len, "\0") ^ str_pad($local_buffer, $raw_salt_len, "\0");\r
+                }\r
+                if (!$buffer_valid || PasswordCompat\binary\_strlen($buffer) < $raw_salt_len) {\r
+                    $buffer_length = PasswordCompat\binary\_strlen($buffer);\r
+                    for ($i = 0; $i < $raw_salt_len; $i++) {\r
+                        if ($i < $buffer_length) {\r
+                            $buffer[$i] = $buffer[$i] ^ chr(mt_rand(0, 255));\r
+                        } else {\r
+                            $buffer .= chr(mt_rand(0, 255));\r
+                        }\r
+                    }\r
+                }\r
+                $salt = $buffer;\r
+                $salt_req_encoding = true;\r
+            }\r
+            if ($salt_req_encoding) {\r
+                // encode string with the Base64 variant used by crypt\r
+                $base64_digits =\r
+                    'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';\r
+                $bcrypt64_digits =\r
+                    './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';\r
+\r
+                $base64_string = base64_encode($salt);\r
+                $salt = strtr(rtrim($base64_string, '='), $base64_digits, $bcrypt64_digits);\r
+            }\r
+            $salt = PasswordCompat\binary\_substr($salt, 0, $required_salt_len);\r
+\r
+            $hash = $hash_format . $salt;\r
+\r
+            $ret = crypt($password, $hash);\r
+\r
+            if (!is_string($ret) || PasswordCompat\binary\_strlen($ret) != $resultLength) {\r
+                return false;\r
+            }\r
+\r
+            return $ret;\r
+        }\r
+\r
+        /**\r
+         * Get information about the password hash. Returns an array of the information\r
+         * that was used to generate the password hash.\r
+         *\r
+         * array(\r
+         *    'algo' => 1,\r
+         *    'algoName' => 'bcrypt',\r
+         *    'options' => array(\r
+         *        'cost' => PASSWORD_BCRYPT_DEFAULT_COST,\r
+         *    ),\r
+         * )\r
+         *\r
+         * @param string $hash The password hash to extract info from\r
+         *\r
+         * @return array The array of information about the hash.\r
+         */\r
+        function password_get_info($hash) {\r
+            $return = array(\r
+                'algo' => 0,\r
+                'algoName' => 'unknown',\r
+                'options' => array(),\r
+            );\r
+            if (PasswordCompat\binary\_substr($hash, 0, 4) == '$2y$' && PasswordCompat\binary\_strlen($hash) == 60) {\r
+                $return['algo'] = PASSWORD_BCRYPT;\r
+                $return['algoName'] = 'bcrypt';\r
+                list($cost) = sscanf($hash, "$2y$%d$");\r
+                $return['options']['cost'] = $cost;\r
+            }\r
+            return $return;\r
+        }\r
+\r
+        /**\r
+         * Determine if the password hash needs to be rehashed according to the options provided\r
+         *\r
+         * If the answer is true, after validating the password using password_verify, rehash it.\r
+         *\r
+         * @param string $hash    The hash to test\r
+         * @param int    $algo    The algorithm used for new password hashes\r
+         * @param array  $options The options array passed to password_hash\r
+         *\r
+         * @return boolean True if the password needs to be rehashed.\r
+         */\r
+        function password_needs_rehash($hash, $algo, array $options = array()) {\r
+            $info = password_get_info($hash);\r
+            if ($info['algo'] !== (int) $algo) {\r
+                return true;\r
+            }\r
+            switch ($algo) {\r
+                case PASSWORD_BCRYPT:\r
+                    $cost = isset($options['cost']) ? (int) $options['cost'] : PASSWORD_BCRYPT_DEFAULT_COST;\r
+                    if ($cost !== $info['options']['cost']) {\r
+                        return true;\r
+                    }\r
+                    break;\r
+            }\r
+            return false;\r
+        }\r
+\r
+        /**\r
+         * Verify a password against a hash using a timing attack resistant approach\r
+         *\r
+         * @param string $password The password to verify\r
+         * @param string $hash     The hash to verify against\r
+         *\r
+         * @return boolean If the password matches the hash\r
+         */\r
+        function password_verify($password, $hash) {\r
+            if (!function_exists('crypt')) {\r
+                trigger_error("Crypt must be loaded for password_verify to function", E_USER_WARNING);\r
+                return false;\r
+            }\r
+            $ret = crypt($password, $hash);\r
+            if (!is_string($ret) || PasswordCompat\binary\_strlen($ret) != PasswordCompat\binary\_strlen($hash) || PasswordCompat\binary\_strlen($ret) <= 13) {\r
+                return false;\r
+            }\r
+\r
+            $status = 0;\r
+            for ($i = 0; $i < PasswordCompat\binary\_strlen($ret); $i++) {\r
+                $status |= (ord($ret[$i]) ^ ord($hash[$i]));\r
+            }\r
+\r
+            return $status === 0;\r
+        }\r
+    }\r
+\r
+}\r
+\r
+namespace PasswordCompat\binary {\r
+\r
+    if (!function_exists('PasswordCompat\\binary\\_strlen')) {\r
+\r
+        /**\r
+         * Count the number of bytes in a string\r
+         *\r
+         * We cannot simply use strlen() for this, because it might be overwritten by the mbstring extension.\r
+         * In this case, strlen() will count the number of *characters* based on the internal encoding. A\r
+         * sequence of bytes might be regarded as a single multibyte character.\r
+         *\r
+         * @param string $binary_string The input string\r
+         *\r
+         * @internal\r
+         * @return int The number of bytes\r
+         */\r
+        function _strlen($binary_string) {\r
+            if (function_exists('mb_strlen')) {\r
+                return mb_strlen($binary_string, '8bit');\r
+            }\r
+            return strlen($binary_string);\r
+        }\r
+\r
+        /**\r
+         * Get a substring based on byte limits\r
+         *\r
+         * @see _strlen()\r
+         *\r
+         * @param string $binary_string The input string\r
+         * @param int    $start\r
+         * @param int    $length\r
+         *\r
+         * @internal\r
+         * @return string The substring\r
+         */\r
+        function _substr($binary_string, $start, $length) {\r
+            if (function_exists('mb_substr')) {\r
+                return mb_substr($binary_string, $start, $length, '8bit');\r
+            }\r
+            return substr($binary_string, $start, $length);\r
+        }\r
+\r
+        /**\r
+         * Check if current PHP version is compatible with the library\r
+         *\r
+         * @return boolean the check result\r
+         */\r
+        function check() {\r
+            static $pass = NULL;\r
+\r
+            if (is_null($pass)) {\r
+                if (function_exists('crypt')) {\r
+                    $hash = '$2y$04$usesomesillystringfore7hnbRJHxXVLeakoG8K30oukPsA.ztMG';\r
+                    $test = crypt("password", $hash);\r
+                    $pass = $test == $hash;\r
+                } else {\r
+                    $pass = false;\r
+                }\r
+            }\r
+            return $pass;\r
+        }\r
+\r
+    }\r
+}\r
+?>
\ No newline at end of file