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)