Just posting this in case anyone finds it useful. Modify to suit.
Code: Select all
<?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;
}
}Code: Select all
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));
}
}Code: Select all
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 ;