PHP Developers Network

A community of PHP developers offering assistance, advice, discussion, and friendship.
 
Loading
It is currently Mon Oct 22, 2018 8:24 am

All times are UTC - 5 hours




Post new topic Reply to topic  [ 25 posts ]  Go to page 1, 2  Next
Author Message
PostPosted: Wed Jan 19, 2011 3:20 pm 
Offline
Site Administrator
User avatar

Joined: Sun May 19, 2002 10:24 pm
Posts: 6887
This code creates a variable length salt to the left and right of a fixed length password hash using the password length to determine the characters allocated for the salt. This makes it impossible to determine what part of the hash is the the salt vs what part of the hash is the actual hash.

Just posting this in case anyone finds it useful. Modify to suit.

Syntax: [ Download ] [ Hide ]
<?php
/**
 * Class asPasswordHash
 *
 * A very secure password hashing scheme using the whirlpool algorythm
 * and creating an impossible to find salt without knowing the actual
 * length of the password.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS
 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * @package
 * @author     Benjamin Lewis
 * @version    1.0
 */

class asPasswordHash
{
    /**
     * Contains the algorythm used for hashing passwords
     *
     * @var string
     * @access private
     */

    private $_algorythm = 'whirlpool';

    /**
     *
     * @param string $algo The hashing algorythm to use
     * @access public
     */

    public function __construct($algo = null) {
        $this->_algorythm = $algo === null ? $this->_algorythm : $algo;
    }

    /**
     * Sets the algorythm to use when creating password hashes
     *
     * @var string The algorythm to use
     * @return object An instance of this class
     * @access public
     */

    public function setAlgo($algo) {
        $this->_algorythm = $algo;
        return $this;
    }

    /**
     * Gets the algorythm currently being used to create hashes
     *
     * @return string The current alogrythm in use
     */

    public function getAlgo() {
        return $this->_algorythm;
    }

    /**
     * Creates a salted password hash with the salt embedded in the actual
     * hash.
     *
     * @param  string $password The actual password
     * @param  string $hash The hash to check a password against
     * @return string The hashed password
     */

    public function get($password, $hash = null) {
        if (!in_array($this->_algorythm, hash_algos())) {
            trigger_error(sprintf("%s is not an available hashing algorythm", $this->_algorythm), E_USER_ERROR);
        }

        /*
         * If a hash is not specified, one is created by hashing a random
         * 256 byte string.
         */

        if ($hash === null) {
            $salt = '';
            for ($i = 0; $i <= 256; $i++) {
                $salt .= chr(mt_rand(0, 255));
            }

            $hashedSalt = hash($this->_algorythm, $salt);
        } else {
            $hashedSalt = $hash;
        }

        /*
         * The length of the salt to use is set by dividing the length
         * of the generated hash for this algorythm by 6 and rounding
         * down.
         */

        $saltLen = floor(strlen($hashedSalt) / 6);

        /*
         * Save the length of the password for later use.
         */

        $passwdLen = strlen($password);

        /*
         * While the length of the password is greater than the salt length,
         * multiply the length of the password by the value of the last digit
         * of the length divided by 10.
         *
         * Example:
         *     Password Length = 1009
         *     (9 / 10) = 0.9
         *     (1009 * 0.9) = 908.1
         *     New Password Length = 908.1
         */

        while ($passwdLen > $saltLen) {
            $passwdLen = $passwdLen * (substr($passwdLen, -1) / 10);
        }

        /*
         * We need $passwdLen to be an absolute integer value
         */

        $passwdLen  = (integer) abs($passwdLen);

        /*
         * Subtracting the length of the password from the length of the
         * salt that we will be using gives us the number of salt characters
         * to use in the final hash
         */

        $saltLen -= $passwdLen;

        /*
         * Populate the left and right salt values from the hashed salt using
         * the values we calculated earlier
         */

        $leftSalt  = substr($hashedSalt, 0, $passwdLen);
        $rightSalt = substr($hashedSalt, -$saltLen, $saltLen);

        /*
         * Generate the password hash
         */

        $passwdHash = hash($this->_algorythm, ($leftSalt . $password . $rightSalt));

        /*
         * Cut off left and right portions of the hashed password.  These will
         * be replaced by the left and right salts.
         */

        if ($saltLen == 0) {
            $passwdHash = substr($passwdHash, $passwdLen);
        } else {
            $passwdHash = substr($passwdHash, $passwdLen, -$saltLen);
        }

        /*
         * Return the left salt, password hash and right salt
         */

        return $leftSalt . $passwdHash . $rightSalt;
    }
}


Usage:

Syntax: [ Download ] [ Hide ]
    public static function isUserPassword($password, $passwordHash) {
        $pHash = new asPasswordHash();
        return $passwordHash == $pHash->get($password, $passwordHash);
    }

    public function setPassword($password) {
        /*
         * Every time this method is called a new password hash will be
         * generated, even if the password has not been changed.  This
         * check will stop the password update if it has not been changed
         * by comparing the password hash with the password posted.
         */

        $pHash = new asPasswordHash();
        if ($this->password == $pHash->get($password, $this->password)) {
            return $this;
        } else {
            return parent::setPassword($pHash->get($password));
        }
    }


