This is just to hide sensitive strings from stack traces, etc.
Beispiel #1
0
 /**
  * WordPress's internal password hashing algorithm. Only used for migrations.
  * The actual security of CMS Airship doesn't depend on this algorithm.
  *
  * @internal
  * @param HiddenString $password
  * @param string $setting
  * @return string
  */
 private function wordPressCryptPrivate(HiddenString $password, string $setting) : string
 {
     $output = '*0';
     if (Binary::safeSubstr($setting, 0, 2) === $output) {
         $output = '*1';
     }
     $id = Binary::safeSubstr($setting, 0, 3);
     if ($id !== '$P$' && $id !== '$H$') {
         return $output;
     }
     // This is a really weird way to encode iteration count.
     $count_log2 = \strpos($this->itoa64, $setting[3]);
     if ($count_log2 < 7 || $count_log2 > 30) {
         return $output;
     }
     $count = 1 << $count_log2;
     $salt = Binary::safeSubstr($setting, 4, 8);
     if (Binary::safeStrlen($salt) !== 8) {
         return $output;
     }
     // And now we do our (default 8192) rounds of MD5...
     $hash = \md5($salt . $password->getString(), true);
     do {
         $hash = \md5($hash . $password->getString(), true);
     } while (--$count);
     $output = Binary::safeSubstr($setting, 0, 12);
     $output .= $this->encode64($hash, 16);
     return $output;
 }
Beispiel #2
0
 /**
  * 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();
 }
Beispiel #3
0
 /**
  * Verifies that the password is valid for a given user account. Returns
  * false whether or not the user name is valid and attempts to minimize
  * leaking that information through timing side-channels.
  * 
  * @param string $username
  * @param HiddenString $password
  * @return bool|int
  */
 public function login(string $username, HiddenString $password)
 {
     /**
      * To prevent extreme stupidity, we escape our table and column names
      * here. We shouldn't ever *need* to do this, but as long as developers
      * are creative, they will find creative ways to make their apps
      * insecure and we should anticipate them as much as we can.
      */
     $table = $this->db->escapeIdentifier($this->tableConfig['table']['accounts']);
     // Let's fetch the user data from the database
     $user = $this->db->row('SELECT * FROM ' . $table . ' WHERE username = ?', $username);
     if (empty($user)) {
         /**
          * User not found. Use the dummy password to mitigate user
          * enumeration via timing side-channels.
          */
         Password::verify($password->getString(), $this->dummyHash, $this->key);
         // No matter what, return false here:
         return false;
     } else {
         if (!empty($user['migration'])) {
             $success = $this->migrateImportedHash($password, new HiddenString($user['password']), $user);
             if ($success) {
                 return (int) $user['userid'];
             }
         }
         if (Password::verify($password->getString(), $user['password'], $this->key)) {
             return (int) $user['userid'];
         }
     }
     return false;
 }