GameZoo Forums

Live free, frag hard.

You are not logged in.

#1 08/09/2014 14:28:12

seven
Administrator

phpass for FluxBB 1.5.*

This thread is here to discuss the password hashing framework phpass and its implementation in FluxBB.

Reference: http://www.openwall.com/phpass/

Useful reading: http://www.openwall.com/articles/PHP-Users-Passwords

FluxBB modification available for download here: http://fluxbb.org/resources/mods/gamezoo-phpass

FluxBB modification README.txt:

##
##
##        Mod title:  GameZoo PHPass for FluxBB
##
##      Mod version:  0.1
##  Works on FluxBB:  1.5.*
##     Release date:  2014-09-08
##           Author:  seven (seven@gamezoo.org)
##
##      Description:  This mod enables PHPass on your FluxBB forum.
##                    The passwords are updated automatically when the user
##                    attempts to login.
##
##   Affected files:  install.php
##                    login.php
##                    profile.php
##                    register.php
##                    include/functions.php
##                    include/PasswordHash.php (new file)
##
##       Affects DB:  Yes
##                    - altered table: users (password goes from 40 to 60 chars)
##
##            Notes:  You cannot revert the passwords.
##                    You have to run one SQL query before proceeding.
##                    The altered files have been included, but they're
##                    not guaranteed to be updated to the latest FluxBB.
##                    The PasswordHash class is taken from:
##                        http://www.openwall.com/phpass/
##
##       DISCLAIMER:  Please note that "mods" are not officially supported by
##                    FluxBB. Installation of this modification is done at your
##                    own risk. Backup your forum database and any and all
##                    applicable files before proceeding.
##
##

#
#---------[ 1. RUN SQL STATEMENT ]--------------------------------------------
#

ALTER TABLE users ALTER COLUMN password varchar(60);

#
#---------[ 2. UPLOAD ]-------------------------------------------------------
#

root/include/PasswordHash.php to /include


#
#---------[ 3. OPEN ]---------------------------------------------------------
#

/include/functions.php


#
#---------[ 4. FIND ]---------------------------------------------------------
#

// Check if there's a user matching $user and $password
    $result = $db->query('SELECT u.*, g.*, o.logged, o.idle FROM '.$db->prefix.'users AS u INNER JOIN '.$db->prefix.'groups AS g ON g.g_id=u.group_id LEFT JOIN '.$db->prefix.'online AS o ON o.user_id=u.id WHERE '.(is_int($user) ? 'u.id='.intval($user) : 'u.username=\''.$db->escape($user).'\'')) or error('Unable to fetch user info', __FILE__, __LINE__, $db->error());
    $pun_user = $db->fetch_assoc($result);

    if (!isset($pun_user['id']) ||
        ($password_is_hash && $password != $pun_user['password']) ||
        (!$password_is_hash && pun_hash($password) != $pun_user['password']))
        set_default_user();
    else
        $pun_user['is_guest'] = false;

        
#
#---------[ 5. REPLACE ]------------------------------------------------------
#

    // Check if there's a user matching $user and $password
    $result = $db->query('SELECT u.*, g.*, o.logged, o.idle FROM '.$db->prefix.'users AS u INNER JOIN '.$db->prefix.'groups AS g ON g.g_id=u.group_id LEFT JOIN '.$db->prefix.'online AS o ON o.user_id=u.id WHERE '.(is_int($user) ? 'u.id='.intval($user) : 'u.username=\''.$db->escape($user).'\'')) or error('Unable to fetch user info', __FILE__, __LINE__, $db->error());
    $pun_user = $db->fetch_assoc($result);

    if (!isset($pun_user['id']) ||
        ($password_is_hash && $password != $pun_user['password']) ||
        (!$password_is_hash && !phpass_check($password, $pun_user['password'])))
        set_default_user();
    else
        $pun_user['is_guest'] = false;


#
#---------[ 6. FIND ]---------------------------------------------------------
#

//
// Compute a hash of $str
//
function pun_hash($str)
{
    return sha1($str);
}


#
#---------[ 7. AFTER, ADD ]---------------------------------------------------
#

