/** * Decrypt then verify a password * * @param string $password - The user-provided password * @param string $stored - The encrypted password hash * @param Key $secret_key - The master key for all passwords * @return boolean */ public static function verify($password, $stored, \ParagonIE\Halite\Contract\CryptoKeyInterface $secret_key) { // First let's decrypt the hash $hash_str = Symmetric::decrypt($stored, $secret_key); // And now to verify the hash return \Sodium\crypto_pwhash_scryptsalsa208sha256_str_verify($hash_str, $password); }
/** * Decrypt a string using asymmetric cryptography * Wraps Symmetric::decrypt() * * @param string $source Ciphertext * @param string $ourPrivateKey Our private key * @param string $theirPublicKey Their public key * @param boolean $raw Don't hex decode the input? * * @return string */ public static function decrypt($source, Contract\CryptoKeyInterface $ourPrivateKey, Contract\CryptoKeyInterface $theirPublicKey, $raw = false) { list($secret, $public) = self::judgeKeys($ourPrivateKey, $theirPublicKey); $ecdh = new Key(self::getSharedSecret($secret, $public), false, false); $ciphertext = Symmetric::decrypt($source, $ecdh, $raw); unset($ecdh); return $ciphertext; }
/** * Decrypt then verify a password * * @param string $password - The user-provided password * @param string $stored - The encrypted password hash * @param EncryptionKey $secret_key - The master key for all passwords * @return boolean */ public static function verify($password, $stored, KeyInterface $secret_key) { if (!$secret_key instanceof EncryptionKey) { throw new \ParagonIE\Halite\Alerts\InvalidKey('Argument 3: Expected an instance of EncryptionKey'); } // First let's decrypt the hash $hash_str = Crypto::decrypt($stored, $secret_key); // Upon successful decryption, verify the password is correct return \Sodium\crypto_pwhash_scryptsalsa208sha256_str_verify($hash_str, $password); }
/** * Decrypt a string using asymmetric cryptography * Wraps SymmetricCrypto::decrypt() * * @param string $source Ciphertext * @param EncryptionSecretKey $ourPrivateKey Our private key * @param EncryptionPublicKey $theirPublicKey Their public key * @param boolean $raw Don't hex decode the input? * * @return string * * @throws CryptoException\InvalidKey */ public static function decrypt($source, Contract\KeyInterface $ourPrivateKey, Contract\KeyInterface $theirPublicKey, $raw = false) { if (!$ourPrivateKey instanceof EncryptionSecretKey) { throw new CryptoException\InvalidKey('Argument 2: Expected an instance of EncryptionSecretKey'); } if (!$theirPublicKey instanceof EncryptionPublicKey) { throw new CryptoException\InvalidKey('Argument 3: Expected an instance of EncryptionPublicKey'); } $ecdh = new EncryptionKey(self::getSharedSecret($ourPrivateKey, $theirPublicKey)); $ciphertext = SymmetricCrypto::decrypt($source, $ecdh, $raw); unset($ecdh); return $ciphertext; }
/** * @covers Symmetric::encrypt() */ public function testEncryptFail() { $key = new EncryptionKey(\str_repeat('A', 32)); $message = Symmetric::encrypt('test message', $key, true); $r = \Sodium\randombytes_uniform(\mb_strlen($message, '8bit')); $message[$r] = \chr(\ord($message[$r]) ^ 1 << \Sodium\randombytes_uniform(8)); try { $plain = Symmetric::decrypt($message, $key, true); $this->assertEquals($plain, $message); $this->fail('This should have thrown an InvalidMessage exception!'); } catch (CryptoException\InvalidMessage $e) { $this->assertTrue($e instanceof CryptoException\InvalidMessage); } }
public function testEncryptFail() { $key = new \ParagonIE\Halite\Key(\str_repeat('A', 32)); $message = Symmetric::encrypt('test message', $key, true); $r = \Sodium\randombytes_uniform(\mb_strlen($message, '8bit')); $message[$r] = \chr(\ord($message[$r]) ^ 1 << \Sodium\randombytes_uniform(8)); try { $plain = Symmetric::decrypt($message, $key, true); $this->assertEquals($plain, $message); throw new Exception('ERROR: THIS SHOULD ALWAYS FAIL'); } catch (CryptoException\InvalidMessage $e) { $this->assertTrue($e instanceof CryptoException\InvalidMessage); } }
/** * Store a value in an encrypted cookie * * @param string $name * @return mixed (typically an array) */ public function fetch($name) { if (!isset($_COOKIE[$name])) { return null; } try { $decrypted = Crypto::decrypt($_COOKIE[$name], $this->key); if (empty($decrypted)) { return null; } return \json_decode($decrypted, true); } catch (InvalidMessage $e) { return; } }
/** * @param string $token * * @return string * * @throws \ParagonIE\Halite\Alerts\InvalidKey * @throws \ParagonIE\Halite\Alerts\InvalidMessage * @throws \ParagonIE\Halite\Alerts\InvalidType */ public function decryptToken($token = '') { $decyrpted = Symmetric::decrypt($token, $this->key); return $decyrpted; }
/** * Rifle through 4 cookies, ensuring that all details line up. If they do, we accept that the cookies authenticate * a specific user. * * Some notes: * * - COOKIE_VERIFY_A is a do-not-decrypt check of COOKIE_USER * - COOKIE_VERIFY_B is a do-not-decrypt check of the random-named-cookie specified by COOKIE_USER * - COOKIE_USER has its contents encrypted by the system key * - the random-named-cookie has its contents encrypted by the user key * * @see self::setSessionCookies * @return User|null */ public function getIdentity() { if ($this->identity) { return $this->identity; } if (!isset($_COOKIE[self::COOKIE_VERIFY_A])) { return null; } if (!isset($_COOKIE[self::COOKIE_USER])) { return null; } $systemKey = new EncryptionKey($this->systemEncryptionKey); $verificationCookie = $_COOKIE[self::COOKIE_VERIFY_A]; $hashPass = hash_equals(hash_hmac('sha256', $_COOKIE[self::COOKIE_USER], $systemKey), $verificationCookie); // // 1. Is the verify cookie still equivalent to the user cookie, if so, do not decrypt // if (!$hashPass) { return null; } // // 2. If the user cookie was not tampered with, decrypt its contents with the system key // try { $userTuple = Crypto::decrypt(base64_decode($_COOKIE[self::COOKIE_USER]), $systemKey); if (strpos($userTuple, ':') === false) { throw new \Exception(); } // paranoid, make sure we have everything we need @(list($cookieUserId, $hashCookieSuffix) = @explode(":", $userTuple, 2)); if (!isset($cookieUserId) || !isset($hashCookieSuffix) || !is_numeric($cookieUserId) || !trim($hashCookieSuffix)) { throw new \Exception(); } /** @var AuthenticationRecordInterface $auth */ if (!($auth = $this->authenticationProvider->findByUserId($cookieUserId))) { throw new \Exception(); } $hashCookieName = self::COOKIE_HASH_PREFIX . $hashCookieSuffix; // // 2. Check the hashCookie for corroborating data // if (!isset($_COOKIE[$hashCookieName])) { throw new \Exception(); } $userKey = new EncryptionKey($auth->getSessionKey()); $hashPass = hash_equals(hash_hmac('sha256', $_COOKIE[$hashCookieName], $userKey), $_COOKIE[self::COOKIE_VERIFY_B]); if (!$hashPass) { throw new \Exception(); } // // 3. Decrypt the hash cookie with the user key // $hashedCookieContents = Crypto::decrypt(base64_decode($_COOKIE[$hashCookieName]), $userKey); if (!substr_count($hashedCookieContents, ':') == 2) { throw new \Exception(); } list(, $hashedUserId, $hashedUsername) = explode(':', $hashedCookieContents); if ($hashedUserId != $cookieUserId) { throw new \Exception(); } if ($hashedUsername != $auth->getUsername()) { throw new \Exception(); } $this->purgeHashCookies($hashCookieName); // // 4. Cookies check out - it's up to the user provider now // $user = $this->userProvider->getUser($auth->getUserId()); if ($user) { $this->setIdentity($user); return $this->identity; } } catch (\Exception $x) { $this->purgeHashCookies(); } return null; }
/** * Perform decryption * * @param $text * @return mixed */ public static function decrypt($text) { $key = KeyFactory::loadEncryptionKey(config('laracrypt.path')); return Crypto::decrypt($text, $key); }
/** * Get the user's two-factor authentication secret * * @param int $userID * @return string */ public function getTwoFactorSecret(int $userID) : string { $secret = $this->db->cell('SELECT totp_secret FROM airship_users WHERE userid = ?', $userID); if (empty($secret)) { return ''; } $state = State::instance(); return Symmetric::decrypt($secret, $state->keyring['auth.password_key']); }
/** * Are we logged in to a user account? * * @return bool */ public function isLoggedIn() : bool { if (!$this->airship_auth instanceof Authentication) { $this->tightenSecurityBolt(); } $state = State::instance(); if (!empty($_SESSION['userid'])) { // We're logged in! if ($this instanceof Landing && $this->config('password-reset.logout')) { return $this->verifySessionCanary($_SESSION['userid']); } return true; } elseif (isset($_COOKIE['airship_token'])) { // We're not logged in, but we have a long-term // authentication token, so we should do an automatic // login and, if successful, respond affirmatively. $token = Symmetric::decrypt($_COOKIE['airship_token'], $state->keyring['cookie.encrypt_key']); if (!empty($token)) { return $this->doAutoLogin($token, 'userid', 'airship_token'); } } return false; }