Syntax: [ Download ] [ Hide ]
CREATE TABLE IF NOT EXISTS `user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_name` varchar(25) NOT NULL,
  `email` varchar(64) NOT NULL,
  `password` varchar(128) NOT NULL,
  `reg_ip_lan` int(11) DEFAULT NULL,
  `reg_ip_wan` int(11) DEFAULT NULL,
  `last_login` datetime DEFAULT NULL,
  `created_at` datetime DEFAULT NULL,
  `updated_at` datetime DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `user_U_1` (`user_name`),
  UNIQUE KEY `user_U_2` (`email`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;

_________________
Image


Top
 Profile  
 
PostPosted: Wed Jan 19, 2011 3:49 pm 
Offline
DevNet Master
User avatar

Joined: Thu Mar 15, 2007 6:28 pm
Posts: 2765
Location: Redding, California
Looks good, a clever way to eliminate the extra table column.


Top
 Profile  
 
PostPosted: Wed Jan 19, 2011 4:19 pm 
Offline
Site Administrator
User avatar

Joined: Sun May 19, 2002 10:24 pm
Posts: 6887
Well, in reality a salt is useless if it is known.

_________________
Image


Top
 Profile  
 
PostPosted: Wed Jan 19, 2011 4:45 pm 
Offline
DevNet Master
User avatar

Joined: Thu Mar 15, 2007 6:28 pm
Posts: 2765
Location: Redding, California
What do you mean? Isn't it unknown stored in a database table?


Top
 Profile  
 
PostPosted: Wed Jan 19, 2011 4:50 pm 
Offline
Site Administrator
User avatar

Joined: Sun May 19, 2002 10:24 pm
Posts: 6887
Sure. But so is the hash. So why use the salt in the first place;)

_________________
Image


Top
 Profile  
 
PostPosted: Wed Jan 19, 2011 5:00 pm 
Offline
Forum Contributor

Joined: Fri Jan 14, 2011 6:33 pm
Posts: 143
Location: England
Its very good but surely doing

Syntax: [ Download ] [ Hide ]
$password = md5($password . $password . $password);


Is just as secure as it basically has a salt as you cant work out the salt or the password without knowing the password.


Top
 Profile  
 
PostPosted: Wed Jan 19, 2011 5:09 pm 
Offline
DevNet Master
User avatar

Joined: Thu Mar 15, 2007 6:28 pm
Posts: 2765
Location: Redding, California
Wait, what hash?


Top
 Profile  
 
PostPosted: Wed Jan 19, 2011 5:22 pm 
Offline
DevNet Master
User avatar

Joined: Wed Jun 27, 2007 9:44 am
Posts: 4313
Location: Sofia, Bulgaria
Benjamin wrote:
Well, in reality a salt is useless if it is known.

Benjamin wrote:
Sure. But so is the hash. So why use the salt in the first place;)


I think rainbow attacks or dictionary attacks are useless (or at least very hard to apply) for salted hashes even if the salt is known. Yes, a "secret" salt will increase the security, but if the salt is long enough it really doesn't matter.

_________________
There are 10 types of people in this world, those who understand binary and those who don't


Top
 Profile  
 
PostPosted: Thu Jan 20, 2011 12:31 pm 
Offline
Site Administrator
User avatar

Joined: Sun May 19, 2002 10:24 pm
Posts: 6887
VladSun wrote:
I think rainbow attacks or dictionary attacks are useless (or at least very hard to apply) for salted hashes even if the salt is known.


What makes you say this?

Jonah Bron wrote:
Wait, what hash?


The one stored in the database.

Peter Kelly wrote:
Its very good but surely doing

Syntax: [ Download ] [ Hide ]
$password = md5($password . $password . $password);


Is just as secure as it basically has a salt as you cant work out the salt or the password without knowing the password.


No. An attacker only needs to know how the hashes are generated in order to break them.

_________________
Image


Top
 Profile  
 
PostPosted: Thu Jan 20, 2011 1:38 pm 
Offline
DevNet Master
User avatar

Joined: Thu Mar 15, 2007 6:28 pm
Posts: 2765
Location: Redding, California
Benjamin wrote:
The one stored in the database.
You mean the hash of the password?


Top
 Profile  
 
PostPosted: Thu Jan 20, 2011 2:25 pm 
Offline
Site Administrator
User avatar

Joined: Sun May 19, 2002 10:24 pm
Posts: 6887
Yeah

_________________
Image


Top
 Profile  
 
PostPosted: Thu Jan 20, 2011 2:27 pm 
Offline
DevNet Master
User avatar

Joined: Thu Mar 15, 2007 6:28 pm
Posts: 2765
Location: Redding, California
I see. So if they have the database and the code, the salt won't help?


Top
 Profile  
 
PostPosted: Thu Jan 20, 2011 2:39 pm 
Offline
Site Administrator
User avatar

Joined: Sun May 19, 2002 10:24 pm
Posts: 6887
This wikipedia entry covers the topic pretty well: http://en.wikipedia.org/wiki/Salt_%28cryptography%29

_________________
Image


Top
 Profile  
 
PostPosted: Thu Jan 20, 2011 3:04 pm 
Offline
DevNet Master
User avatar

Joined: Thu Mar 15, 2007 6:28 pm
Posts: 2765
Location: Redding, California
Okay, I read it. Does one store a hash of the salt or the salt itself? I'm still not entirely clear on how it secures things if a malicious person has access to the database.


Top
 Profile  
 
PostPosted: Thu Jan 20, 2011 3:07 pm 
Offline
Site Administrator
User avatar

Joined: Sun May 19, 2002 10:24 pm
Posts: 6887
Well most of the code I've seen that actually *does* use a salt generally prefixes the password with it, so it's easy to find.

My class above creates a random, variable length salt that is mixed in with the actual password hash, so it's extremely difficult to determine what the salt actually is.

_________________
Image


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 25 posts ]  Go to page 1, 2  Next

All times are UTC - 5 hours


Who is online

Users browsing this forum: No registered users and 1 guest


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Jump to:  
Powered by phpBB® Forum Software © phpBB Group