...

View Full Version : Password Validator



MRushton
02-19-2011, 09:54 PM
/**
* Squiloople Framework
*
* LICENSE: Feel free to use and redistribute this code.
*
* @author Michael Rushton <michael@squiloople.com>
* @link http://squiloople.com/
* @category Squiloople
* @package Models
* @subpackage Validators
* @version 1.0
* @copyright Copyright 2011 Michael Rushton
*/

/**
* Password Validator
*
* Generate salts and peppers, and validate and hash passwords
*/
final class PasswordValidator
{

/**
* The password to validate
*
* @access private
* @var string $_password
*/
private $_password;

/**
* The key to be used for the HMAC
*
* @access private
* @var string $_key
*/
private $_key;

/**
* The salt
*
* @access private
* @var string $_salt
*/
private $_salt;

/**
* The pepper
*
* @access private
* @var string $_pepper
*/
private $_pepper = 'Sz^3X6r[UyvV~2]_0stT}8`uY7RwZx4{q|Q91W5';

/**
* Set the password and the optional key
*
* @access public
* @param string $password
* @param string $key
*/
public function __construct($password, $key = '')
{

// Set the password
$this->_password = $password;

// Set the key
$this->_key = $key;

}

/**
* Call the constructor fluently
*
* @access public
* @static
* @param string $password
* @param string key
* @return PasswordValidator
*/
public static function setPassword($password, $key = '')
{
return new self($password, $key);
}

/**
* Check to see if the password is between 8 and 39 characters inclusive in length
*
* @access public
* @var bool $key
* @return bool
*/
public function isValidLength($key = false)
{

// Select which of the password or key is to be validated
$password = $key ? $this->_key : $this->_password;

// If the password is not between 8 and 39 characters inclusive in length then return false
if (!isset($password[7]) || isset($password[39]))
{
return false;
}

// Otherwise return true
return true;

}

/**
* Check to see if the password is correctly formed
*
* @access public
* @var bool key
* @return bool
*/
public function isValidSyntax($key = false)
{

// Select which of the password or key is to be validated
$password = $key ? $this->_key : $this->_password;

// Return false if the password does not contain at least two characters of each case, two digits, and two other characters
if (!preg_match('/^(?=(?:.*[a-z]){2})(?=(?:.*[A-Z]){2})(?=(?:.*[0-9]){2})(?=(?:.*[^a-zA-Z0-9]){2})[\x20-\x7E]+$/sD', $password))
{
return false;
}

// Otherwise return true
return true;

}

/**
* Perform the validation check on the password's length and syntax
*
* @access public
* @var bool $key
* @return bool
*/
public function isValid($key = false)
{

// If the length validation is successful then return the syntax validation result
if ($this->isValidLength($key))
{
return $this->isValidSyntax($key);
}

// Otherwise return false
return false;

}

/**
* Set the salt
*
* @access public
* @var string $salt
* @return PasswordValidator
*/
public function setSalt($salt)
{

// Set the salt
$this->_salt = $salt;

// Return itself
return $this;

}

/**
* Generate and return a salt
*
* @access public
* @var bool $reset
* @return string
*/
public function getSalt($reset = false)
{

// If a salt has been set and a reset is not required then return the stored salt
if (!$reset && isset($this->_salt))
{
return $this->_salt;
}

// Reset the salt
$salt = '';

// Generate a random salt of 39 printable ASCII characters
for ($i = 1; $i <= 39; ++$i)
{
$salt .= chr(mt_rand(32, 126));
}

// Return the random salt
return $this->_salt = $salt;

}

/**
* Return the pepper if required
*
* @access private
* @var bool $key
* @return string
*/
private function _getPepper($key = false)
{

// If the pepper is for the key then reverse it
$pepper = $key ? strrev($this->_pepper) : $this->_pepper;

// Return the pepper portion
return substr($pepper, 0, 39 - strlen($key ? $this->_key : $this->_password));

}

/**
* Generate and return a key
*
* @access private
* @return string
*/
private function _getKey()
{
return $this->_getPepper(true) . $this->_key . strrev($this->getSalt());
}

/**
* Hash the the salt, the password, and the pepper using SHA 512
*
* @access private
* @return string
*/
private function _getHash()
{
return hash('sha512', $this->getSalt() . $this->_password . $this->_getPepper());
}

/**
* Hash the password using an HMAC
*
* @access public
* @return string
*/
public function getHash()
{
return hash('sha512', $this->_getKey() . $this->_getHash());
}

}

To instantiate the password validator, either use the new keyword or call the class statically using PasswordValidator::setPassword() passing as the first parameter the password and as the optional second parameter the key.


$passwordValidator = new PasswordValidator('swordfish', '5W0rdF!$h');

