/** * Hash then encrypt a password * * @param string $password - The user's password * @param Key $secret_key - The master key for all passwords * @return string */ public static function hash($password, \ParagonIE\Halite\Contract\CryptoKeyInterface $secret_key) { // First, let's calculate the hash $hashed = \Sodium\crypto_pwhash_scryptsalsa208sha256_str($password, \Sodium\CRYPTO_PWHASH_SCRYPTSALSA208SHA256_OPSLIMIT_INTERACTIVE, \Sodium\CRYPTO_PWHASH_SCRYPTSALSA208SHA256_MEMLIMIT_INTERACTIVE); // Now let's encrypt the result return Symmetric::encrypt($hashed, $secret_key); }
/** * Encrypt a string using asymmetric cryptography * Wraps Symmetric::encrypt() * * @param string $source Plaintext * @param string $ourPrivateKey Our private key * @param string $theirPublicKey Their public key * @param boolean $raw Don't hex encode the output? * * @return string */ public static function encrypt($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::encrypt($source, $ecdh, $raw); unset($ecdh); return $ciphertext; }
/** * Hash then encrypt a password * * @param string $password - The user's password * @param EncryptionKey $secret_key - The master key for all passwords * @return string */ public static function hash($password, KeyInterface $secret_key) { if (!$secret_key instanceof EncryptionKey) { throw new \ParagonIE\Halite\Alerts\InvalidKey('Argument 2: Expected an instance of EncryptionKey'); } // First, let's calculate the hash $hashed = \Sodium\crypto_pwhash_scryptsalsa208sha256_str($password, \Sodium\CRYPTO_PWHASH_SCRYPTSALSA208SHA256_OPSLIMIT_INTERACTIVE, \Sodium\CRYPTO_PWHASH_SCRYPTSALSA208SHA256_MEMLIMIT_INTERACTIVE); // Now let's encrypt the result return Crypto::encrypt($hashed, $secret_key); }
/** * Encrypt a string using asymmetric cryptography * Wraps SymmetricCrypto::encrypt() * * @param string $source Plaintext * @param EncryptionSecretKey $ourPrivateKey Our private key * @param EncryptionPublicKey $theirPublicKey Their public key * @param boolean $raw Don't hex encode the output? * * @return string * * @throws CryptoException\InvalidKey */ public static function encrypt($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::encrypt($source, $ecdh, $raw); unset($ecdh); return $ciphertext; }
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); } }
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); } }
/** * Store a value in an encrypted cookie * * @param string $name * @param mixed $value * @param int $expire (defaults to 0) * @param string $path (defaults to '/') * @param string $domain (defaults to NULL) * @param bool $secure (defaults to TRUE) * @param bool $httponly (defaults to TRUE) * @return bool */ public function store($name, $value, $expire = 0, $path = '/', $domain = null, $secure = true, $httponly = true) { return \setcookie($name, Crypto::encrypt(\json_encode($value), $this->key), $expire, $path, $domain, $secure, $httponly); }
/** * @param string $token * * @return string * * @throws \ParagonIE\Halite\Alerts\InvalidKey * @throws \ParagonIE\Halite\Alerts\InvalidType */ public function encryptToken($token = '') { $encrypted = Symmetric::encrypt($token, $this->key); return $encrypted; }
public function it_fails_when_the_user_tuple_and_random_verify_do_not_match($authenticationMapper, $userMapper) { $systemKey = $this->systemEncryptionKey; $userKey = new EncryptionKey($this->authenticationData->getSessionKey()); $hashCookieName = hash_hmac('sha256', $this->authenticationData->getSessionKey() . $this->authenticationData->getUsername(), $systemKey); $userTuple = base64_encode(Crypto::encrypt($this->authenticationData->getUserId() . ":" . $hashCookieName, $systemKey)); $hashCookieContents = base64_encode(Crypto::encrypt(time() . ':' . 2 . ':' . $this->authenticationData->getUsername(), $userKey)); $_COOKIE[AuthenticationService::COOKIE_USER] = $userTuple; $_COOKIE[AuthenticationService::COOKIE_HASH_PREFIX . $hashCookieName] = $hashCookieContents; $_COOKIE[AuthenticationService::COOKIE_VERIFY_A] = hash_hmac('sha256', $userTuple, $systemKey); $_COOKIE[AuthenticationService::COOKIE_VERIFY_B] = hash_hmac('sha256', $hashCookieContents, $userKey) . 'b'; $userMapper->getUser(Argument::any())->shouldNotBeCalled(); $this->getIdentity()->shouldBe(null); }
/** * @covers Symmetric::unpackMessageForDecryption() */ public function testUnpack() { $key = new EncryptionKey(new HiddenString(\str_repeat('A', 32))); // Randomly sized plaintext $size = \Sodium\randombytes_uniform(1023) + 1; $plaintext = \Sodium\randombytes_buf($size); $message = Symmetric::encrypt(new HiddenString($plaintext), $key, true); // Let's unpack our message $unpacked = Symmetric::unpackMessageForDecryption($message); // Now to test our expected results! $this->assertSame(Util::safeStrlen($unpacked[0]), Halite::VERSION_TAG_LEN); $this->assertTrue($unpacked[1] instanceof \ParagonIE\Halite\Symmetric\Config); $config = $unpacked[1]; if ($config instanceof \ParagonIE\Halite\Symmetric\Config) { $this->assertSame(Util::safeStrlen($unpacked[2]), $config->HKDF_SALT_LEN); $this->assertSame(Util::safeStrlen($unpacked[3]), \Sodium\CRYPTO_STREAM_NONCEBYTES); $this->assertSame(Util::safeStrlen($unpacked[4]), Util::safeStrlen($message) - (Halite::VERSION_TAG_LEN + $config->HKDF_SALT_LEN + \Sodium\CRYPTO_STREAM_NONCEBYTES + $config->MAC_SIZE)); $this->assertSame(Util::safeStrlen($unpacked[5]), $config->MAC_SIZE); } else { $this->fail('Cannot continue'); } }
/** * Set the auth session cookies that can be used to regenerate the session on subsequent visits * * @param AuthenticationRecordInterface $authentication */ private function setSessionCookies(AuthenticationRecordInterface $authentication) { $systemKey = new EncryptionKey($this->systemEncryptionKey); $userKey = new EncryptionKey($authentication->getSessionKey()); $hashCookieName = hash_hmac('sha256', $authentication->getSessionKey() . $authentication->getUsername(), $systemKey); $userTuple = base64_encode(Crypto::encrypt($authentication->getUserId() . ":" . $hashCookieName, $systemKey)); $hashCookieContents = base64_encode(Crypto::encrypt(time() . ':' . $authentication->getUserId() . ':' . $authentication->getUsername(), $userKey)); // // 1 - Set the cookie that contains the user ID, and hash cookie name // $this->setCookie(self::COOKIE_USER, $userTuple); // // 2 - Set the cookie with random name, that contains a verification hash, that's a function of the switching session key // $this->setCookie(self::COOKIE_HASH_PREFIX . $hashCookieName, $hashCookieContents); // // 3 - Set the sign cookie, that acts as a safeguard against tampering // $this->setCookie(self::COOKIE_VERIFY_A, hash_hmac('sha256', $userTuple, $systemKey)); // // 4 - Set a sign cookie for the hashCookie's values // $this->setCookie(self::COOKIE_VERIFY_B, hash_hmac('sha256', $hashCookieContents, $userKey)); }
/** * Perform encryption * * @param $field * @return string */ public static function encrypt($field) { $key = KeyFactory::loadEncryptionKey(config('laracrypt.path')); return Crypto::encrypt($field, $key); }
/** * Get the user's two-factor authentication secret * * @param int $userID * @return bool */ public function resetTwoFactorSecret(int $userID) : bool { $state = State::instance(); $this->db->beginTransaction(); $secret = \random_bytes(20); $this->db->update('airship_users', ['totp_secret' => Symmetric::encrypt($secret, $state->keyring['auth.password_key'])], ['userid' => $userID]); return $this->db->commit(); }
/** * Let's do an automatic login * * @param string $token * @param string $uid_idx * @param string $token_idx * @return bool * @throws LongTermAuthAlert (only in debug mode) * @throws \TypeError */ protected function doAutoLogin(string $token, string $uid_idx, string $token_idx) : bool { if (!$this->airship_auth instanceof Authentication) { $this->tightenSecurityBolt(); } $state = State::instance(); try { $userId = $this->airship_auth->loginByToken($token); \Sodium\memzero($token); if (!$this->verifySessionCanary($userId, false)) { return false; } // Regenerate session ID: Session::regenerate(true); // Set session variable $_SESSION[$uid_idx] = $userId; $autoPilot = Gears::getName('AutoPilot'); if (IDE_HACKS) { // We're using getName(), this is just to fool IDEs. $autoPilot = new AutoPilot(); } $httpsOnly = (bool) $autoPilot::isHTTPSConnection(); // Rotate the authentication token: Cookie::setcookie($token_idx, Symmetric::encrypt($this->airship_auth->rotateToken($token, $userId), $state->keyring['cookie.encrypt_key']), \time() + ($state->universal['long-term-auth-expire'] ?? self::DEFAULT_LONGTERMAUTH_EXPIRE), '/', '', $httpsOnly ?? false, true); return true; } catch (LongTermAuthAlert $e) { $state = State::instance(); // Let's wipe our long-term authentication cookies Cookie::setcookie($token_idx, null, 0, '/', '', $httpsOnly ?? false, true); // Let's log this incident if (\property_exists($this, 'log')) { $this->log($e->getMessage(), LogLevel::CRITICAL, ['exception' => \Airship\throwableToArray($e)]); } else { $state->logger->log(LogLevel::CRITICAL, $e->getMessage(), ['exception' => \Airship\throwableToArray($e)]); } // In debug mode, re-throw the exception: if ($state->universal['debug']) { throw $e; } } return false; }