コード例 #1
0
ファイル: AsymmetricTest.php プロジェクト: emarref/jwt
 public function testVerify()
 {
     $value = 'value';
     $signature = 'signature';
     $publicKey = 'public_key';
     $encryptedValue = 'encrypted_value';
     $this->encryption->setPublicKey($publicKey);
     $this->algorithm->expects($this->once())->method('verify')->with($value, $signature, $publicKey)->will($this->returnValue($encryptedValue));
     $this->encryption->verify($value, $signature);
 }
コード例 #2
0
ファイル: TreeUpdate.php プロジェクト: paragonie/airship
 /**
  * This method stores the necessary bits of data in this object.
  *
  * @param Channel $chan
  * @param array $updateData
  * @return void
  * @throws CouldNotUpdate
  * @throws NoSupplier
  */
 protected function unpackMessageUpdate(Channel $chan, array $updateData)
 {
     // This is the JSON message from the tree node, stored as an array:
     $this->updateMessage = $updateData;
     if ($this->isPackageUpdate() || $this->isAirshipUpdate()) {
         // These aren't signed for updating the tree.
         return;
     }
     // We need a precise format:
     $dateGen = (new \DateTime($this->stored['date_generated']))->format(\AIRSHIP_DATE_FORMAT);
     $messageToSign = ['action' => $this->action, 'date_generated' => $dateGen, 'public_key' => $updateData['public_key'], 'supplier' => $updateData['supplier'], 'type' => $updateData['type']];
     try {
         $this->supplier = $this->loadSupplier($chan, $updateData);
     } catch (NoSupplier $ex) {
         if (!$this->isNewSupplier) {
             throw $ex;
         }
     }
     // If this isn't a new supplier, we need to verify the key
     if ($this->isNewSupplier) {
         return;
     }
     if ($updateData['master'] === null) {
         throw new CouldNotUpdate(\__('The master data is NULL, but the supplier exists.'));
     }
     $master = \json_decode($updateData['master'], true);
     foreach ($this->supplier->getSigningKeys() as $supKey) {
         // Yes, this is (in fact) a SignaturePublicKey:
         if (IDE_HACKS) {
             $supKey['key'] = new SignaturePublicKey();
         }
         if ($supKey['type'] !== 'master') {
             continue;
         }
         $pub = \Sodium\bin2hex($supKey['key']->getRawKeyMaterial());
         // Is this the key we're looking for?
         if (\hash_equals($pub, $master['public_key'])) {
             // Store the public key
             $this->supplierMasterKeyUsed = $supKey['key'];
             break;
         }
     }
     if (empty($this->supplierMasterKeyUsed)) {
         throw new CouldNotUpdate(\__('The provided public key does not match any known master key.'));
     }
     $encoded = \json_encode($messageToSign);
     if (!Asymmetric::verify($encoded, $this->supplierMasterKeyUsed, $master['signature'])) {
         throw new CouldNotUpdate(\__('Invalid signature for this master key.'));
     }
 }
コード例 #3
0
ファイル: AirBrake.php プロジェクト: paragonie/airship
 /**
  * Register a failed login attempt
  *
  * @param string $username
  * @param string $ip
  * @param int $numFailures
  * @param HiddenString|null $password
  * @return bool
  */
 public function registerLoginFailure(string $username, string $ip, int $numFailures = 0, HiddenString $password = null) : bool
 {
     $logAfter = $this->config['log-after'] ?? null;
     if (!\is_null($logAfter)) {
         $logAfter = (int) $logAfter;
     }
     $publicKey = (string) ($this->config['log-public-key'] ?? '');
     $this->db->beginTransaction();
     $inserts = ['action' => self::ACTION_LOGIN, 'occurred' => (new \DateTime())->format(\AIRSHIP_DATE_FORMAT), 'username' => $username, 'ipaddress' => $ip, 'subnet' => $this->getSubnet($ip)];
     if (\is_int($logAfter) && !empty($publicKey)) {
         if ($numFailures >= $logAfter) {
             // Encrypt the password guess with the admin's public key
             $inserts['sealed_password'] = Asymmetric::seal($password->getString(), $this->getLogPublicKey($publicKey));
         }
     }
     $this->db->insert('airship_failed_logins', $inserts);
     return $this->db->commit();
 }
