require_once("Patterns.php");
require_once("Config.php");
require_once("Database.php");
class PasswordStore {
private $db;
const cipher = MCRYPT_RIJNDAEL_256;
const hash = MHASH_WHIRLPOOL;
const salt = "Well done. Here come the test results: \"You are a horrible person.\" That's what it says: a horrible person. We weren't even testing for that.";
public function __construct() {
$this->db = new Database();
$this->houseKeeping();
}
private function hash($string = null, $salt = null) {
if (!$salt) {
$salt = $this::salt;
}
return bin2hex(mhash($this::hash, $salt . $string));
}
private function unique() {
/* Originally found on php.net - http://php.net/manual/en/function.uniqid.php - credited to Andrew Moore 04-Dec-2009 04:45
Should be replaced with PECL module UUID */
return sprintf('%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
// 32 bits for "time_low"
mt_rand(0, 0xffff), mt_rand(0, 0xffff),
// 16 bits for "time_mid"
mt_rand(0, 0xffff),
// 16 bits for "time_hi_and_version",
// four most significant bits holds version number 4
mt_rand(0, 0x0fff) | 0x4000,
// 16 bits, 8 bits for "clk_seq_hi_res",
// 8 bits for "clk_seq_low",
// two most significant bits holds zero and one for variant DCE1.1
mt_rand(0, 0x3fff) | 0x8000,
// 48 bits for "node"
mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff)
);
}
private function getInitVector($userId = null, $credentialId = null) {
if ($userId && $credentialId) {
/* sql fetch init vector from credential table */
} else {
$size = mcrypt_get_iv_size($this::cipher, MCRYPT_MODE_CFB);
$iv = mcrypt_create_iv($size, MCRYPT_DEV_RANDOM);
}
}
private function validSession($userId, $session) {
$sessionHash = $this->hash($userId . $session);
$sqlQuery = "SELECT * FROM session WHERE sessionHash = '%sessionHash'";
$params = array("%sessionHash" => $sessionHash);
$this->db->prepare($sqlQuery, $params);
$resultId = $this->db->execute();
if ($this->db->numRows($resultId) == 1) {
return true;
} else {
return false;
}
}
private function houseKeeping() {
$sqlQuery = "DELETE FROM session WHERE sessionExpires < %now";
$params = array("%now", time());
$this->db->prepare($sqlQuery, $params);
$this->db->execute();
}
public function createSession($userId, $pw = null, $sessionExpires = null) {
$sqlQuery = "SELECT * FROM userauth WHERE uniqueId = '%userId'";
$params = array("%userId" => $userId);
$this->db->prepare($sqlQuery, $params);
$resultId = $this->db->execute();
if ($this->db->numRows($resultId) == 1) {
$row = $this->db->fetchAssoc($resultId);
if ($row["hashedPassword"] == $this->hash($pw)) {
$session = $this->unique();
if (!isset($sessionExpires) || !is_numeric($sessionExpires)) {
$sessionExpires = 3600; //hardcoding is bad!
}
$sessionExpires = time() + $sessionExpires;
$encryptionKey = $this->hash($pw, strrev($this::salt));
$sessionHash = $this->hash($userId . $session);
$sqlQuery = "INSERT INTO session
(sessionHash, encryptionKey, sessionExpires) VALUES
('%sessionHash', '%encryptionKey', %sessionExpires)";
$params = array("%sessionHash" => $sessionHash, "%encryptionKey" => $encryptionKey, "%sessionExpires" => $sessionExpires);
$this->db->prepare($sqlQuery, $params);
$this->db->execute();
return $session;
} else {
// password bad;
}
} else {
// no or duplicate users
}
}
public function expireSession($userId, $session) {
$sessionHash = $this->hash($userId . $session);
$sqlQuery = "DELETE FROM session WHERE sessionHash = '%sessionHash'";
$params = array("%sessionHash" => $sessionHash);
$this->db->prepare($sqlQuery, $params);
$this->db->execute();
}
public function registerUser($pw = null) {
if ($pw) {
$unique = $this->unique();
$pw = $this->hash($pw);
echo strlen($pw);
$sqlQuery = "INSERT INTO userauth
(uniqueId, hashedPassword, createTime) VALUES
('%uniqueId', '%hashedPassword', %createTime)";
$params = array("%uniqueId" => $unique, "%hashedPassword" => $pw, "%createTime" => time());
$this->db->prepare($sqlQuery, $params);
$this->db->execute();
return $unique;
}
}
public function updatePassword($userId, $session, $pw = null) {
/* foreach credential stored against userId, decrypt with existing key stored in session, and reencrypt using new key
$key = $this->hash($pw, strrev($this::salt))
*/
}
public function enumerateCredentials($userId, $session) {
if ($this->validSession($userId, $session) {
/* select * from credentials where userId = userId */
}
}
public function createCredential($userId, $session, $cred = null, $pw = null) {
if ($this->validSession($userId, $session) {
}
}
public function returnCredential($userId, $session, $cred = null, $pw = null) {
if ($this->validSession($userId, $session) {
}
/* get credential $cred for $userId
get decryption key for $session
decrypt $cred using decryption key */
//$cleartext = mcrypt_decrypt(MCRYPT_RIJNDAEL_256,
}
public function deleteCredential($userId, $session, $cred = null) {
}
public function updateCredential($userId, $session, $cred = null, $pw = null) {
}
}