* @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; } } ?>