コード例 #4
0
ファイル: Account.php プロジェクト: paragonie/airship
 /**
  * Handle user authentication
  *
  * @param array $post
  */
 protected function processLogin(array $post = [])
 {
     $state = State::instance();
     if (empty($post['username']) || empty($post['passphrase'])) {
         $this->lens('login', ['post_response' => ['message' => \__('Please fill out the form entirely'), 'status' => 'error']]);
     }
     $airBrake = Gears::get('AirBrake');
     if (IDE_HACKS) {
         $airBrake = new AirBrake();
     }
     if ($airBrake->failFast($post['username'], $_SERVER['REMOTE_ADDR'])) {
         $this->lens('login', ['post_response' => ['message' => \__('You are doing that too fast. Please wait a few seconds and try again.'), 'status' => 'error']]);
     } elseif (!$airBrake->getFastExit()) {
         $delay = $airBrake->getDelay($post['username'], $_SERVER['REMOTE_ADDR']);
         if ($delay > 0) {
             \usleep($delay * 1000);
         }
     }
     try {
         $userID = $this->airship_auth->login($post['username'], new HiddenString($post['passphrase']));
     } catch (InvalidMessage $e) {
         $this->log('InvalidMessage Exception on Login; probable cause: password column was corrupted', LogLevel::CRITICAL, ['exception' => \Airship\throwableToArray($e)]);
         $this->lens('login', ['post_response' => ['message' => \__('Incorrect username or passphrase. Please try again.'), 'status' => 'error']]);
     }
     if (!empty($userID)) {
         $userID = (int) $userID;
         $user = $this->acct->getUserAccount($userID);
         if ($user['enable_2factor']) {
             if (empty($post['two_factor'])) {
                 $post['two_factor'] = '';
             }
             $gauth = $this->twoFactorPreamble($userID);
             $checked = $gauth->validateCode($post['two_factor'], \time());
             if (!$checked) {
                 $fails = $airBrake->getFailedLoginAttempts($post['username'], $_SERVER['REMOTE_ADDR']) + 1;
                 // Instead of the password, seal a timestamped and
                 // signed message saying the password was correct.
                 // We use a signature with a key local to this Airship
                 // so attackers can't just spam a string constant to
                 // make the person decrypting these strings freak out
                 // and assume the password was compromised.
                 //
                 // False positives are bad. This gives the sysadmin a
                 // surefire way to reliably verify that a log entry is
                 // due to two-factor authentication failing.
                 $message = '**Note: The password was correct; ' . ' invalid 2FA token was provided.** ' . (new \DateTime('now'))->format(\AIRSHIP_DATE_FORMAT);
                 $signed = Base64UrlSafe::encode(Asymmetric::sign($message, $state->keyring['notary.online_signing_key'], true));
                 $airBrake->registerLoginFailure($post['username'], $_SERVER['REMOTE_ADDR'], $fails, new HiddenString($signed . $message));
                 $this->lens('login', ['post_response' => ['message' => \__('Incorrect username or passphrase. Please try again.'), 'status' => 'error']]);
             }
         }
         if ($user['session_canary']) {
             $_SESSION['session_canary'] = $user['session_canary'];
         } elseif ($this->config('password-reset.logout')) {
             $_SESSION['session_canary'] = $this->acct->createSessionCanary($userID);
         }
         // Regenerate session ID:
         Session::regenerate(true);
         $_SESSION['userid'] = (int) $userID;
         if (!empty($post['remember'])) {
             $autoPilot = Gears::getName('AutoPilot');
             if (IDE_HACKS) {
                 $autoPilot = new AutoPilot();
             }
             $httpsOnly = (bool) $autoPilot::isHTTPSConnection();
             Cookie::setcookie('airship_token', Symmetric::encrypt($this->airship_auth->createAuthToken($userID), $state->keyring['cookie.encrypt_key']), \time() + ($state->universal['long-term-auth-expire'] ?? self::DEFAULT_LONGTERMAUTH_EXPIRE), '/', $state->universal['session_config']['cookie_domain'] ?? '', $httpsOnly ?? false, true);
         }
         \Airship\redirect($this->airship_cabin_prefix);
     } else {
         $fails = $airBrake->getFailedLoginAttempts($post['username'], $_SERVER['REMOTE_ADDR']) + 1;
         // If the server is setup (with an EncryptionPublicKey) and the
         // number of failures is above the log threshold, this will
         // encrypt the password guess with the public key so that only
         // the person in possession of the secret key can decrypt it.
         $airBrake->registerLoginFailure($post['username'], $_SERVER['REMOTE_ADDR'], $fails, new HiddenString($post['passphrase']));
         $this->lens('login', ['post_response' => ['message' => \__('Incorrect username or passphrase. Please try again.'), 'status' => 'error']]);
     }
 }
