Feofilaktt wrote:Miki wrote:But it's better to change md5 to pvpgn_hash::get_hash in wordpress
Hi @Miki,
I am interested in getting this merger between DB PvPGN -> DB Website(Phpbb)..
But I just wanted to logged in to the site with the user/password of PvPGN(xsha1).
In case the site would be disabled for account register and would only take the DB PvPGN data for Login.
(Account register PvPGN only)
It would be possible? It seems to be simple, as I just want to change the Authentication/Login on the Site to xsha1, but I do not know how to do it...
I use version phpbb 3.2.2
Add xsha1, open file phpbb/passwords/manager.php and after the function check_combined_hash on line 406 add this code
/**
* Check supplied password against hash and set convert_flag if password
* needs to be converted to different format (preferrably newer one)
*
* @param string $password Password that should be checked
* @param string $hash Stored hash
* @param array $user_row User's row in users table
* @return string|bool True if password is correct, false if not
*/
public function check($password, $hash, $user_row = array())
{
if (strlen($password) > 4096)
{
// If the password is too huge, we will simply reject it
// and not let the server try to hash it.
return false;
}
// Empty hashes can't be checked
if (empty($hash))
{
return false;
}
$this->initialize();
// First find out what kind of hash we're dealing with
$stored_hash_type = $this->detect_algorithm($hash);
if ($stored_hash_type == false)
{
// Still check MD5 hashes as that is what the installer
// will default to for the admin user
return $this->get_algorithm('$H$')->check($password, $hash);
}
// Multiple hash passes needed
if (is_array($stored_hash_type))
{
$correct = $this->check_combined_hash($password, $stored_hash_type, $hash);
$this->convert_flag = ($correct === true) ? true : false;
return $correct;
}
if ($stored_hash_type->get_prefix() !== $this->type)
{
$this->convert_flag = true;
}
else
{
if ($stored_hash_type instanceof driver\rehashable_driver_interface)
{
$this->convert_flag = $stored_hash_type->needs_rehash($hash);
}
else
{
$this->convert_flag = false;
}
}
// Check all legacy hash types if prefix is $CP$
if ($stored_hash_type->get_prefix() === '$CP$')
{
// Remove $CP$ prefix for proper checking
$hash = substr($hash, 4);
foreach ($this->type_map as $algorithm)
{
if ($algorithm->is_legacy() && $algorithm->check($password, $hash, $user_row) === true)
{
return true;
}
}
}
return $stored_hash_type->check($password, $hash);
}
/**
* Create combined hash from already hashed password
*
* @param string $password_hash Complete current password hash
* @param string $type Type of the hashing algorithm the password hash
* should be combined with
* @return string|bool Combined password hash if combined hashing was
* successful, else false
*/
public function combined_hash_password($password_hash, $type)
{
$this->initialize();
$data = array(
'prefix' => '$',
'settings' => '$',
);
$hash_settings = $this->helper->get_combined_hash_settings($password_hash);
$hash = $hash_settings[0];
// Put settings of current hash into data array
$stored_hash_type = $this->detect_algorithm($password_hash);
$this->helper->combine_hash_output($data, 'prefix', $stored_hash_type->get_prefix());
$this->helper->combine_hash_output($data, 'settings', $stored_hash_type->get_settings_only($password_hash));
// Hash current hash with the defined types
foreach ($type as $cur_type)
{
if (isset($this->algorithms[$cur_type]))
{
$new_hash_type = $this->algorithms[$cur_type];
}
else
{
$new_hash_type = $this->get_algorithm($cur_type);
}
if (!$new_hash_type)
{
return false;
}
$new_hash = $new_hash_type->hash(str_replace($stored_hash_type->get_settings_only($password_hash), '', $hash));
$this->helper->combine_hash_output($data, 'prefix', $new_hash_type->get_prefix());
$this->helper->combine_hash_output($data, 'settings', substr(str_replace('$', '\\', $new_hash_type->get_settings_only($new_hash, true)), 0));
$hash = str_replace($new_hash_type->get_settings_only($new_hash), '', $this->helper->obtain_hash_only($new_hash));
}
return $this->helper->combine_hash_output($data, 'hash', $hash);
}
/**
* Check combined password hash against the supplied password
*
* @param string $password Password entered by user
* @param array $stored_hash_type An array containing the hash types
* as described by stored password hash
* @param string $hash Stored password hash
*
* @return bool True if password is correct, false if not
*/
public function check_combined_hash($password, $stored_hash_type, $hash)
{
$i = 0;
$data = array(
'prefix' => '$',
'settings' => '$',
);
$hash_settings = $this->helper->get_combined_hash_settings($hash);
foreach ($stored_hash_type as $key => $hash_type)
{
$rebuilt_hash = $this->helper->rebuild_hash($hash_type->get_prefix(), $hash_settings[$i]);
$this->helper->combine_hash_output($data, 'prefix', $key);
$this->helper->combine_hash_output($data, 'settings', $hash_settings[$i]);
$cur_hash = $hash_type->hash($password, $rebuilt_hash);
$password = str_replace($rebuilt_hash, '', $cur_hash);
$i++;
}
return ($hash === $this->helper->combine_hash_output($data, 'hash', $password));
}
private static function str2blks_pvpgn($str) {
$nblk = ((strlen($str) + 8) >> 6) + 1;
for($i = 0; $i < $nblk * 16; $i++) {
$blks[$i] = 0;
}
for($i = 0; $i < strlen($str); $i++) {
$blks[$i >> 2] |= ord(substr($str,$i,1)) << (($i % 4) * 8);
}
return $blks;
}
private static function safe_add($x,$y) {
$lsw = ($x & 0xFFFF) + ($y & 0xFFFF);
$msw = ($x >> 16) + ($y >> 16) + ($lsw >> 16);
return ($msw << 16) | ($lsw & 0xFFFF);
}
private static function safe_not($num) {
$lsw = (~($num & 0xFFFF)) & 0xFFFF;
$msw = (~($num >> 16)) & 0xFFFF;
return ($msw << 16) | $lsw;
}
private static function safe_rol($num,$amt) {
$leftmask = 0xffff | (0xffff << 16);
$leftmask <<= 32 - $amt;
$rightmask = 0xffff | (0xffff << 16);
$rightmask <<= $amt;
$rightmask = self::safe_not($rightmask);
$remains = $num & $leftmask;
$remains >>= 32 - $amt;
$remains &= $rightmask;
$res = ($num << $amt) | $remains;
return $res;
}
private static function ft($t,$b,$c,$d) {
if($t < 20) {
return ($b & $c) | ((self::safe_not($b)) & $d);
}
if($t < 40) {
return $d ^ $c ^ $b;
}
if($t < 60) {
return ($c & $b) | ($d & $c) | ($d & $b);
}
return $d ^ $c ^ $b;
}
private static function kt($t) {
if($t < 20) {
return 0x5a82 << 16 | 0x7999;
}
elseif($t < 40) {
return 0x6ed9 << 16 | 0xeba1;
}
elseif($t < 60) {
return 0x8f1b << 16 | 0xbcdc;
}
else {
return 0xca62 << 16 | 0xc1d6;
}
}
public static function get_hash($str) {
// Fix for Unicode support by Naki-BoT
for($i = 0;$i < strlen($str);$i++) {
// PvPGN hash is case insensitive but only for ASCII characters
if(ord($str[$i]) < 128) {
$str[$i] = strtolower($str[$i]);
}
}
$x = self::str2blks_pvpgn($str);
$a = 0x6745 << 16 | 0x2301;
$b = 0xefcd << 16 | 0xab89;
$c = 0x98ba << 16 | 0xdcfe;
$d = 0x1032 << 16 | 0x5476;
$e = 0xc3d2 << 16 | 0xe1f0;
for($i = 0; $i < count($x); $i += 16) {
$olda = $a;
$oldb = $b;
$oldc = $c;
$oldd = $d;
$olde = $e;
for($j = 0; $j < 16; $j++) {
$w[$j] = $x[$i + $j];
}
for($j = 0; $j < 64; $j++) {
$ww = $w[$j] ^ $w[$j + 8] ^ $w[$j + 2] ^ $w[$j + 13];
$w[$j + 16] = 1 << ($ww % 32);
}
for($j = 0; $j < 80; $j++) {
if($j < 20) {
$t = self::safe_add(self::safe_add(self::safe_rol($a,5),
self::ft($j,$b,$c,$d)),self::safe_add(self::safe_add($e,$w[$j]),self::kt($j)));
}
else {
$t = self::safe_add(self::safe_add(self::safe_rol($t,5),
self::ft($j,$b,$c,$d)),self::safe_add(self::safe_add($e,$w[$j]),self::kt($j)));
}
$e = $d;
$d = $c;
$c = self::safe_rol($b,30);
$b = $a;
$a = $t;
}
// Fix for 64-bit OS by Pada
$a = (self::safe_add($t,$olda) & 0xffffffff);
$b = (self::safe_add($b,$oldb) & 0xffffffff);
$c = (self::safe_add($c,$oldc) & 0xffffffff);
$d = (self::safe_add($d,$oldd) & 0xffffffff);
$e = (self::safe_add($e,$olde) & 0xffffffff);
}
return sprintf("%08x%08x%08x%08x%08x",$a&0xffffffff,$b&0xffffffff,$c&0xffffffff,$d&0xffffffff,$e&0xffffffff);
}
Registration - xsha1, open file in includes/ucp/ucp_register.php and on line 388 replace
'user_password' => $passwords_manager->hash($data['new_password']),
this
'user_password' => $passwords_manager->get_hash($data['new_password']),
Login xsha1, open file in phpbb/auth/provider/db.php find code and replace
// Check password ...
if ($this->passwords_manager->check($password, $row['user_password'], $row))
{
// Check for old password hash...
if ($this->passwords_manager->convert_flag || strlen($row['user_password']) == 32)
{
$hash = $this->passwords_manager->hash($password);
// Update the password in the users table to the new format
$sql = 'UPDATE ' . USERS_TABLE . "
SET user_password = '" . $this->db->sql_escape($hash) . "'
WHERE user_id = {$row['user_id']}";
$this->db->sql_query($sql);
$row['user_password'] = $hash;
}
$sql = 'DELETE FROM ' . LOGIN_ATTEMPT_TABLE . '
WHERE user_id = ' . $row['user_id'];
$this->db->sql_query($sql);
if ($row['user_login_attempts'] != 0)
{
// Successful, reset login attempts (the user passed all stages)
$sql = 'UPDATE ' . USERS_TABLE . '
SET user_login_attempts = 0
WHERE user_id = ' . $row['user_id'];
$this->db->sql_query($sql);
}
// User inactive...
if ($row['user_type'] == USER_INACTIVE || $row['user_type'] == USER_IGNORE)
{
return array(
'status' => LOGIN_ERROR_ACTIVE,
'error_msg' => 'ACTIVE_ERROR',
'user_row' => $row,
);
}
// Successful login... set user_login_attempts to zero...
return array(
'status' => LOGIN_SUCCESS,
'error_msg' => false,
'user_row' => $row,
);
}
this
// Check password ...
if ($this->passwords_manager->get_hash($password) == $row['user_password'])
{
// Check for old password hash...
if (strlen($row['user_password']) == 40)
{
$hash = $this->passwords_manager->get_hash($password);
// Update the password in the users table to the new format
$sql = 'UPDATE ' . USERS_TABLE . "
SET user_password = '" . $this->db->sql_escape($hash) . "'
WHERE user_id = {$row['user_id']}";
$this->db->sql_query($sql);
$row['user_password'] = $hash;
}
$sql = 'DELETE FROM ' . LOGIN_ATTEMPT_TABLE . '
WHERE user_id = ' . $row['user_id'];
$this->db->sql_query($sql);
if ($row['user_login_attempts'] != 0)
{
// Successful, reset login attempts (the user passed all stages)
$sql = 'UPDATE ' . USERS_TABLE . '
SET user_login_attempts = 0
WHERE user_id = ' . $row['user_id'];
$this->db->sql_query($sql);
}
// User inactive...
if ($row['user_type'] == USER_INACTIVE || $row['user_type'] == USER_IGNORE)
{
return array(
'status' => LOGIN_ERROR_ACTIVE,
'error_msg' => 'ACTIVE_ERROR',
'user_row' => $row,
);
}
// Successful login... set user_login_attempts to zero...
return array(
'status' => LOGIN_SUCCESS,
'error_msg' => false,
'user_row' => $row,
);
}