diff --git a/composer.json b/composer.json index 4661b165..48dec807 100644 --- a/composer.json +++ b/composer.json @@ -36,6 +36,7 @@ "inc/functions.php", "inc/functions/dice.php", "inc/functions/format.php", + "inc/functions/hide.php", "inc/functions/net.php", "inc/functions/num.php", "inc/functions/theme.php", diff --git a/inc/config.php b/inc/config.php index cb6aee95..a1044906 100644 --- a/inc/config.php +++ b/inc/config.php @@ -2101,7 +2101,7 @@ // Password hashing method version // If set to 0, it won't upgrade hashes using old password encryption schema, only create new. // You can set it to a higher value, to further migrate to other password hashing function. - $config['password_crypt_version'] = 1; + $config['password_crypt_version'] = 2; // Use CAPTCHA for reports? $config['report_captcha'] = false; diff --git a/inc/functions.php b/inc/functions.php index 8379fcc2..1787b440 100755 --- a/inc/functions.php +++ b/inc/functions.php @@ -10,6 +10,8 @@ if (realpath($_SERVER['SCRIPT_FILENAME']) == str_replace('\\', '/', __FILE__)) { exit; } +use Vichan\Functions\Hide; + $microtime_start = microtime(true); // the user is not currently logged in as a moderator @@ -1605,8 +1607,9 @@ function checkSpam(array $extra_salt = array()) { // Use SHA1 for the hash $_hash = sha1($_hash . $extra_salt); - if ($hash != $_hash) + if ($hash != $_hash) { return true; + } $query = prepare('SELECT `passed` FROM ``antispam`` WHERE `hash` = :hash'); $query->bindValue(':hash', $hash); @@ -2443,11 +2446,11 @@ function rrmdir($dir) { function poster_id($ip, $thread) { global $config; - if ($id = event('poster-id', $ip, $thread)) + if ($id = event('poster-id', $ip, $thread)) { return $id; + } - // Confusing, hard to brute-force, but simple algorithm - return substr(sha1(sha1($ip . $config['secure_trip_salt'] . $thread) . $config['secure_trip_salt']), 0, $config['poster_id_length']); + return \substr(Hide\secure_hash($ip . $config['secure_trip_salt'] . $thread . $config['secure_trip_salt'], false), 0, $config['poster_id_length']); } function generate_tripcode($name) { @@ -2475,7 +2478,7 @@ function generate_tripcode($name) { if (isset($config['custom_tripcode']["##{$trip}"])) $trip = $config['custom_tripcode']["##{$trip}"]; else - $trip = '!!' . substr(crypt($trip, str_replace('+', '.', '_..A.' . substr(base64_encode(sha1($trip . $config['secure_trip_salt'], true)), 0, 4))), -10); + $trip = '!!' . substr(crypt($trip, str_replace('+', '.', '_..A.' . substr(Hide\secure_hash($trip . $config['secure_trip_salt'], false), 0, 4))), -10); } else { if (isset($config['custom_tripcode']["#{$trip}"])) $trip = $config['custom_tripcode']["#{$trip}"]; diff --git a/inc/functions/hide.php b/inc/functions/hide.php new file mode 100644 index 00000000..bf972751 --- /dev/null +++ b/inc/functions/hide.php @@ -0,0 +1,6 @@ + 12 ]); + if ($r === false) { + throw new \RuntimeException("Could not hash password"); } - return [ $version, hash_equals($password, $comp) ]; + + return [ $version, $r ]; } -function generate_salt(): string { - return strtr(base64_encode(random_bytes(16)), '+', '.'); +function test_password(string $db_hash, string|int $version, string $input_password): bool { + $version = (int)$version; + if ($version < 2) { + $ok = \hash_equals($db_hash, \crypt($input_password, $db_hash)); + } else { + $pre_hash = \hash('tiger160,3', $input_password, false); + $ok = \password_verify($pre_hash, $db_hash); + } + return $ok; } function calc_cookie_name(bool $is_https, bool $is_path_jailed, string $base_name): string { @@ -80,24 +79,24 @@ function calc_cookie_name(bool $is_https, bool $is_path_jailed, string $base_nam } function login(string $username, string $password): array|false { - global $mod, $config; + global $mod; $query = prepare("SELECT `id`, `type`, `boards`, `password`, `version` FROM ``mods`` WHERE BINARY `username` = :username"); $query->bindValue(':username', $username); - $query->execute() or error(db_error($query)); + $query->execute(); if ($user = $query->fetch(PDO::FETCH_ASSOC)) { - list($version, $ok) = test_password($user['password'], $user['version'], $password); + $ok = test_password($user['password'], $user['version'], $password); if ($ok) { - if ($config['password_crypt_version'] > $version) { + if ((int)$user['version'] < 2) { // It's time to upgrade the password hashing method! list ($user['version'], $user['password']) = crypt_password($password); $query = prepare("UPDATE ``mods`` SET `password` = :password, `version` = :version WHERE `id` = :id"); $query->bindValue(':password', $user['password']); $query->bindValue(':version', $user['version']); $query->bindValue(':id', $user['id']); - $query->execute() or error(db_error($query)); + $query->execute(); } return $mod = [