PHP Password Hashing Class
<?php
//usage:
// $hash = HashSimple::hash($password);
// if (HashSimple::equivalent($password, $hash))...
class HashSimple
{
private static $rounds_exp=14;//14 : 2^14 rounds of hashing alg
private static $salt_length=12;//12 base64_encodes nicely 16 chars without padding, and is a multiple of 2
private static $skip_logging=true;
public static function hash($input)
{
$random_salt = openssl_random_pseudo_bytes(self::$salt_length, $crypto_strong=true);
return self::saltedHash($input,$random_salt);
}
public static function equivalent($plaintext,$candidate_hash)
{
$candidate_hash[0]=='$' or self::error("HashError: invalid param");
$pieces = explode("$", substr($candidate_hash,1));
$rounds_exp = ltrim($pieces[0],".");
$salt = base64_decode(strtr($pieces[1],".","+"));
$generated_hash = self::saltedHash($plaintext,$salt,$rounds_exp);
return ($candidate_hash==$generated_hash) ? true : false;
}
private static function saltedHash($input,$salt,$rounds_exp=null)
{
$rounds_exp = is_null($rounds_exp) ? self::$rounds_exp : $rounds_exp;
if (!in_array('sha384', hash_algos())) { return self::log("HashError: unknown hash alg:".self::$hash_alg); }
if (self::$salt_length%2==1) { return self::log("HashError: salt length must be multiple of 2"); }
$rounds = pow(2,$rounds_exp);
$halfway = floor(self::$salt_length/2);
$p1 = substr($salt, 0, $halfway);
$p2 = substr($salt, $halfway);
$hashme = $p1.$input.$p2;
self::$skip_logging or $start = microtime(true);
for($i=0; $i<$rounds; $i++)
{
$hashme = hash('sha384', $hashme, $raw = true);
}
self::$skip_logging or self::log("HashLog: hashtime-".sprintf("%1.3f", microtime(true) - $start));
self::$skip_logging or self::log("HashLog: rounds-".$rounds);
return '$.'.$rounds_exp.'$'.strtr(base64_encode($salt),"+",".").'$'.strtr(base64_encode($hashme),"+",".");
}
private static function log($message)
{
$r = php_sapi_name()=='cli' ? file_put_contents('php://stderr', $message."\n") : error_log($message);
return null;
}
}code snippets are licensed under Creative Commons CC-By-SA 3.0 (unless otherwise specified)
|