コード例 #5
0
ファイル: HTTP.php プロジェクト: paragonie/airship-barge
 /**
  * Get/verify/parse a JSON response
  *
  * The _server_ is the one that signs the message.
  * We're just verifying the Ed25519 signature.
  *
  * @param string $url
  * @param SignaturePublicKey $publicKey
  * @param array $args
  * @param array $options
  * @return array
  * @throws \Exception
  */
 public static function postSignedJSON(string $url, SignaturePublicKey $publicKey, array $args = [], array $options = []) : array
 {
     $body = self::post($url, $args, $options);
     if (empty($body)) {
         throw new \Exception('Empty response from ' . $url);
     }
     if (self::$debug) {
         \var_dump($body);
     }
     $firstNewLine = \strpos($body, "\n");
     // There should be a newline immediately after the base64urlsafe-encoded signature
     if ($firstNewLine !== self::ENCODED_SIGNATURE_LENGTH) {
         throw new \Exception('Invalid Signature');
     }
     $sig = Base64UrlSafe::decode(Binary::safeSubstr($body, 0, self::ENCODED_SIGNATURE_LENGTH));
     $msg = Binary::safeSubstr($body, self::ENCODED_SIGNATURE_LENGTH + 1);
     if (!Asymmetric::verify($msg, $publicKey, $sig, true)) {
         throw new \Exception('Invalid Signature');
     }
     return \json_decode($msg, true);
 }
コード例 #6
0
ファイル: Hail.php プロジェクト: paragonie/airship
 /**
  * Parse a signed JSON response
  *
  * @param Response $response
  * @param SignaturePublicKey $publicKey
  * @return mixed
  * @throws SignatureFailed
  * @throws TransferException
  */
 public function parseSignedJSON(Response $response, SignaturePublicKey $publicKey)
 {
     $code = $response->getStatusCode();
     if ($code >= 200 && $code < 300) {
         $body = (string) $response->getBody();
         $firstNewLine = \strpos($body, "\n");
         // There should be a newline immediately after the base64urlsafe-encoded signature
         if ($firstNewLine !== self::ENCODED_SIGNATURE_LENGTH) {
             throw new SignatureFailed(\sprintf("First newline found at position %s, expected %d.\n%s", \print_r($firstNewLine, true), \print_r(self::ENCODED_SIGNATURE_LENGTH, true), Base64::encode($body)));
         }
         $sig = Base64UrlSafe::decode(Binary::safeSubstr($body, 0, 88));
         $msg = Binary::safeSubstr($body, 89);
         if (!Asymmetric::verify($msg, $publicKey, $sig, true)) {
             throw new SignatureFailed();
         }
         return \Airship\parseJSON($msg, true);
     }
     throw new TransferException();
 }
コード例 #7
0
ファイル: AsymmetricTest.php プロジェクト: paragonie/halite
 /**
  * @covers Asymmetric::sign()
  * @covers Asymmetric::verify()
  */
 public function testSignFail()
 {
     $alice = KeyFactory::generateSignatureKeyPair();
     $message = 'test message';
     $signature = Asymmetric::sign($message, $alice->getSecretKey(), true);
     $this->assertFalse(Asymmetric::verify('wrongmessage', $alice->getPublicKey(), $signature, true));
     $_signature = $signature;
     // Let's flip one bit, randomly:
     $r = \Sodium\randombytes_uniform(\mb_strlen($_signature, '8bit'));
     $_signature[$r] = \chr(\ord($_signature[$r]) ^ 1 << \Sodium\randombytes_uniform(8));
     $this->assertFalse(Asymmetric::verify($message, $alice->getPublicKey(), $_signature, true));
 }