legacy open qoob framework

php mvc framework for generating dynamic websites.

qoob/utils/crypto/hash.php


<?php
/**
 * hash class
 * functions creating password hashes.
 * based on ideas from Nils Reimers (www.php-einfach.de)
 * ImprovedHashAlgorithm (IHA) released open-source under 
 * the GNU Lesser General Public License version 2.1
 * 
 * @author xero harrison <x@xero.nu>
 * @copyright (cc) creative commons - attribution-shareAlike 3.0 unported
 * @version 2.3
 * @package qoob
 * @subpackage utils.crypto
 * @category cryptography
 */
class hash {
	/**
	 * @var string $salt an optional string used for encryption
	 */
	private $salt = "";
	/**
	 * @var boolean $sha1 a boolean if true the sha1 algorithm will be used if false md5 is used.
	 */
	private $sha1 = false;
	/**
	 * @var int $rounds the number of times the hash will be key-stretched.  a higher value yealds increased security but at the cost of increased calculation time.
	 */
	private $rounds = 2500;
	/**
	 * @var int $saltLength the length of the salt string
	 */
	private $saltLength = 8;
	/**
	 * make hash function
	 * returns a strong hash value from a weak password.
	 * 
	 * @example $this->library(qoob_types::utility, "hash", "crypto/");
	 * $this->hash->saltLength = 10;
	 * $this->hash->salt = "aCgbEDzq9h";
	 * $this->hash->sha1 = true;
	 * $this->hash->rounds = 5000;
	 * $hash = $this->hash->make($pass);
	 * 	
	 * // $hash would be something like:
	 * // gAATiA;aCgbEDzq9h;iPl9xBKgfBGtE6iR4pQU1g5VgKs=
	 * 
	 * @param string $pass
	 * @return string
	 */
	public function make($pass) {
		return $this->generateHash($pass);
	}
	/**
	 * compare function
	 * checks if the value of $pass belongs to the value of $hash.
	 * 
	 * @todo what do you do when the hash is not in the correct format?
	 *       bacause false is if the hash and pass dont match... ?:P
	 * 
	 * @param string $pass
	 * @param string $hash
	 * @return boolean
	 */
	public function compare($pass, $hash) {
		if(substr_count($hash, ";") != 2) {
			return false;
		}
		list($header,$salt,$value) = explode(";", $hash);

		$this->salt = $salt;
		$header = base64_decode($header);
		$this->rounds = ord($header{1})<<16 | ord($header{2})<<8 | ord($header{3});
		$flag = ord($header{0});
		$this->sha1 = ((($flag&0x80)>>7) == 1);

		return ($this->generateHash($pass) == $hash);
	}
	/**
	 * benchmark function
	 * makes a benchmark of the key stretching method.
	 * $times is the number of hashes to preform and average.
	 * 
	 * @param int $times
	 * @return string
	 */
	public function benchmark($times = 10) {
		$str = "generated $times hashes ";
		
		$start = (double)microtime() + time();
		
		for($i=0;$i<$times;$i++) {
			$this->make("open_qoob_framework");
		}
		
		$end = (double)microtime() + time();
		$diff = round($end-$start, 4);
		
		return $str."in $diff seconds; average ".($diff/$times)." per hash.";
	}
	/**
	 * variable setter magic method
	 * 
	 * @param string $var
	 * @param string $val
	 */
	public function __set($var, $val) {
		$this->$var = $val;
	}
	/**
	 * variable getter magic method
	 * 
	 * @param string $var
	 * @return mixed
	 */
	public function __get($var) {
		return (isset($this->$var)) ? $this->$var : false;
	}
	/**
	 * hash generation function
	 * generates the hash of a password. the returned string is a
	 * semicolon deliminated string in header;salt;key format.
	 * an install unique string in your qoob app config is used
	 * as an added layer of security.
	 * 
	 * @internal
	 * @param $pass
	 */
	private function generateHash($pass) {
		if (empty($this->salt)) {
			$this->salt = $this->generateSalt();
		}
		$header = $this->generateHeader();
		// --- hashpass is set in the app config
		$key = $this->salt.$pass.library::catalog()->hashpass;
		
		if($this->sha1 == true && function_exists("sha1")) {
			$key = sha1($key);
		} else {
			$key = md5($key);
		}
		
		$key = base64_encode(pack("H*", $this->keyStretching($key)));
		
		return $header.";".$this->salt.";".$key;
	}
	/**
	 * salt generation function
	 * this creates a random salt based on the current time
	 * 
	 * @return string
	 */
	private function generateSalt() {
		$salt = base64_encode(pack("H*", md5(microtime())));
		return substr($salt, 0, $this->saltLength);
	}
	/**
	 * header generation function
	 * used to indentify what settings were used to generate the hash.
	 * 
	 * @internal
	 * @return string
	 */
	private function generateHeader() {
		$flag = (($this->sha1 == true && function_exists("sha1"))?1:0)<<7;
		return substr(base64_encode(pack("N*", $this->rounds | $flag<<24)), 0, 6);
	}
	/**
	 * key stretching function
	 * encrypting the key repeatedly makes cracking a password much more time consuming.
	 * 
	 * @internal
	 * @param string $key
	 * @return string
	 */
	private function keyStretching($key) {
		if($this->sha1 == true && function_exists("sha1")) {
			for ($i=0;$i<$this->rounds;++$i) {
				$key = sha1($key);
			}
		} else {
			for ($i=0;$i<$this->rounds;++$i) {
				$key = md5($key);
			}
		}
		return $key;
	}
}

?>

Download

raw zip tar