MyBB Tutorials

Bcrypt Database Passwords

Submitted by Aforic, , Thread ID: 28305

Thread Closed
Aforic
Novice
Level:
0
Reputation:
0
Posts:
28
Likes:
0
Credits:
0
22-01-2017, 01:15 PM
#1
Their have been no tutorials on this for some reason, but today is the day. Mybb uses MD5 for storing passwords and said they are not going to move to Bcrypt until 2.0. I don't think it's a good decision, if someone gets access you your database, they can easily decrypted the hashes (hashcat) to get passwords. Anyway, once you have finished the tutorial, everything is automatic, your users passwords will be converted on login. This may work for older & newer versions of mybb, but you will have to pick through the code (and not go by line numbers).



Notes
1. You will have to make core edits
2. You will have to re-make core edits after major Mybb updates
3. You need a minimum of PHP 5.5.0
4. If you would rather a plugin, you can useThis


Before you go any further!
MAKE A BACKUP OF YOUR DATABASE AND THE FILES YOU EDIT!
It's better to be safe than sorry.


First thing we want to do is see if you can use Bcrypt.
Open a new text document, Copy & Paste the below into it, save as cost.php, upload to your server and access it in a browser. If you have the minimum PHP version, It will spit out a number after a few seconds. Copy it, we will be using it later, you can then delete cost.php. If you do not have the minimum php version, you will have to update to 5.5.0 (or newer) and re-run cost.php.
PHP Code:
Code:
<?php
/**
*Thiscodewillbenchmarkyourservertodeterminehowhighofacostyoucan
*afford.Youwanttosetthehighestcostthatyoucanwithoutslowingdown
*youservertoomuch.8-10isagoodbaseline,andmoreisgoodifyourservers
*arefastenough.Thecodebelowaimsfor50millisecondsstretchingtime,
*whichisagoodbaselineforsystemshandlinginteractivelogins.
*/
if(PHP_VERSION_ID>=50500){
$timeTarget=0.05;//50milliseconds

$cost=8;
do{
$cost++;
$start=microtime(true);
password_hash("test",PASSWORD_BCRYPT,["cost"=>$cost]);
$end=microtime(true);
}while(($end-$start)<$timeTarget);

echo"AppropriateCostFound:".$cost;
}
else
{
echonl2br("Minimumrequirementnotmet!\nYourPHPversion:".PHP_VERSION."\nPHPversionneeded:5.5.0");
}



Edit: \inc\functions_user.php
Line: 73 - 189
Select the following:
PHP Code:
Code:
/**
*Checksapasswordwithasupplieduid.
*
*@paramint$uidTheuserid.
*@paramstring$passwordTheplain-textpassword.
*@paramarray$userAnoptionaluserdataarray.
*@returnboolean|arrayFalsewhennotvalid,userdataarraywhenvalid.
*/
functionvalidate_password_from_uid($uid,$password,$user=array())
{
global$db,$mybb;
if(isset($mybb->user['uid'])&&$mybb->user['uid']==$uid)
{
$user=$mybb->user;
}
if(!$user['password'])
{
$query=$db->simple_select("users","uid,username,password,salt,loginkey,usergroup","uid='".(int)$uid."'");
$user=$db->fetch_array($query);
}
if(!$user['salt'])
{
//Generateasaltforthisuserandassumethepasswordstoredindbisaplainmd5password
$user['salt']=generate_salt();
$user['password']=salt_password($user['password'],$user['salt']);
$sql_array=array(
"salt"=>$user['salt'],
"password"=>$user['password']
);
$db->update_query("users",$sql_array,"uid='".$user['uid']."'");
}

if(!$user['loginkey'])
{
$user['loginkey']=generate_loginkey();
$sql_array=array(
"loginkey"=>$user['loginkey']
);
$db->update_query("users",$sql_array,"uid=".$user['uid']);
}
if(salt_password(md5($password),$user['salt'])===$user['password'])
{
return$user;
}
else
{
returnfalse;
}
}

/**
*Updatesauser'spassword.
*
*@paramint$uidTheuser'sid.
*@paramstring$passwordThemd5()'edpassword.
*@paramstring$salt(Optional)Thesaltoftheuser.
*@returnarrayThenewpassword.
*/
functionupdate_password($uid,$password,$salt="")
{
global$db,$plugins;

$newpassword=array();

//Ifnosaltwasspecified,checkindatabasefirst,ifstilldoesn'texist,createone
if(!$salt)
{
$query=$db->simple_select("users","salt","uid='$uid'");
$user=$db->fetch_array($query);
if($user['salt'])
{
$salt=$user['salt'];
}
else
{
$salt=generate_salt();
}
$newpassword['salt']=$salt;
}

//Createnewpasswordbasedonsalt
$saltedpw=salt_password($password,$salt);

//Generatenewloginkey
$loginkey=generate_loginkey();

//Updatepasswordandloginkeyindatabase
$newpassword['password']=$saltedpw;
$newpassword['loginkey']=$loginkey;
$db->update_query("users",$newpassword,"uid='$uid'");

$plugins->run_hooks("password_changed");

return$newpassword;
}

/**
*Saltsapasswordbasedonasuppliedsalt.
*
*@paramstring$passwordThemd5()'edpassword.
*@paramstring$saltThesalt.
*@returnstringThepasswordhash.
*/
functionsalt_password($password,$salt)
{
returnmd5(md5($salt).$password);
}

/**
*Generatesarandomsalt
*
*@returnstringThesalt.
*/
functiongenerate_salt()
{
returnrandom_str(8);
}

Replace with:
PHP Code:
Code:
/**
*Checksapasswordwithasupplieduid.
*
*@paramint$uidTheuserid.
*@paramstring$passwordthemd5()'edpassword.
*@paramarray$userAnoptionaluserdataarray.
*@returnboolean|arrayFalsewhennotvalid,userdataarraywhenvalid.
*/
functionvalidate_password_from_uid($uid,$password,$user=array())
{
global$db,$mybb;
if(isset($mybb->user['uid'])&&$mybb->user['uid']==$uid)
{
$user=$mybb->user;
}
if(!$user['password'])
{
$query=$db->simple_select("users","uid,username,password,salt,loginkey,usergroup","uid='".(int)$uid."'");
$user=$db->fetch_array($query);
}
if(!$user['loginkey'])
{
$user['loginkey']=generate_loginkey();
$sql_array=array(
"loginkey"=>$user['loginkey']
);
$db->update_query("users",$sql_array,"uid=".$user['uid']);
}

if(strlen($user['password'])===32)
{
if(!$user['salt'])
{
if($password!==$user['password'])
returnfalse;
}
else
{
if(md5(md5($user['salt']).$password)!==$user['password'])
returnfalse;
}

$user['password']=salt_password($password);

$sql_array=array(
"salt"=>Bcrypt,
"password"=>$user['password']
);
$db->update_query("users",$sql_array,"uid='".$user['uid']."'");

return$user;
}
if(password_verify($password,$user['password'])||password_verify(md5($password),$user['password']))//UserCpdoesnotuseMD5,addMD5topassword_verifyforchangingpassword
{
return$user;
}
else
{
returnfalse;
}
returnfalse;
}

/**
*Updatesauser'spassword.
*
*@paramint$uidTheuser'sid.
*@paramstring$passwordthemd5()'edpassword.
*@paramstring$salt(Optional)Thesaltoftheuser.
*@returnarrayThenewpassword.
*/
functionupdate_password($uid,$password,$salt="")
{
global$db,$plugins;

//Createnewpassword
$user['password']=salt_password($password);

//Generatenewloginkey
$user['loginkey']=generate_loginkey();

$sql_array=array(
"salt"=>Bcrypt,
"password"=>$user['password'],
"loginkey"=>$user['loginkey']
);
$db->update_query("users",$sql_array,"uid='$uid'");

$plugins->run_hooks("password_changed");

return$user;
}

/**
*Bcryptpassword.
*
*@paramstring$passwordthemd5()'edpassword.
*@returnstringThepasswordhash.
*/
functionsalt_password($password)
{
$options=array('cost'=>11);
returnpassword_hash($password,PASSWORD_BCRYPT,$options);
}

/**
*DummyBcryptsalt
*
*@returnstringThesalt.
*/
functiongenerate_salt()
{
return'Bcrypt';
}



Edit: \inc\functions_user.php
Line: 173
Find the following and change the cost (default 11) to what cost.php gave you.
PHP Code:
Code:
$options=array('cost'=>11);



Edit: \inc\datahandlers\login.php
Line: 174 - 206
Select the following:
PHP Code:
Code:
if($strict==true)
{
if(!$this->login_data['salt'])
{
//Generateasaltforthisuserandassumethepasswordstoredindbisaplainmd5password
$this->login_data['salt']=generate_salt();
$this->login_data['password']=salt_password($this->login_data['password'],$this->login_data['salt']);

$sql_array=array(
"salt"=>$this->login_data['salt'],
"password"=>$this->login_data['password']
);

$db->update_query("users",$sql_array,"uid='{$this->login_data['uid']}'");
}

if(!$this->login_data['loginkey'])
{
$this->login_data['loginkey']=generate_loginkey();

$sql_array=array(
"loginkey"=>$this->login_data['loginkey']
);

$db->update_query("users",$sql_array,"uid='{$this->login_data['uid']}'");
}
}

$salted_password=md5(md5($this->login_data['salt']).$password);

$plugins->run_hooks('datahandler_login_verify_password_end',$args);

if($salted_password!==$this->login_data['password'])

Replace with:
PHP Code:
Code:
$plugins->run_hooks('datahandler_login_verify_password_end',$args);

if(validate_password_from_username($this->login_data['username'],$password)===false)

Users browsing this thread: 1 Guest(s)