To validate the password's length, which must be between 8 and 39 characters inclusive, call the isValidLength() method. To validate the password's syntax, which may only contain printable ASCII characters and must contain at least one lower-case alphabetic character, one upper-case alphabetic character, one digit, and one other character, call the isValidSyntax() method. To validate both, call the isValid() method. Passing a true parameter to any of these will validate the key.


$passwordValidator = PasswordValidator::setPassword('swordfish', 'SW0r!$H');

$passwordValidator->isValidLength(); // Returns true
$passwordValidator->isValidSyntax(); // Returns false
$passwordValidator->isValid() // Returns false

$passwordValidator->isValidLength(true); // Returns true
$passwordValidator->isValidSyntax(true); // Returns true
$passwordValidator->isValid(true) // Returns false

To generate and return a salt, which is 39 characters in length and follows the same syntax rules as a valid password, call the getSalt() method. Generated salts are stored and returned if the method is called subsequent times. To generate a new salt pass a true parameter to the method.


$passwordValidator->getSalt(); // Returns h&%G8\SThz7\P"$j>nB[Fpip{_rS{(f{2DEw>4R
$passwordValidator->getSalt(); // Returns h&%G8\SThz7\P"$j>nB[Fpip{_rS{(f{2DEw>4R
$passwordValidator->getSalt(true) // Returns g0ow;+}5HnM*G ;|%!@?px$W4,DK)(3WbE*iK:1

To set an established salt, primarily used when verifying against an already hashed password, use the setSalt() method passing as the only parameter the salt. Calling getSalt() after setting a salt this way will return the set salt unless a true parameter is passed to the former.


$passwordValidator->setSalt('g0ow;+}5HnM*G ;|%!@?px$W4,DK)(3WbE*iK:1'); // Set the salt

To return a hash of the password, which automatically generates a salt if one has not already been set and appends to the password a portion of the pepper to increase the total length to 78 characters, call the getHash() method. This uses an HMAC SHA 512 cryptographic hash function.


$passwordValidator = new PasswordValidator('M1ch43L !$ 4w3S0m3', '4m ! RiT3?');

if ($passwordValidator->isValid() && $passwordValidator->isValid(true))
{
$hash = $passwordValidator->getHash();
}

// Returns: 645995e153424619fb6f6194f6d60c323a678470388f91c4a84ae713d56b3d00e9feb46040f92df799b00e689c6a9e285eb3 78ac6475193e13e715e53a3cb854

1. Is this the correct way to use an HMAC (I know there's a native hash_hmac function but decided on doing it my way instead)?
2. Should the key be longer than the 79 characters returned already? If so, should the same be true of the salt + password + pepper, and how many? 128?

Thanks.

Arcticwarrio
08-08-2012, 09:40 PM
i made this for adding salt to a password also for temporary passwords or pin numbers, could also be used for creating password reset keys

unique string chars or duplicated,
upper case, lowercase + numbers
Upper case + numbers
Numbers only

feel free to message me if you need help modifying it for your own needs
could easily be altered to generate lottery numbers etc

function:


function GenCode($len,$type = 1,$uni = 0){
//Written by Arcticwarrio - 08-August-2012
//http://www.codingforums.com/member.php?u=147238
//GenCode(length of string,$type = 1, 2 or 3,unique chars?)
//Unique Switch 1 for on 0 or ommited for off
//Type Switch 1 = a-z, A-Z, 0-9 Usage: GenCode(8); or GenCode(8,1);
//Type Switch 2 = A-Z, 0-9 Usage: GenCode(10,2);
//Type Switch 2 = 0-9 Usage: GenCode(4,3);

//Reset Function
$code ='';
//Array of chars to choose from, feel free to add more arrays
$codestring['1'] = array('a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x ','y','z','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W ','X','Y','Z','1','2','3','4','5','6','7','8','9','0');
$codestring['2'] = array('A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X ','Y','Z','1','2','3','4','5','6','7','8','9','0');
$codestring['3'] = array('1','2','3','4','5','6','7','8','9','0');

//see if the string should contain unique chars
if ($uni == 1){
//check if theres enough chars to have a unique string
if ($len > count($codestring[$type])-1){ echo "error length too long for unique string"; exit;}
//loop for lenght of $len NOT allowing duplicate chars
for ($i=1; $i<=$len; $i++){
//add char from chosen array to the end of the variable $code
$tempx = $codestring[$type][rand(0,count($codestring[$type])-1)];
if (strstr($code, $tempx) != false){
$i--;
}else{
$code .= $tempx;
}
}

}else{
//loop for lenght of $len allowing duplicate chars
for ($i=1; $i<=$len; $i++){
//add char from chosen array to the end of the variable $code
$code .= $codestring[$type][rand(0,count($codestring[$type])-1)];
}
}
//send $code back to where GenCode() was called from
return $code;
}



EZ Archive Ads Plugin for vBulletin Copyright 2006 Computer Help Forum