From 92cdd4cc7f6955760236e134126d8a68efa13360 Mon Sep 17 00:00:00 2001 From: Andreas Baumann Date: Wed, 12 Feb 2020 19:21:35 +0100 Subject: hand-picked changes for better password functions from tyzoids branch --- include/functions.php | 91 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 90 insertions(+), 1 deletion(-) (limited to 'include/functions.php') diff --git a/include/functions.php b/include/functions.php index ace2934..8e9265c 100644 --- a/include/functions.php +++ b/include/functions.php @@ -164,7 +164,7 @@ function authenticate_user($user, $password, $password_is_hash = false) $pun_user = $db->fetch_assoc($result); $is_password_authorized = pun_hash_equals($password, $pun_user['password']); - $is_hash_authorized = pun_hash_equals(pun_hash($password), $pun_user['password']); + $is_hash_authorized = pun_password_verify($password, $pun_user['password']); if (!isset($pun_user['id']) || ($password_is_hash && !$is_password_authorized || @@ -1130,6 +1130,95 @@ function validate_redirect($redirect_url, $fallback_url) } +// +// Compute the hash of a password +// using a secure password hashing algorithm, if available +// As of PHP 7.2, this is BLOWFISH. +// This function will fall back to unsecure defaults if +// password_hash does not exist (requires >=PHP5.5) +// +function pun_password_hash($pass) +{ + global $password_hash_cost; + + $cost = $password_hash_cost; + if (empty($cost)) + $cost = 10; + + if (function_exists('password_hash')) + return password_hash($pass, PASSWORD_DEFAULT, array('cost' => $cost)); + else + return pun_hash($pass); +} + + +// +// Verify that $pass and $hash match +// This supports any password hashing algorithm +// used by pun_password_hash +// +function pun_password_verify($pass, $hash) +{ + if (!empty($hash) && $hash[0] !== '$') + return pun_hash_equals(pun_hash($pass), $hash); + else + return password_verify($pass, $hash); +} + +// +// Verify that $pass and $hash match +// This supports any password hashing algorithm +// used by pun_password_hash, but is also +// backwards-compatable with older versions of this software. +// +function pun_password_verify_legacy($pass, $hash, $salt = null) +{ + // MD5 from 1.2 + if (strlen($hash) < 40) + return pun_hash_equals(md5($pass), $hash); + + // SHA1-With-Salt from 1.3 + if (!empty($salt)) + return pun_hash_equals(sha1($salt . sha1($pass)), $hash); + + // SHA1-Without-Salt from 1.4 + if (strlen($hash) == 40) + return pun_hash_equals(sha1($pass), $hash); + + // Support current password standard + return pun_password_verify($pass, $hash); +} + + +// +// Check if $hash is outdated and needs to be rehashed +// +function pun_password_needs_rehash($hash) +{ + global $password_hash_cost; + + // Determine appropriate cost + $cost = $password_hash_cost; + if (empty($cost)) + $cost = 10; + + // Check for legacy md5 hash + if (strlen($hash) < 40) + return true; + + // Check for legacy sha1 hash. Note: legacy sha1 is used + // if password_hash is not available + if (function_exists('password_hash') && strlen($hash) == 40) + return true; + + // Check for out-of-date hash type or cost + if (function_exists('password_needs_rehash')) + return password_needs_rehash($hash, PASSWORD_DEFAULT, array('cost' => $cost)); + + return false; +} + + // // Generate a random password of length $len // Compatibility wrapper for random_key -- cgit v1.2.3-54-g00ecf