//
// Compute PHPass password hashes. pun_hash() is used for many other things.
//
function phpass_hash($password)
{
    if (strlen($password) > 72) { die("Password is longer than 72 characters"); }
    if(!class_exists("PasswordHash"))
        require "PasswordHash.php";
    $hasher = new PasswordHash(8, false);
    $hash = $hasher->HashPassword($password);
    if (strlen($hash) < 20) { die("Password hashing failed"); }
    unset($hasher);
    return $hash;
}

//
// Check passwords against PHPass stored hashes
// returns true if the password matches with the stored hash
// returns false if the password is too long or doesn't match
//
function phpass_check($password, $storedHash)
{
    if (strlen($password) > 72) return false;
    if(!class_exists("PasswordHash"))
        require "PasswordHash.php";
    $hasher = new PasswordHash(8, false);
    $check = $hasher->CheckPassword($password, $storedHash);
    unset($hasher);
    return $check;
}

#
#---------[ 8. OPEN ]---------------------------------------------------------
#

/install.php


#
#---------[ 9. FIND ]---------------------------------------------------------
#

            'username'            => array(
                'datatype'        => 'VARCHAR(200)',
                'allow_null'    => false,
                'default'        => '\'\''
            ),
            'password'            => array(
                'datatype'        => 'VARCHAR(40)',
                'allow_null'    => false,
                'default'        => '\'\''
            ),


#
#---------[ 10. REPLACE ]-----------------------------------------------------
#

            'username'            => array(
                'datatype'        => 'VARCHAR(200)',
                'allow_null'    => false,
                'default'        => '\'\''
            ),
            'password'            => array(
                'datatype'        => 'VARCHAR(60)',
                'allow_null'    => false,
                'default'        => '\'\''
            ),


#
#---------[ 11. FIND ]--------------------------------------------------------
#

    $db->query('INSERT INTO '.$db_prefix.'users (group_id, username, password, email, language, style, num_posts, last_post, registered, registration_ip, last_visit) VALUES(1, \''.$db->escape($username).'\', \''.pun_hash($password1).'\', \''.$email.'\', \''.$db->escape($default_lang).'\', \''.$db->escape($default_style).'\', 1, '.$now.', '.$now.', \''.$db->escape(get_remote_address()).'\', '.$now.')')
        or error('Unable to add administrator user. Please check your configuration and try again', __FILE__, __LINE__, $db->error());

        
#
#---------[ 12. REPLACE ]-----------------------------------------------------
#        

    $db->query('INSERT INTO '.$db_prefix.'users (group_id, username, password, email, language, style, num_posts, last_post, registered, registration_ip, last_visit) VALUES(1, \''.$db->escape($username).'\', \''.phpass_hash($password1).'\', \''.$email.'\', \''.$db->escape($default_lang).'\', \''.$db->escape($default_style).'\', 1, '.$now.', '.$now.', \''.$db->escape(get_remote_address()).'\', '.$now.')')
        or error('Unable to add administrator user. Please check your configuration and try again', __FILE__, __LINE__, $db->error());

        
#
#---------[ 13. OPEN ]--------------------------------------------------------
#

/login.php


#
#---------[ 14. FIND ]--------------------------------------------------------
#

    $cur_user = $db->fetch_assoc($result);

    $authorized = false;

    if (!empty($cur_user['password']))
    {
        
        
        $form_password_hash = pun_hash($form_password); // Will result in a SHA-1 hash

        // If there is a salt in the database we have upgraded from 1.3-legacy though haven't yet logged in
        if (!empty($cur_user['salt']))
        {
            if (sha1($cur_user['salt'].sha1($form_password)) == $cur_user['password']) // 1.3 used sha1(salt.sha1(pass))
            {
                $authorized = true;

                $db->query('UPDATE '.$db->prefix.'users SET password=\''.$form_password_hash.'\', salt=NULL WHERE id='.$cur_user['id']) or error('Unable to update user password', __FILE__, __LINE__, $db->error());
            }
        }
        // If the length isn't 40 then the password isn't using sha1, so it must be md5 from 1.2
        else if (strlen($cur_user['password']) != 40)
        {
            if (md5($form_password) == $cur_user['password'])
            {
                $authorized = true;

                $db->query('UPDATE '.$db->prefix.'users SET password=\''.$form_password_hash.'\' WHERE id='.$cur_user['id']) or error('Unable to update user password', __FILE__, __LINE__, $db->error());
            }
        }
        // Otherwise we should have a normal sha1 password
        else
            
            $authorized = ($cur_user['password'] == $form_password_hash);
    }

    if (!$authorized)
        message($lang_login['Wrong user/pass'].' <a href="login.php?action=forget">'.$lang_login['Forgotten pass'].'</a>');

    // Update the status if this is the first time the user logged in


