From 4873d03d4242fe46edf2fe3eb2df266be95f5c60 Mon Sep 17 00:00:00 2001 From: "Fedor A. Fetisov" Date: Mon, 21 Oct 2013 20:14:42 +0400 Subject: [PATCH] Improve passwords hashing --- src/mibew/libs/operator.php | 64 +++++++++++++++++++++++++++++---- src/mibew/operator/index.php | 2 +- src/mibew/operator/login.php | 2 +- src/mibew/operator/operator.php | 8 ++--- src/mibew/operator/resetpwd.php | 2 +- 5 files changed, 64 insertions(+), 14 deletions(-) diff --git a/src/mibew/libs/operator.php b/src/mibew/libs/operator.php index a61eb694..0f819c5b 100644 --- a/src/mibew/libs/operator.php +++ b/src/mibew/libs/operator.php @@ -264,7 +264,7 @@ function update_operator($operatorid, $login, $email, $password, $localename, $c ':code' => $code ); if ($password) { - $values[':password'] = md5($password); + $values[':password'] = calculate_password_hash($login, $password); } $db->query( "update {chatoperator} set vclogin = :login, " . @@ -311,7 +311,7 @@ function create_operator($login, $email, $password, $localename, $commonname, $a ")", array( ':login' => $login, - ':pass' => md5($password), + ':pass' => calculate_password_hash($login, $password), ':localename' => $localename, ':commonname' => $commonname, ':avatar' => $avatar, @@ -489,9 +489,9 @@ function check_login($redirect = true) { global $mibewroot, $session_prefix; if (!isset($_SESSION[$session_prefix."operator"])) { if (isset($_COOKIE['mibew_operator'])) { - list($login, $pwd) = preg_split("/,/", $_COOKIE['mibew_operator'], 2); + list($login, $pwd) = preg_split('/\x0/', base64_decode($_COOKIE['mibew_operator']), 2); $op = operator_by_login($login); - if ($op && isset($pwd) && isset($op['vcpassword']) && md5($op['vcpassword']) == $pwd && !operator_is_disabled($op)) { + if ($op && isset($pwd) && isset($op['vcpassword']) && calculate_password_hash($op['vclogin'], $op['vcpassword']) == $pwd && !operator_is_disabled($op)) { $_SESSION[$session_prefix."operator"] = $op; return $op; } @@ -524,8 +524,7 @@ function check_login($redirect = true) { function force_password($operator) { global $mibewroot; - if($operator['vcpassword']==md5('')) - { + if (check_password_hash($operator['vclogin'], $operator['vcpassword'], '')) { header("Location: $mibewroot/operator/operator.php?op=1"); exit; } @@ -558,7 +557,7 @@ function login_operator($operator, $remember) { global $mibewroot, $session_prefix; $_SESSION[$session_prefix."operator"] = $operator; if ($remember) { - $value = $operator['vclogin'] . "," . md5($operator['vcpassword']); + $value = base64_encode($operator['vclogin'] . "\x0" . calculate_password_hash($operator['vclogin'], $operator['vcpassword'])); setcookie('mibew_operator', $value, time() + 60 * 60 * 24 * 1000, "$mibewroot/"); } else if (isset($_COOKIE['mibew_operator'])) { @@ -828,4 +827,55 @@ function get_operator_groupids($operatorid) ); } +/** + * Calculate hashed password value based upon operator's login and password + * + * By default function tries to make us of Blowfish encryption algorithm, + * with salted MD5 as a second possible choice, and unsalted MD5 as a fallback + * option + * + * @param string $login operator's login + * @param string $password Operator's password (as plain text) + * + * @return string hashed password value + */ +function calculate_password_hash($login, $password) +{ + $hash = '*0'; + if (CRYPT_BLOWFISH == 1) { + if (defined('PHP_VERSION_ID') && (PHP_VERSION_ID > 50306)) { + $hash = crypt($password, '$2y$08$' . $login); + } + else { + $hash = crypt($password, '$2a$08$' . $login); + } + } + + if ( (CRYPT_MD5 == 1) && !strcmp($hash, '*0') ) { + $hash = crypt($password, '$1$' . $login); + } + + return strcmp($hash, '*0') ? $hash : md5($password); +} + +/** + * Validate incoming hashed value to be the hashed value of operator's password + * + * @param string $login operator's login + * @param string $password Operator's password (as plain text) + * @param string $hash incoming hashed value + * + * @return boolean true if incoming value is the correct hashed value of + * operators' password and false otherwise + */ +function check_password_hash($login, $password, $hash) +{ + if (preg_match('/^\$/', $hash)) { + return !strcmp(calculate_password_hash($login, $password), $hash); + } + else { + return !strcmp(md5($password), $hash); + } +} + ?> \ No newline at end of file diff --git a/src/mibew/operator/index.php b/src/mibew/operator/index.php index 7df53a32..1891c68d 100644 --- a/src/mibew/operator/index.php +++ b/src/mibew/operator/index.php @@ -27,7 +27,7 @@ $page = array( 'version' => $version, 'localeLinks' => get_locale_links("$mibewroot/operator/index.php"), 'needUpdate' => Settings::get('dbversion') != $dbversion, - 'needChangePassword' => $operator['vcpassword'] == md5(''), + 'needChangePassword' => check_password_hash($operator['vclogin'], '', $operator['vcpassword']), 'profilePage' => "$mibewroot/operator/operator.php?op=".$operator['operatorid'], 'updateWizard' => "$mibewroot/install/", 'newFeatures' => Settings::get('featuresversion') != $featuresversion, diff --git a/src/mibew/operator/login.php b/src/mibew/operator/login.php index 71cea1cc..7de017b8 100644 --- a/src/mibew/operator/login.php +++ b/src/mibew/operator/login.php @@ -27,7 +27,7 @@ if (isset($_POST['login']) && isset($_POST['password'])) { $remember = isset($_POST['isRemember']) && $_POST['isRemember'] == "on"; $operator = operator_by_login($login); - if ($operator && isset($operator['vcpassword']) && $operator['vcpassword'] == md5($password) && !operator_is_disabled($operator)) { + if ($operator && isset($operator['vcpassword']) && check_password_hash($operator['vclogin'], $password, $operator['vcpassword']) && !operator_is_disabled($operator)) { $target = $password == '' ? "$mibewroot/operator/operator.php?op=" . $operator['operatorid'] diff --git a/src/mibew/operator/operator.php b/src/mibew/operator/operator.php index e8e8fe77..9af3c892 100644 --- a/src/mibew/operator/operator.php +++ b/src/mibew/operator/operator.php @@ -97,8 +97,8 @@ if ((isset($_POST['login']) || !is_capable(CAN_ADMINISTRATE, $operator)) && isse update_operator($opId, $login, $email, $password, $localname, $commonname, $code); // update the session password if (!empty($password) && $opId == $operator['operatorid']) { - $toDashboard = $operator['vcpassword'] == md5('') && $password != ''; - $_SESSION[$session_prefix."operator"]['vcpassword'] = md5($password); + $toDashboard = check_password_hash($login, '', $operator['vcpassword']) && $password != ''; + $_SESSION[$session_prefix."operator"]['vcpassword'] = calculate_password_hash($login, $password); if($toDashboard) { header("Location: $mibewroot/operator/index.php"); exit; @@ -125,7 +125,7 @@ if ((isset($_POST['login']) || !is_capable(CAN_ADMINISTRATE, $operator)) && isse $page['opid'] = topage($opId); } else { //show an error if the admin password hasn't been set yet. - if ($operator['vcpassword']==md5('') && !isset($_GET['stored'])) + if (check_password_hash($operator['vclogin'], '', $operator['vcpassword']) && !isset($_GET['stored'])) { $errors[] = getlocal("my_settings.error.no_password"); } @@ -149,7 +149,7 @@ $canmodify = ($opId == $operator['operatorid'] && is_capable(CAN_MODIFYPROFILE, $page['stored'] = isset($_GET['stored']); $page['canmodify'] = $canmodify ? "1" : ""; $page['canchangelogin'] = is_capable(CAN_ADMINISTRATE, $operator); -$page['needChangePassword'] = $operator['vcpassword'] == md5(''); +$page['needChangePassword'] = check_password_hash($operator['vclogin'], '', $operator['vcpassword']); prepare_menu($operator); setup_operator_settings_tabs($opId, 0); diff --git a/src/mibew/operator/resetpwd.php b/src/mibew/operator/resetpwd.php index 43158cb6..d03509e4 100644 --- a/src/mibew/operator/resetpwd.php +++ b/src/mibew/operator/resetpwd.php @@ -52,7 +52,7 @@ if (count($errors) == 0 && isset($_POST['password'])) { $db->query( "update {chatoperator} set vcpassword = ?, vcrestoretoken = '' " . "where operatorid = ?", - array(md5($password), $opId) + array(calculate_password_hash($operator['vclogin'], $password), $opId) ); $page['loginname'] = $operator['vclogin'];