/** * Open a session. * * @param string $path * @param string $name * @return bool */ public static function open($path, $name) { /* Set some variables we need later. */ self::$_savePath = $path; self::$_name = $name; self::$_keyCookie = $name . '_secret'; /* Set current and new ID. */ if (isset($_COOKIE[$name])) { self::$_currID = $_COOKIE[$name]; } else { self::$_currID = null; } self::$_newID = phpsecRand::str(128); /* Set cookie with new session ID. */ $cookieParam = session_get_cookie_params(); setcookie($name, self::$_newID, $cookieParam['lifetime'], $cookieParam['path'], $cookieParam['domain'], $cookieParam['secure'], $cookieParam['httponly']); /* If we don't have a encryption key, create one. */ if (!isset($_COOKIE[self::$_keyCookie])) { /* Create a secret used for encryption of session. */ self::setSecret(); } else { self::$_secret = base64_decode($_COOKIE[self::$_keyCookie]); } return true; }
/** * Creates a salted hash from a string. * * @param string $str * String to hash. * * @return string * Returns hashed string, or false on error. */ public static function create($str) { switch (self::$_method) { case self::BCRYPT: $saltRnd = phpsecRand::str(22, self::$charsets['itoa64']); $salt = sprintf('$2a$%s$%s', self::$_bcrypt_cost, $saltRnd); $hash = crypt($str, $salt); break; case self::PBKDF2: $salt = phpsecRand::bytes(64); $hash = phpsecCrypt::pbkdf2($str, $salt, self::$_pbkdf2_c, self::$_pbkdf2_dkLen, self::$_pbkdf2_prf); $hash = sprintf('$pbkdf2$c=%s&dk=%s&f=%s$%s$%s', self::$_pbkdf2_c, self::$_pbkdf2_dkLen, self::$_pbkdf2_prf, base64_encode($hash), base64_encode($salt)); break; case self::SHA256: case self::SHA512: $saltRnd = phpsecRand::str(16, self::$charsets['itoa64']); $salt = sprintf('%srounds=%s$%s', self::$_method, self::$_sha2_c, $saltRnd); $hash = crypt($str, $salt); break; } if (strlen($hash) > 13) { return $hash; } return false; }
/** * Generate and save a one-time-token for a form. Used to protect against * CSRF attacks. * * @param string $name * Name of the form to generate a token for. * * @param integer $ttl * How long the token should be valid in seconds. * * @return string * The token to supply with the form data. */ public static function set($name, $ttl = 3600) { $token = phpsecRand::str(32); /* Save the token to the cahce. */ phpsecCache::cacheSet('token-' . $name, $token, $ttl); return $token; }
/** * Verify Yubikey one time password against the Yubico servers. * * @param string $otp * One time password to verify. * * @return boolean * True on valid OTP, false on invalid. If this method returns false * phpsecYubikey::$lastError will contain details. * * @see http://phpseclib.com/manual/yubikey/errors */ public static function verify($otp) { if (self::$_clientId === null || self::$_clientSecret === null) { self::$lastError = 'YUBIKEY_CLIENT_DATA_NEEDED'; return false; } if (!self::validOtp($otp)) { self::$lastError = 'YUBIKEY_INVALID_OTP'; return false; } /* Setup the data needed to make the request. */ $data['otp'] = $otp; $data['id'] = self::$_clientId; $data['nonce'] = phpsecRand::str(20); $data['timestamp'] = 1; $data['h'] = self::sign($data); /* Do the request. */ $response = self::getResponse($data); if ($response === false) { self::$lastError = 'YUBIKEY_SERVER_ERROR'; return false; } /* Check status of response. If not OK return false. */ if ($response['status'] != 'OK') { switch ($response['status']) { case 'REPLAYED_OTP': self::$lastError = 'YUBIKEY_SERVER_REPLAYED_OTP'; break; case 'REPLAYED_REQUEST': self::$lastError = 'YUBIKEY_SERVER_REPLAYED_REQUEST'; break; case 'BAD_OTP': self::$lastError = 'YUBIKEY_SERVER_BAD_OTP'; break; case 'NO_SUCH_CLIENT': self::$lastError = 'YUBIKEY_SERVER_NO_SUCH_CLIENT'; break; case 'BAD_SIGNATURE': self::$lastError = 'YUBIKEY_SERVER_BAD_SIGNATURE'; break; default: self::$lastError = 'YUBIKEY_SERVER_SAYS_NO'; break; } return false; } /* If tokens don't match return false. */ if ($response['otp'] != $otp) { self::$lastError = 'YUBIKEY_NO_MATCH'; return false; } /* Sign the request to see if it matches signature from server. */ $signature = self::sign($response); if ($signature !== $response['h']) { self::$lastError = 'YUBIKEY_BAD_SERVER_SIGNATURE'; return false; } return true; }
/** * Create a list of 64 pre shared one-time-passwords, * or a so called password card. * * This differs from phpsecOtp::generate() because passwords generated by * this function is saved permanent and can be validated on a later time. */ public static function create($length = 6, $num = 32) { $card['list'] = array(); for ($i = 0; $i < $num; $i++) { $card['list'][$i] = phpsecRand::str($length); $card['usable'][$i] = true; } $card = self::save($card); return $card['id']; }
/** * Generate a one-time-password (OTP). The password is only valid for a given time, * and must be delivered to the user instantly. The password is also only valid * for the current session. * * @param string $action * The action to generate a OTP for. This should be as specific as possible. * Used to ensure that the OTP is used for the intended action. * * @param array $data * Optional array of data that belongs to $action. Used to ensure that the action * is performed with the same data as when the OTP was generated. * * @param integer $length * OTP length. * * @param integer $ttl * Time to live for the OTP. In seconds. * * @return string * One time password that should be delivered to the user by for example email or SMS. * */ public static function generate($action, $data = '', $length = 6, $ttl = 480) { $pw = phpsecRand::str($length); $otp['pw'] = phpsecHash::create($pw); if ($data !== null) { $otp['data'] = phpsecHash::create(serialize($data)); } else { $otp['data'] = $data; } phpsecCache::cacheSet('otp-' . $action, $otp, $ttl); return $pw; }
/** * Returns a unique identifier in the format spsecified in * OpenID Authentication 2.0 protocol. * For example: 2005-05-15T17:11:51ZUNIQUE * This function is used to generate all unique tokens used by * phpSec. * @see http://openid.net/specs/openid-authentication-2_0.html * * @param integer $length * The total length of the uid. Must be above 25. */ public static function genUid($length = 50) { if ($length < 25) { self::error('Length must be longer than 25'); return false; } $timeStamp = gmdate('Y-m-d\\TH:i:se'); $randLength = $length - strlen($timeStamp); return $timeStamp . phpsecRand::str($randLength); }