Ejemplo n.º 1
0
    def _get_server_nonce_and_hash(self):
        """
        Get the server's nonce and hash, validate them and send our own hash.
        """

        if len(self.buffer) < AUTH_HASH_LEN + AUTH_NONCE_LEN:
            return

        server_hash = self.buffer.read(AUTH_HASH_LEN)
        server_nonce = self.buffer.read(AUTH_NONCE_LEN)
        auth_cookie = _read_auth_cookie(self.cookie_file)

        proper_server_hash = hmac_sha256.hmac_sha256_digest(auth_cookie,
                                                            AUTH_SERVER_TO_CLIENT_CONST + self.client_nonce + server_nonce)

        log.debug("%s: client_nonce: %s\nserver_nonce: %s\nserver_hash: %s\nproper_server_hash: %s\n" % \
                      (self.name, repr(self.client_nonce), repr(server_nonce), repr(server_hash), repr(proper_server_hash)))

        if proper_server_hash != server_hash:
            log.warning("%s: Invalid server hash. Authentication failed." % (self.name))
            self.close()
            return

        client_hash = hmac_sha256.hmac_sha256_digest(auth_cookie,
                                                     AUTH_CLIENT_TO_SERVER_CONST + self.client_nonce + server_nonce)

        # Send our hash.
        self.write(client_hash)

        self.state = STATE_WAIT_FOR_RESULTS
Ejemplo n.º 2
0
    def _handle_server_nonce_and_hash(self):
        """
        Get the server's nonce and hash, validate them and send our own hash.

        Throws NeedMoreData and RcvdInvalidAuth and CouldNotReadCookie.
        """

        if len(self.buffer) < AUTH_HASH_LEN + AUTH_NONCE_LEN:
            raise NeedMoreData('Need more data')

        server_hash = self.buffer.read(AUTH_HASH_LEN)
        server_nonce = self.buffer.read(AUTH_NONCE_LEN)
        auth_cookie = _read_auth_cookie(self.cookie_file)

        proper_server_hash = hmac_sha256.hmac_sha256_digest(auth_cookie,
                                                            AUTH_SERVER_TO_CLIENT_CONST + self.client_nonce + server_nonce)

        log.debug("%s: client_nonce: %s\nserver_nonce: %s\nserver_hash: %s\nproper_server_hash: %s\n" % \
                      (self.name, repr(self.client_nonce), repr(server_nonce), repr(server_hash), repr(proper_server_hash)))

        if proper_server_hash != server_hash:
            raise RcvdInvalidAuth("%s: Invalid server hash. Authentication failed." % (self.name))

        client_hash = hmac_sha256.hmac_sha256_digest(auth_cookie,
                                                     AUTH_CLIENT_TO_SERVER_CONST + self.client_nonce + server_nonce)

        # Send our hash.
        self.write(client_hash)
Ejemplo n.º 3
0
    def _read_handshake_post_dh(self, shared_secret, other_pubkey, data):
        """
        Setup the crypto from the calculated shared secret, and complete the
        obfs3 handshake.
        """

        self.shared_secret = shared_secret
        log_prefix = "obfs3:_read_handshake_post_dh()"
        log.debug("Got public key: %s.\nGot shared secret: %s" %
                  (repr(other_pubkey), repr(self.shared_secret)))

        # Set up our crypto.
        self.send_crypto = self._derive_crypto(self.send_keytype)
        self.recv_crypto = self._derive_crypto(self.recv_keytype)
        self.other_magic_value = hmac_sha256.hmac_sha256_digest(self.shared_secret,
                                                                self.recv_magic_const)

        # Send our magic value to the remote end and append the queued outgoing data.
        # Padding is prepended so that the server does not just send the 32-byte magic
        # in a single TCP segment.
        padding_length = random.randint(0, MAX_PADDING/2)
        magic = hmac_sha256.hmac_sha256_digest(self.shared_secret, self.send_magic_const)
        message = rand.random_bytes(padding_length) + magic + self.send_crypto.crypt(self.queued_data)
        self.queued_data = ''

        log.debug("%s: Transmitting %d bytes (with magic)." % (log_prefix, len(message)))
        self.circuit.downstream.write(message)

        self.state = ST_SEARCHING_MAGIC
        if len(data) > 0:
             log.debug("%s: Processing %d bytes of handshake data remaining after key." % (log_prefix, len(data)))
             self._scan_for_magic(data)
