Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- <?php // https://en.wikipedia.org/wiki/Hash-based_message_authentication_code
- /**
- * Based on something by Created by Chris on 9/29/2014 3:55 PM.
- *
- * - added password_hash functions - http://php.net/manual/en/faq.passwords.php
- * by RFV 7/2015
- *
- * Added HMAC (Hash-based_message_authentication_code) functions...
- *
- * All the faults are mine.
- *
- * These have been PHPUnit tested.
- *
- * Licence: https://opensource.org/licenses/MIT
- *
- * I really do not care what you use it for. All the information used here is
- * in the public domain. Enjoy, change it or whatever.
- *
- */
- namespace app\system\encryption;
- use app\system\encryption\RandomData;
- // use app\system\IForgetState;
- class Hash /* implements IForgetState */ {
- const GEN_RANDOM = 'random';
- const HASH_LEN = 32; // bytes not characters i.e CHR(0) .. CHR(255)
- const SALT_LEN = 32; // bytes...
- const HMAC_LEN = 32; // bytes not characters i.e CHR(0) .. CHR(255)
- const HMAC_KEY_LEN = 32; // bytes...
- /**
- * @var Hash
- */
- private static $instance = null;
- public static function instance()
- {
- if (is_null(self::$instance)) {
- self::$instance = new static();
- }
- return self::$instance;
- }
- public static function factory($hmacKey = '')
- {
- $instance = new static();
- if (!empty($hmacKey)) {
- $instance->setHmacKey($hmacKey);
- }
- return $instance;
- }
- // do not allow CHR(0) as it may confuse by being treated as a terminator
- public static function uniqueId() {
- return hash('sha256',
- uniqid() . RandomData::instance()->filteredBytes(self::SALT_LEN, 1, 255));
- }
- /**
- * Create a new hash from the supplied password
- *
- * @param type $password
- */
- public static function passwordHash($password)
- {
- return \password_hash($password, PASSWORD_DEFAULT);
- }
- /**
- * Verify Password matches
- *
- * @param type $password
- * @param type $passwordHash
- * @return boolean
- */
- public static function passwordVerify($password, $passwordHash, $throwError = true)
- {
- if (\password_verify($password, $passwordHash)) {
- return true;
- }
- else {
- if ($throwError) {
- throw new \UnexpectedValueException('Invalid Login Details', 500);
- }
- else {
- return false;
- }
- }
- }
- /**
- * HMAC - Is what you got matching either:
- * 1) what you sent out?
- * 2) from a reliable source?
- *
- * @param string $data
- * @param string $digest
- * @param string $sharedKey
- * @param boolean $throwError
- * @return boolean
- * @throws \UnexpectedValueException
- */
- public static function hmacVerify($data, $digest, $sharedKey, $throwError = true)
- {
- $hash = self::factory();
- $hash->setHmacKey($sharedKey);
- $allOk = $hash->generateHMAC($data);
- if ($allOk && $hash->curHMAC() === $digest) {
- $hash = null;
- return true;
- }
- else {
- $hash = null;
- if ($throwError) {
- throw new \UnexpectedValueException('Invalid HMAC details', 500);
- }
- else {
- return false;
- }
- }
- }
- // testing - next call will have re-initialize everything
- public static function forget() {
- self::$instance = null;
- }
- /**
- * unique identifier for this instance
- */
- private $instanceId = null;
- public function instanceId()
- {
- return $this->instanceId;
- }
- /**
- * Salt value corresponding to the curremt Hash
- * @var string
- */
- private $curSalt = '';
- public function curSalt() { return $this->curSalt; }
- public function curSaltAsHex() { return bin2hex($this->curSalt); }
- public function setSalt($salt = self::GEN_RANDOM)
- {
- if ($salt === self::GEN_RANDOM) { // zero not allowed
- $this->curSalt = RandomData::instance()->filteredBytes(self::SALT_LEN, 1, 255);
- }
- elseif (!empty($salt)) { // repeat the salt until required length
- if (strlen($salt) < self::SALT_LEN) {
- $this->curSalt = $salt;
- while (strlen($this->curSalt) < self::SALT_LEN) {
- $this->curSalt .= $salt;
- }
- $this->curSalt = substr($this->curSalt, 0, self::SALT_LEN);
- }
- else {
- $this->curSalt = $salt;
- }
- }
- else {
- throw new \UnexpectedValueException('Empty salt is not allowed', 500);
- }
- return !empty($this->curSalt);
- }
- /**
- * The hash generated using the salt
- * @var string
- */
- private $curHash = '';
- public function curHash() { return $this->curHash; }
- public function curHashAsHex() { return bin2hex($this->curHash); }
- /**
- * Generate a hash
- * @param string $string
- * @return string
- */
- public function generateHash($data, $salt = self::GEN_RANDOM)
- {
- $this->setSalt($salt);
- $this->curHash = hash('sha256', $data . $this->curSalt, true);
- return $this->curHash !== false;
- }
- /**
- * HMAC key - shared key used to verify the message is authentic
- *
- * @var string
- */
- private $curHmacKey = '';
- public function curHmacKey() { return $this->curHmacKey; }
- public function setHmacKey($keyString = self::GEN_RANDOM)
- {
- if ($keyString === self::GEN_RANDOM) { // you need to store this to use it later
- $this->curHmacKey = RandomData::instance()->filteredBytes(self::HMAC_KEY_LEN, 1, 255);
- }
- elseif (!empty($keyString)) { // pad to required length by repeating...
- if (strlen($keyString) < self::HMAC_KEY_LEN) {
- $this->curHmacKey = $keyString;
- while (strlen($this->curHmacKey) < self::HMAC_KEY_LEN) {
- $this->curHmacKey .= $keyString;
- }
- $this->curHmacKey = substr($this->curHmacKey, 0, self::HMAC_KEY_LEN);
- }
- else {
- $this->curHmacKey = $keyString;
- }
- }
- else {
- throw new \UnexpectedValueException('Empty HMAC key is not allowed', 500);
- }
- return !empty($this->curHmacKey);
- }
- /**
- * The HMAC generated using the key
- * @var string
- */
- private $curHMAC = '';
- public function curHMAC() { return $this->curHMAC; }
- public function curHMACAsHex() { return bin2hex($this->curHMAC); }
- public function generateHMAC($data, $key = '')
- {
- if (empty($data)) {
- throw new UnexpectedValueException('no data provided', 500);
- }
- if (empty($key)) {
- if (empty($this->curHmacKey)) {
- throw new UnexpectedValueException('no key available', 500);
- }
- }
- else {
- $this->setHmacKey($key);
- }
- $this->curHMAC = hash_hmac('sha256', $data, $this->curHmacKey(), true);
- return strlen($this->curHMAC) == self::HMAC_LEN;
- }
- public function __construct()
- {
- $this->instanceId = self::uniqueId();
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement