Exemplo n.º 1
0
 /**
  * @route notary/verify
  */
 public function verify()
 {
     // Input validation
     if (empty($_POST['challenge'])) {
         \Airship\json_response(['status' => 'error', 'message' => 'Expected a challenge=something HTTP POST parameter.']);
     }
     if (!\is_string($_POST['challenge'])) {
         \Airship\json_response(['status' => 'error', 'message' => 'Challenge must be a string.']);
     }
     if (Binary::safeStrlen($_POST['challenge']) < 20) {
         \Airship\json_response(['status' => 'error', 'message' => 'Challenge is too short. Continuum should be generating a long random nonce.']);
     }
     try {
         list($update, $signature) = $this->chanUp->verifyUpdate($this->sk, $_POST['challenge']);
         \Airship\json_response(['status' => 'OK', 'response' => $update, 'signature' => $signature]);
     } catch (\Exception $ex) {
         \Airship\json_response(['status' => 'error', 'message' => $ex->getMessage()]);
     }
 }
Exemplo n.º 2
0
 /**
  * Convert a hexadecimal string into a binary string without cache-timing
  * leaks
  *
  * @param string $hex_string
  * @param bool $strictPadding
  * @return string (raw binary)
  * @throws \RangeException
  */
 public static function decode(string $hexString, bool $strictPadding = false) : string
 {
     $hex_pos = 0;
     $bin = '';
     $c_acc = 0;
     $hex_len = Binary::safeStrlen($hexString);
     $state = 0;
     if (($hex_len & 1) !== 0) {
         if ($strictPadding) {
             throw new \RangeException('Expected an even number of hexadecimal characters');
         } else {
             $hexString = '0' . $hexString;
             ++$hex_len;
         }
     }
     $chunk = \unpack('C*', $hexString);
     while ($hex_pos < $hex_len) {
         ++$hex_pos;
         $c = $chunk[$hex_pos];
         $c_num = $c ^ 48;
         $c_num0 = $c_num - 10 >> 8;
         $c_alpha = ($c & ~32) - 55;
         $c_alpha0 = ($c_alpha - 10 ^ $c_alpha - 16) >> 8;
         if (($c_num0 | $c_alpha0) === 0) {
             throw new \RangeException('hexEncode() only expects hexadecimal characters');
         }
         $c_val = $c_num0 & $c_num | $c_alpha & $c_alpha0;
         if ($state === 0) {
             $c_acc = $c_val * 16;
         } else {
             $bin .= \pack('C', $c_acc | $c_val);
         }
         $state ^= 1;
     }
     return $bin;
 }
Exemplo n.º 3
0
/**
 * Is this URL a Tor Hidden Service?
 *
 * @param string $url
 * @return bool
 */
function isOnionUrl(string $url) : bool
{
    $host = \parse_url($url, \PHP_URL_HOST);
    if ($host !== null) {
        if (Binary::safeStrlen($host) < 7) {
            return false;
        }
        $suffix = Binary::safeSubstr($host, -6);
        return \strtolower($suffix) === '.onion';
    }
    return false;
}
Exemplo n.º 4
0
 /**
  * Generate, store, and return the index and token
  *
  * @param string $lockTo What URI endpoint this is valid for
  * @return string[]
  */
 protected function generateToken(string $lockTo) : array
 {
     $index = Base64::encode(\random_bytes(18));
     $token = Base64::encode(\random_bytes(33));
     $this->session[$this->sessionIndex][$index] = ['created' => \intval(\date('YmdHis')), 'uri' => isset($this->server['REQUEST_URI']) ? $this->server['REQUEST_URI'] : $this->server['SCRIPT_NAME'], 'token' => $token];
     if (\preg_match('#/$#', $lockTo)) {
         $lockTo = Binary::safeSubstr($lockTo, 0, Binary::safeStrlen($lockTo) - 1);
     }
     $this->session[$this->sessionIndex][$index]['lockTo'] = $lockTo;
     $this->recycleTokens();
     return [$index, $token];
 }