Ejemplo n.º 4
0
    def _read_handshake_post_dh(self, shared_secret, other_pubkey, data):
        """
        Setup the crypto from the calculated shared secret, and complete the
        obfs3 handshake.
        """

        self.shared_secret = shared_secret
        log_prefix = "obfs3:_read_handshake_post_dh()"
        log.debug("Got public key: %s.\nGot shared secret: %s" %
                  (repr(other_pubkey), repr(self.shared_secret)))

        # Set up our crypto.
        self.send_crypto = self._derive_crypto(self.send_keytype)
        self.recv_crypto = self._derive_crypto(self.recv_keytype)
        self.other_magic_value = hmac_sha256.hmac_sha256_digest(self.shared_secret,
                                                                self.recv_magic_const)

        # Send our magic value to the remote end and append the queued outgoing data.
        # Padding is prepended so that the server does not just send the 32-byte magic
        # in a single TCP segment.
        padding_length = random.randint(0, MAX_PADDING/2)
        magic = hmac_sha256.hmac_sha256_digest(self.shared_secret, self.send_magic_const)
        message = rand.random_bytes(padding_length) + magic + self.send_crypto.crypt(self.queued_data)
        self.queued_data = ''

        log.debug("%s: Transmitting %d bytes (with magic)." % (log_prefix, len(message)))
        self.circuit.downstream.write(message)

        self.state = ST_SEARCHING_MAGIC
        if len(data) > 0:
             log.debug("%s: Processing %d bytes of handshake data remaining after key." % (log_prefix, len(data)))
             self._scan_for_magic(data)
Ejemplo n.º 5
0
 def _derive_crypto(self, pad_string):
     """
     Derive and return an obfs3 key using the pad string in 'pad_string'.
     """
     secret = hmac_sha256.hmac_sha256_digest(self.shared_secret, pad_string)
     return aes.AES_CTR_128(secret[:KEYLEN], secret[KEYLEN:],
                            counter_wraparound=True)
Ejemplo n.º 6
0
    def _read_handshake(self, data, circuit):
        """
        Read handshake message, parse the other peer's public key and
        set up our crypto.
        """

        log_prefix = "obfs3:_read_handshake()"
        if len(data) < PUBKEY_LEN:
            log.debug("%s: Not enough bytes for key (%d)." %
                      (log_prefix, len(data)))
            return

        log.debug("%s: Got %d bytes of handshake data (waiting for key)." %
                  (log_prefix, len(data)))

        # Get the public key from the handshake message, do the DH and
        # get the shared secret.
        other_pubkey = data.read(PUBKEY_LEN)
        try:
            self.shared_secret = self.dh.get_secret(other_pubkey)
        except ValueError:
            raise base.PluggableTransportError(
                "obfs3: Corrupted public key '%s'" % repr(other_pubkey))
        log.debug("Got public key: %s.\nGot shared secret: %s" %
                  (repr(other_pubkey), repr(self.shared_secret)))

        # Set up our crypto.
        self.send_crypto = self._derive_crypto(self.send_keytype)
        self.recv_crypto = self._derive_crypto(self.recv_keytype)
        self.other_magic_value = hmac_sha256.hmac_sha256_digest(
            self.shared_secret, self.recv_magic_const)

        # Send our magic value to the remote end and append the queued outgoing data.
        # Padding is prepended so that the server does not just send the 32-byte magic
        # in a single TCP segment.
        padding_length = random.randint(0, MAX_PADDING / 2)
        magic = hmac_sha256.hmac_sha256_digest(self.shared_secret,
                                               self.send_magic_const)
        message = rand.random_bytes(
            padding_length) + magic + self.send_crypto.crypt(self.queued_data)
        self.queued_data = ''

        log.debug("%s: Transmitting %d bytes (with magic)." %
                  (log_prefix, len(message)))
        circuit.downstream.write(message)

        self.state = ST_SEARCHING_MAGIC
Ejemplo n.º 7
0
    def _read_handshake(self, data):
        """
        Read handshake message, parse the other peer's public key and
        set up our crypto.
        """

        log_prefix = "obfs3:_read_handshake()"
        if len(data) < PUBKEY_LEN:
            log.debug("%s: Not enough bytes for key (%d)." % (log_prefix, len(data)))
            return

        log.debug("%s: Got %d bytes of handshake data (waiting for key)." % (log_prefix, len(data)))

        # Get the public key from the handshake message, do the DH and
        # get the shared secret.
        other_pubkey = data.read(PUBKEY_LEN)
        try:
            self.shared_secret = self.dh.get_secret(other_pubkey)
        except ValueError:
            raise base.PluggableTransportError("obfs3: Corrupted public key '%s'" % repr(other_pubkey))
        log.debug("Got public key: %s.\nGot shared secret: %s" %
                  (repr(other_pubkey), repr(self.shared_secret)))

        # Set up our crypto.
        self.send_crypto = self._derive_crypto(self.send_keytype)
        self.recv_crypto = self._derive_crypto(self.recv_keytype)
        self.other_magic_value = hmac_sha256.hmac_sha256_digest(self.shared_secret,
                                                                self.recv_magic_const)

        # Send our magic value to the remote end and append the queued outgoing data.
        # Padding is prepended so that the server does not just send the 32-byte magic
        # in a single TCP segment.
        padding_length = random.randint(0, MAX_PADDING/2)
        magic = hmac_sha256.hmac_sha256_digest(self.shared_secret, self.send_magic_const)
        message = rand.random_bytes(padding_length) + magic + self.send_crypto.crypt(self.queued_data)
        self.queued_data = ''

        log.debug("%s: Transmitting %d bytes (with magic)." % (log_prefix, len(message)))
        self.circuit.downstream.write(message)

        self.state = ST_SEARCHING_MAGIC