<?php
namespace framework\components\security;
use framework\base\Component;
class Password extends Component
{
private $_value;
private $PBKDF2_HASH_ALGORITHM="sha256";
private $PBKDF2_ITERATIONS=3000;
private $PBKDF2_SALT_BYTE_SIZE=16;
private $PBKDF2_HASH_BYTE_SIZE=32;
private $HashSalt;
private $HashStr;
protected function init()
{
$this->unInstall();
}
public function setPassword($val)
{
$this->_value = $val;
return $this;
}
public function setHash($val)
{
$this->HashStr = $val;
return $this;
}
public function setSalt($val)
{
$this->HashSalt = $val;
return $this;
}
private function MakeHashSalt()
{
if(\function_exists("openssl_random_pseudo_bytes"))
$salt = \base64_encode(\openssl_random_pseudo_bytes($this->PBKDF2_SALT_BYTE_SIZE ));
else
$salt=\base64_encode($this->MakeTmpSalt());
$this->HashSalt=$salt;
}
private function MakeTmpSalt()
{
return \randStr($this->PBKDF2_SALT_BYTE_SIZE);
}
public function GetHashSalt()
{
return $this->HashSalt;
}
public function GetHashStr()
{
return $this->HashStr;
}
public function MakeHashStr()
{
$this->MakeHashSalt();
$this->HashStr= \base64_encode($this->pbkdf2(
$this->PBKDF2_HASH_ALGORITHM,
$this->_value,
$this->HashSalt,
$this->PBKDF2_ITERATIONS,
$this->PBKDF2_HASH_BYTE_SIZE,
true
));
return $this->HashStr;
}
public function validate()
{
if(!$this->HashStr||!$this->HashSalt||!$this->_value)
return false;
$pbkdf2 = \base64_decode($this->HashStr);
return $this->SlowEquals(
$pbkdf2,
$this->pbkdf2(
$this->PBKDF2_HASH_ALGORITHM,
$this->_value,
$this->HashSalt,
$this->PBKDF2_ITERATIONS,
strlen($pbkdf2),
true
)
);
}
private function SlowEquals($a, $b)
{
$diff = \strlen($a) ^ \strlen($b);
for($i = 0; $i < \strlen($a) && $i < \strlen($b); $i++)
{
$diff |= \ord($a[$i]) ^ \ord($b[$i]);
}
return $diff === 0;
}
private function Pbkdf2($algorithm, $password, $salt, $count, $key_length, $raw_output = false)
{
$algorithm = \strtolower($algorithm);
if(!\in_array($algorithm, \hash_algos(), true))
\trigger_error('PBKDF2 ERROR: Invalid hash algorithm.', E_USER_ERROR);
if($count <= 0 || $key_length <= 0)
\trigger_error('PBKDF2 ERROR: Invalid parameters.', E_USER_ERROR);
if (\function_exists("hash_pbkdf2")) {
if (!$raw_output) {
$key_length = $key_length * 2;
}
return \hash_pbkdf2($algorithm, $password, $salt, $count, $key_length, $raw_output);
}
$hash_length = \strlen(\hash($algorithm, "", true));
$block_count = \ceil($key_length / $hash_length);
$output = "";
for($i = 1; $i <= $block_count; $i++) {
$last = $salt . \pack("N", $i);
$last = $xorsum = \hash_hmac($algorithm, $last, $password, true);
for ($j = 1; $j < $count; $j++) {
$xorsum ^= ($last = \hash_hmac($algorithm, $last, $password, true));
}
$output .= $xorsum;
}
if($raw_output)
return \substr($output, 0, $key_length);
else
return \bin2hex(\substr($output, 0, $key_length));
}
}