Exemplo n.º 5
0
 /**
  * decode from base64 into binary
  *
  * Base64 character set "./[A-Z][a-z][0-9]"
  *
  * @param string $src
  * @param bool $strictPadding
  * @return string|bool
  * @throws \RangeException
  */
 public static function decode(string $src, bool $strictPadding = false) : string
 {
     // Remove padding
     $srcLen = Binary::safeStrlen($src);
     if ($srcLen === 0) {
         return '';
     }
     if ($strictPadding) {
         if (($srcLen & 3) === 0) {
             if ($src[$srcLen - 1] === '=') {
                 $srcLen--;
                 if ($src[$srcLen - 1] === '=') {
                     $srcLen--;
                 }
             }
         }
         if (($srcLen & 3) === 1) {
             throw new \RangeException('Incorrect padding');
         }
         if ($src[$srcLen - 1] === '=') {
             throw new \RangeException('Incorrect padding');
         }
     } else {
         $src = \rtrim($src, '=');
         $srcLen = Binary::safeStrlen($src);
     }
     $err = 0;
     $dest = '';
     // Main loop (no padding):
     for ($i = 0; $i + 4 <= $srcLen; $i += 4) {
         $chunk = \unpack('C*', Binary::safeSubstr($src, $i, 4));
         $c0 = static::decode6Bits($chunk[1]);
         $c1 = static::decode6Bits($chunk[2]);
         $c2 = static::decode6Bits($chunk[3]);
         $c3 = static::decode6Bits($chunk[4]);
         $dest .= \pack('CCC', ($c0 << 2 | $c1 >> 4) & 0xff, ($c1 << 4 | $c2 >> 2) & 0xff, ($c2 << 6 | $c3) & 0xff);
         $err |= ($c0 | $c1 | $c2 | $c3) >> 8;
     }
     // The last chunk, which may have padding:
     if ($i < $srcLen) {
         $chunk = \unpack('C*', Binary::safeSubstr($src, $i, $srcLen - $i));
         $c0 = static::decode6Bits($chunk[1]);
         if ($i + 2 < $srcLen) {
             $c1 = static::decode6Bits($chunk[2]);
             $c2 = static::decode6Bits($chunk[3]);
             $dest .= \pack('CC', ($c0 << 2 | $c1 >> 4) & 0xff, ($c1 << 4 | $c2 >> 2) & 0xff);
             $err |= ($c0 | $c1 | $c2) >> 8;
         } elseif ($i + 1 < $srcLen) {
             $c1 = static::decode6Bits($chunk[2]);
             $dest .= \pack('C', ($c0 << 2 | $c1 >> 4) & 0xff);
             $err |= ($c0 | $c1) >> 8;
         } elseif ($i < $srcLen && $strictPadding) {
             $err |= 1;
         }
     }
     if ($err !== 0) {
         throw new \RangeException('Base64::decode() only expects characters in the correct base64 alphabet');
     }
     return $dest;
 }
Exemplo n.º 6
0
 /**
  * Base32 Decoding
  *
  * @param string $src
  * @param bool $upper
  * @return string
  */
 protected static function doEncode(string $src, bool $upper = false) : string
 {
     // We do this to reduce code duplication:
     $method = $upper ? 'encode5BitsUpper' : 'encode5Bits';
     $dest = '';
     $srcLen = Binary::safeStrlen($src);
     // Main loop (no padding):
     for ($i = 0; $i + 5 <= $srcLen; $i += 5) {
         $chunk = \unpack('C*', Binary::safeSubstr($src, $i, 5));
         $b0 = $chunk[1];
         $b1 = $chunk[2];
         $b2 = $chunk[3];
         $b3 = $chunk[4];
         $b4 = $chunk[5];
         $dest .= static::$method($b0 >> 3 & 31) . static::$method(($b0 << 2 | $b1 >> 6) & 31) . static::$method($b1 >> 1 & 31) . static::$method(($b1 << 4 | $b2 >> 4) & 31) . static::$method(($b2 << 1 | $b3 >> 7) & 31) . static::$method($b3 >> 2 & 31) . static::$method(($b3 << 3 | $b4 >> 5) & 31) . static::$method($b4 & 31);
     }
     // The last chunk, which may have padding:
     if ($i < $srcLen) {
         $chunk = \unpack('C*', Binary::safeSubstr($src, $i, $srcLen - $i));
         $b0 = $chunk[1];
         if ($i + 3 < $srcLen) {
             $b1 = $chunk[2];
             $b2 = $chunk[3];
             $b3 = $chunk[4];
             $dest .= static::$method($b0 >> 3 & 31) . static::$method(($b0 << 2 | $b1 >> 6) & 31) . static::$method($b1 >> 1 & 31) . static::$method(($b1 << 4 | $b2 >> 4) & 31) . static::$method(($b2 << 1 | $b3 >> 7) & 31) . static::$method($b3 >> 2 & 31) . static::$method($b3 << 3 & 31) . '=';
         } elseif ($i + 2 < $srcLen) {
             $b1 = $chunk[2];
             $b2 = $chunk[3];
             $dest .= static::$method($b0 >> 3 & 31) . static::$method(($b0 << 2 | $b1 >> 6) & 31) . static::$method($b1 >> 1 & 31) . static::$method(($b1 << 4 | $b2 >> 4) & 31) . static::$method($b2 << 1 & 31) . '===';
         } elseif ($i + 1 < $srcLen) {
             $b1 = $chunk[2];
             $dest .= static::$method($b0 >> 3 & 31) . static::$method(($b0 << 2 | $b1 >> 6) & 31) . static::$method($b1 >> 1 & 31) . static::$method($b1 << 4 & 31) . '====';
         } else {
             $dest .= static::$method($b0 >> 3 & 31) . static::$method($b0 << 2 & 31) . '======';
         }
     }
     return $dest;
 }
Exemplo n.º 7
0
 /**
  * Replace the existing long-term authentication cookie
  *
  * @param string $token
  * @param int $userId
  * @return mixed
  */
 public function rotateToken(string $token, int $userId = 0)
 {
     try {
         $decoded = Base64::decode($token);
     } catch (\RangeException $ex) {
         return false;
     }
     if ($decoded === false) {
         return false;
     } elseif (Binary::safeStrlen($decoded) !== self::LONG_TERM_AUTH_BYTES) {
         return false;
     }
     $sel = Binary::safeSubstr($decoded, 0, self::SELECTOR_BYTES);
     \Sodium\memzero($decoded);
     // Delete the old token
     $this->db->delete($this->tableConfig['table']['longterm'], [$this->tableConfig['fields']['longterm']['selector'] => Base64::encode($sel)]);
     // Let's get a new token
     return $this->createAuthToken($userId);
 }