diff --git a/classes/config.template b/classes/config.template index 4de33e2f..0ccb2280 100644 --- a/classes/config.template +++ b/classes/config.template @@ -54,6 +54,7 @@ if (!empty($_SERVER['SERVER_PORT']) && $_SERVER['SERVER_PORT'] == 80) { } // Site settings +define('CRYPT_HASH_PREFIX', '$2y$07$'); // Crypt salt prefix for hash settings. See http://php.net/crypt for details define('DEBUG_MODE', false); //Set to false if you dont want everyone to see debug information, can be overriden with 'site_debug' define('OPEN_REGISTRATION', true); //Set to false to disable open regirstration, true to allow anyone to register define('USER_LIMIT', 5000); //The maximum number of users the site can have, 0 for no limit diff --git a/classes/script_start.php b/classes/script_start.php index 20d15e73..3f74607c 100644 --- a/classes/script_start.php +++ b/classes/script_start.php @@ -16,7 +16,7 @@ if(isset($_REQUEST['info_hash']) && isset($_REQUEST['peer_id'])) { die('d14:failure reason40:Invalid .torrent, try downloading again.e'); } require(SERVER_ROOT.'/classes/class_proxies.php'); -if (!empty($_SERVER['HTTP_X_FORWARDED_FOR']) && proxyCheck($_SERVER['REMOTE_ADDR'])) { +if (!empty($_SERVER['HTTP_X_FORWARDED_FOR']) && proxyCheck($_SERVER['REMOTE_ADDR']) && filter_var($_SERVER['HTTP_X_FORWARDED_FOR'], FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) { $_SERVER['REMOTE_ADDR'] = $_SERVER['HTTP_X_FORWARDED_FOR']; } @@ -1185,11 +1185,87 @@ function make_secret($Length = 32) { } */ -// Password hashes, feel free to make your own algorithm here +/** + * Create a password hash. This method is deprecated and + * should not be used to create new passwords + * + * @param $Str password + * @param $Secret salt + * @return password hash + */ function make_hash($Str,$Secret) { return sha1(md5($Secret).$Str.sha1($Secret).SITE_SALT); } +/** + * Verify a password against a password hash + * + * @param $Password password + * @param $Hash password hash + * @param $Secret salt - Only used if the hash was created + * with the deprecated make_hash() method + * @return true on correct password + */ +function check_password($Password, $Hash, $Secret='') { + if(!$Password || !$Hash) { + return false; + } + if(is_crypt_hash($Hash)) { + return crypt($Password, $Hash) == $Hash; + } elseif($Secret) { + return make_hash($Password, $Secret) == $Hash; + } + return false; +} + +/** + * Test if a given hash is a crypt hash + * + * @param $Hash password hash + * @return true if hash is a crypt hash + */ +function is_crypt_hash($Hash) { + return preg_match('/\$\d[axy]?\$/', substr($Hash, 0, 4)); +} + +/** + * Create salted crypt hash for a given string with + * settings specified in CRYPT_HASH_PREFIX + * + * @param $Str string to hash + * @return salted crypt hash + */ +function make_crypt_hash($Str) { + $Salt = CRYPT_HASH_PREFIX.gen_crypt_salt().'$'; + return crypt($Str, $Salt); +} + +/** + * Create salt string for eksblowfish hashing. If /dev/urandom cannot be read, + * fall back to an unsecure method based on mt_rand(). The last character needs + * a special case as it must be either '.', 'O', 'e', or 'u'. + * + * @return salt suitable for eksblowfish hashing + */ +function gen_crypt_salt() { + $Salt = ''; + $Chars = "./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + $Numchars = strlen($Chars) - 1; + if($Handle = @fopen('/dev/urandom', 'r')) { + $Bytes = fread($Handle, 22); + for($i = 0; $i < 21; $i++) { + $Salt .= $Chars[ord($Bytes[$i]) & $Numchars]; + } + $Salt[$i] = $Chars[(ord($Bytes[$i]) & 3) << 4]; + } else { + for($i = 0; $i < 21; $i++) { + $Salt .= $Chars[mt_rand(0, $Numchars)]; + } + $Salt[$i] = $Chars[mt_rand(0, 3) << 4]; + } + return $Salt; +} + /* Returns a username string for display $Class and $Title can be omitted for an abbreviated version diff --git a/sections/login/index.php b/sections/login/index.php index 728d31f4..fe8cd39b 100644 --- a/sections/login/index.php +++ b/sections/login/index.php @@ -53,12 +53,10 @@ $Err=$Validate->ValidateForm($_REQUEST); if ($Err=='') { // Form validates without error, set new secret and password. - $Secret=make_secret(); $DB->query("UPDATE users_main AS m, users_info AS i - SET m.PassHash='".db_string(make_hash($_REQUEST['password'],$Secret))."', - m.Secret='".db_string($Secret)."', + SET m.PassHash='".db_string(make_crypt_hash($_REQUEST['password']))."', i.ResetKey='', i.ResetExpires='0000-00-00 00:00:00' WHERE m.ID='".db_string($UserID)."' @@ -237,7 +235,11 @@ function log_attempt($UserID) { AND Username<>''"); list($UserID,$PermissionID,$CustomPermissions,$PassHash,$Secret,$Enabled)=$DB->next_record(MYSQLI_NUM, array(2)); if (strtotime($BannedUntil)query("UPDATE users_main SET passhash = '".db_string($CryptHash)."' WHERE ID = $UserID"); + } if ($Enabled == 1) { $SessionID = make_secret(); $Cookie = $Enc->encrypt($Enc->encrypt($SessionID.'|~|'.$UserID)); diff --git a/sections/register/index.php b/sections/register/index.php index 5e0300f5..4e654e42 100644 --- a/sections/register/index.php +++ b/sections/register/index.php @@ -66,7 +66,6 @@ } if(!$Err) { - $Secret=make_secret(); $torrent_pass=make_secret(); //Previously SELECT COUNT(ID) FROM users_main, which is a lot slower. @@ -86,8 +85,8 @@ $DB->query("INSERT INTO users_main - (Username,Email,PassHash,Secret,torrent_pass,IP,PermissionID,Enabled,Invites,Uploaded,ipcc) VALUES - ('".db_string(trim($_POST['username']))."','".db_string($_POST['email'])."','".db_string(make_hash($_POST['password'],$Secret))."','".db_string($Secret)."','".db_string($torrent_pass)."','".db_string($_SERVER['REMOTE_ADDR'])."','".$Class."','".$Enabled."','".STARTING_INVITES."', '524288000', '$ipcc')"); + (Username,Email,PassHash,torrent_pass,IP,PermissionID,Enabled,Invites,Uploaded,ipcc) VALUES + ('".db_string(trim($_POST['username']))."','".db_string($_POST['email'])."','".db_string(make_crypt_hash($_POST['password']))."','".db_string($torrent_pass)."','".db_string($_SERVER['REMOTE_ADDR'])."','".$Class."','".$Enabled."','".STARTING_INVITES."', '524288000', '$ipcc')"); $UserID = $DB->inserted_id(); diff --git a/sections/tools/misc/create_user.php b/sections/tools/misc/create_user.php index e95b5530..c21e4225 100644 --- a/sections/tools/misc/create_user.php +++ b/sections/tools/misc/create_user.php @@ -22,7 +22,7 @@ $torrent_pass=make_secret(); //Create the account - $DB->query("INSERT INTO users_main (Username,Email,PassHash,Secret,torrent_pass,Enabled,PermissionID, Language) VALUES ('".db_string($Username)."','".db_string($Email)."','".db_string(make_hash($Password, $Secret))."','".db_string($Secret)."','".db_string($torrent_pass)."','1','".USER."', 'en')"); + $DB->query("INSERT INTO users_main (Username,Email,PassHash,torrent_pass,Enabled,PermissionID, Language) VALUES ('".db_string($Username)."','".db_string($Email)."','".db_string(make_crypt_hash($Password))."','".db_string($torrent_pass)."','1','".USER."', 'en')"); //Increment site user count $Cache->increment('stats_user_count'); @@ -102,4 +102,4 @@ \ No newline at end of file +show_footer(); ?> diff --git a/sections/user/takeedit.php b/sections/user/takeedit.php index 872fe1e0..070d88f4 100644 --- a/sections/user/takeedit.php +++ b/sections/user/takeedit.php @@ -130,7 +130,7 @@ if(!check_perms('users_edit_profiles')) { // Non-admins have to authenticate to change email $DB->query("SELECT PassHash,Secret FROM users_main WHERE ID='".db_string($UserID)."'"); list($PassHash,$Secret)=$DB->next_record(); - if ($PassHash!=make_hash($_POST['cur_pass'],$Secret)) { + if(!check_password($_POST['cur_pass'], $PassHash, $Secret)) { $Err = "You did not enter the correct password."; } } @@ -159,7 +159,7 @@ $DB->query("SELECT PassHash,Secret FROM users_main WHERE ID='".db_string($UserID)."'"); list($PassHash,$Secret)=$DB->next_record(); - if ($PassHash == make_hash($_POST['cur_pass'],$Secret)) { + if (check_password($_POST['cur_pass'], $PassHash, $Secret)) { if ($_POST['new_pass_1'] && $_POST['new_pass_2']) { $ResetPassword = true; } @@ -258,9 +258,8 @@ if($ResetPassword) { $ChangerIP = db_string($LoggedUser['IP']); - $Secret=make_secret(); - $PassHash=make_hash($_POST['new_pass_1'],$Secret); - $SQL.=",m.Secret='".db_string($Secret)."',m.PassHash='".db_string($PassHash)."'"; + $PassHash=make_crypt_hash($_POST['new_pass_1']); + $SQL.=",m.PassHash='".db_string($PassHash)."'"; $DB->query("INSERT INTO users_history_passwords (UserID, ChangerIP, ChangeTime) VALUES ('$UserID', '$ChangerIP', '".sqltime()."')"); diff --git a/sections/user/takemoderate.php b/sections/user/takemoderate.php index 813f2278..414f7643 100644 --- a/sections/user/takemoderate.php +++ b/sections/user/takemoderate.php @@ -32,7 +32,7 @@ $Visible = (isset($_POST['Visible']))? 1 : 0; $Invites = (int)$_POST['Invites']; $SupportFor = db_string($_POST['SupportFor']); -$Pass = db_string($_POST['ChangePassword']); +$Pass = $_POST['ChangePassword']; $Warned = (isset($_POST['Warned']))? 1 : 0; $Logs095 = (int)$_POST['095logs']; if(isset($_POST['Uploaded']) && isset($_POST['Downloaded'])) { @@ -624,9 +624,7 @@ } if ($Pass && check_perms('users_edit_password')) { - $Secret=make_secret(); - $UpdateSet[]="Secret='$Secret'"; - $UpdateSet[]="PassHash='".db_string(make_hash($Pass,$Secret))."'"; + $UpdateSet[]="PassHash='".db_string(make_crypt_hash($Pass))."'"; $EditSummary[]='password reset'; $Cache->delete_value('user_info_'.$UserID);