#
#---------[ 15. REPLACE ]-----------------------------------------------------
#        

    $cur_user = $db->fetch_assoc($result);

    $authorized = false;

    if (!empty($cur_user['password']))
    {
        // Try with PHPass first.
        $authorized = phpass_check($form_password, $cur_user['password']);
        
        if(!$authorized)
        {
            // Old FluxBB passwords that will be updated to PHPass.
        
            // If there is a salt in the database we have upgraded from 1.3-legacy though haven't yet logged in
            if (!empty($cur_user['salt']))
            {
                if (sha1($cur_user['salt'].sha1($form_password)) == $cur_user['password']) // 1.3 used sha1(salt.sha1(pass))
                {
                    $authorized = true;
                
                    // Compute the new hash using the provided password
                    $new_password_hash = phpass_hash($form_password);
                
                    // Update password with PHPass
                    $db->query('UPDATE '.$db->prefix.'users SET password=\''.$new_password_hash.'\', salt=NULL WHERE id='.$cur_user['id']) or error('Unable to update user password', __FILE__, __LINE__, $db->error());
                }
            }
            // If the length isn't 40 then the password isn't using sha1, so it must be md5 from FluxBB 1.2
            else if (strlen($cur_user['password']) != 40)
            {
                if (md5($form_password) == $cur_user['password'])
                {
                    $authorized = true;
                    
                    // Compute the new hash using the provided password
                    $new_password_hash = phpass_hash($form_password);
                    
                    // Update password with PHPass
                    $db->query('UPDATE '.$db->prefix.'users SET password=\''.$new_password_hash.'\' WHERE id='.$cur_user['id']) or error('Unable to update user password', __FILE__, __LINE__, $db->error());
                }
            }
            // Otherwise we should have a normal sha1 password (FluxBB 1.5.x)
            else if (strlen($cur_user['password'] == 40)
            {
                $form_password_hash = pun_hash($form_password); // Will result in a SHA-1 hash
                
                if ($cur_user['password'] == $form_password_hash)
                {
                    $authorized = true;
                    
                    // Compute the new hash using the provided password
                    $new_password_hash = phpass_hash($form_password);
                    
                    // Update password with PHPass
                    $db->query('UPDATE '.$db->prefix.'users SET password=\''.$new_password_hash.'\' WHERE id='.$cur_user['id']) or error('Unable to update user password', __FILE__, __LINE__, $db->error());
                }
            }
            
            // If we end up here, nothing can be done.
        }
    }

    if (!$authorized)
        message($lang_login['Wrong user/pass'].' <a href="login.php?action=forget">'.$lang_login['Forgotten pass'].'</a>');

    // Update the status if this is the first time the user logged in

#
#---------[ 16. FIND ]--------------------------------------------------------
#

    // Remove this user's guest entry from the online list
    $db->query('DELETE FROM '.$db->prefix.'online WHERE ident=\''.$db->escape(get_remote_address()).'\'') or error('Unable to delete from online list', __FILE__, __LINE__, $db->error());

    $expire = ($save_pass == '1') ? time() + 1209600 : time() + $pun_config['o_timeout_visit'];
    pun_setcookie($cur_user['id'], $form_password_hash, $expire);

    // Reset tracked topics
    set_tracked_topics(null);

    redirect(pun_htmlspecialchars($_POST['redirect_url']), $lang_login['Login redirect']);


#
#---------[ 17. REPLACE ]-----------------------------------------------------
#

    // Remove this user's guest entry from the online list
    $db->query('DELETE FROM '.$db->prefix.'online WHERE ident=\''.$db->escape(get_remote_address()).'\'') or error('Unable to delete from online list', __FILE__, __LINE__, $db->error());

    $expire = ($save_pass == '1') ? time() + 1209600 : time() + $pun_config['o_timeout_visit'];
    pun_setcookie($cur_user['id'], $cur_user['password'], $expire);

    // Reset tracked topics
    set_tracked_topics(null);

    redirect(pun_htmlspecialchars($_POST['redirect_url']), $lang_login['Login redirect']);


#
#---------[ 18. FIND ]--------------------------------------------------------
#

                    // Generate a new password and a new password activation code
                    $new_password = random_pass(8);
                    $new_password_key = random_pass(8);

                    $db->query('UPDATE '.$db->prefix.'users SET activate_string=\''.pun_hash($new_password).'\', activate_key=\''.$new_password_key.'\', last_email_sent = '.time().' WHERE id='.$cur_hit['id']) or error('Unable to update activation data', __FILE__, __LINE__, $db->error());

                    // Do the user specific replacements to the template


#
#---------[ 19. REPLACE ]-----------------------------------------------------
#

                    // Generate a new password and a new password activation code
                    $new_password = random_pass(8);
                    $new_password_key = random_pass(8);

                    $db->query('UPDATE '.$db->prefix.'users SET activate_string=\''.phpass_hash($new_password).'\', activate_key=\''.$new_password_key.'\', last_email_sent = '.time().' WHERE id='.$cur_hit['id']) or error('Unable to update activation data', __FILE__, __LINE__, $db->error());

                    
#
#---------[ 20. OPEN ]--------------------------------------------------------
#

/profile.php


#
#---------[ 21. FIND ]--------------------------------------------------------
#

        $authorized = false;

        if (!empty($cur_user['password']))
        {
            $old_password_hash = pun_hash($old_password);

            if ($cur_user['password'] == $old_password_hash || $pun_user['is_admmod'])
                $authorized = true;
        }

        if (!$authorized)
            message($lang_profile['Wrong pass']);

        $new_password_hash = pun_hash($new_password1);


#
#---------[ 22. REPLACE ]-----------------------------------------------------
#

        $authorized = false;

        if (!empty($cur_user['password']))
        {
            if (phpass_check($old_password, $cur_user['password']) || $pun_user['is_admmod'])
                $authorized = true;
        }

        if (!$authorized)
            message($lang_profile['Wrong pass']);

        $new_password_hash = phpass_hash($new_password1);

        
#
#---------[ 23. FIND ]--------------------------------------------------------
#

    else if (isset($_POST['form_sent']))
    {
        if (pun_hash($_POST['req_password']) !== $pun_user['password'])
            message($lang_profile['Wrong pass']);
            
        // Make sure they got here from the site
        confirm_referrer('profile.php');

        
#
#---------[ 24. REPLACE ]-----------------------------------------------------
#

    else if (isset($_POST['form_sent']))
    {
        if (!phpass_check($_POST['req_password'], $pun_user['password']))
            message($lang_profile['Wrong pass']);
            
        // Make sure they got here from the site
        confirm_referrer('profile.php');

        
#
#---------[ 25. OPEN ]--------------------------------------------------------
#

/register.php


#
#---------[ 26. FIND ]--------------------------------------------------------
#

        $password_hash = pun_hash($password1);

        
#
#---------[ 27. REPLACE ]-----------------------------------------------------
#

        $password_hash = phpass_hash($password1);

        
#
#---------[ 28. SAVE/UPLOAD ]-------------------------------------------------
#

Punirne cento per educarne uno.

Offline

#2 10/09/2014 13:53:38

seven
Administrator

Re: phpass for FluxBB 1.5.*

I found a glitch in the SQL statement. MySQL expects:

ALTER TABLE users MODIFY password varchar(60);

Punirne cento per educarne uno.

Offline

Board footer

Powered by FluxBB