def __init__(self): """Initialize the obfs2 pluggable transport.""" super(Obfs2Transport, self).__init__() # Check if the shared_secret class attribute was already # instantiated. If not, instantiate it now. if not hasattr(self, 'shared_secret'): self.shared_secret = None # If external-mode code did not specify the number of hash # iterations, just use the default. if not hasattr(self, 'ss_hash_iterations'): self.ss_hash_iterations = HASH_ITERATIONS if self.shared_secret: log.debug("Starting obfs2 with shared secret: %s" % self.shared_secret) # Our state. self.state = ST_WAIT_FOR_KEY if self.we_are_initiator: self.initiator_seed = rand.random_bytes( SEED_LENGTH) # Initiator's seed. self.responder_seed = None # Responder's seed. else: self.initiator_seed = None # Initiator's seed. self.responder_seed = rand.random_bytes( SEED_LENGTH) # Responder's seed # Shared secret seed. self.secret_seed = None # Crypto to encrypt outgoing data. self.send_crypto = None # Crypto to encrypt outgoing padding. self.send_padding_crypto = None # Crypto to decrypt incoming data. self.recv_crypto = None # Crypto to decrypt incoming padding. self.recv_padding_crypto = None # Number of padding bytes left to read. self.padding_left_to_read = 0 # If it's True, it means that we received upstream data before # we had the chance to set up our crypto (after receiving the # handshake). This means that when we set up our crypto, we # must remember to push the cached upstream data downstream. self.pending_data_to_send = False
def __init__(self, private_key = None): # Generate private key if private_key != None: if len(private_key) != self.group_len: raise ValueError("private_key is a invalid length (Expected %d, got %d)" % (group_len, len(private_key))) self.priv_str = private_key else: self.priv_str = rand.random_bytes(self.group_len) self.priv = int(binascii.hexlify(self.priv_str), 16) # Make the private key even flip = self.priv % 2 self.priv -= flip # Generate public key # # Note: Always generate both valid public keys, and then pick to avoid # leaking timing information about which key was chosen. pub = modexp.powMod(self.g, self.priv, self.mod) pub_p_sub_X = self.mod - pub if flip == 1: self.pub = pub_p_sub_X else: self.pub = pub self.pub_str = int_to_bytes(self.pub, self.group_len) self.shared_secret = None
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)
def __init__(self): """Initialize the obfs2 pluggable transport.""" super(Obfs2Transport, self).__init__() # Check if the shared_secret class attribute was already # instantiated. If not, instantiate it now. if not hasattr(self, 'shared_secret'): self.shared_secret = None # If external-mode code did not specify the number of hash # iterations, just use the default. if not hasattr(self, 'ss_hash_iterations'): self.ss_hash_iterations = HASH_ITERATIONS if self.shared_secret: log.debug("Starting obfs2 with shared secret: %s" % self.shared_secret) # Our state. self.state = ST_WAIT_FOR_KEY if self.we_are_initiator: self.initiator_seed = rand.random_bytes(SEED_LENGTH) # Initiator's seed. self.responder_seed = None # Responder's seed. else: self.initiator_seed = None # Initiator's seed. self.responder_seed = rand.random_bytes(SEED_LENGTH) # Responder's seed # Shared secret seed. self.secret_seed = None # Crypto to encrypt outgoing data. self.send_crypto = None # Crypto to encrypt outgoing padding. self.send_padding_crypto = None # Crypto to decrypt incoming data. self.recv_crypto = None # Crypto to decrypt incoming padding. self.recv_padding_crypto = None # Number of padding bytes left to read. self.padding_left_to_read = 0 # If it's True, it means that we received upstream data before # we had the chance to set up our crypto (after receiving the # handshake). This means that when we set up our crypto, we # must remember to push the cached upstream data downstream. self.pending_data_to_send = False
def __init__(self, circuit, ext_orport_addr, cookie_file, peer_addr): self.state = STATE_WAIT_FOR_AUTH_TYPES self.name = "ext_%s" % hex(id(self)) self.ext_orport_addr = ext_orport_addr self.peer_addr = peer_addr self.cookie_file = cookie_file self.client_nonce = rand.random_bytes(AUTH_NONCE_LEN) self.client_hash = None network.GenericProtocol.__init__(self, circuit)
def circuitConnected(self): """ Do the obfs3 handshake: PUBKEY | WR(PADLEN) """ padding_length = random.randint(0, MAX_PADDING/2) handshake_message = self.dh.get_public() + rand.random_bytes(padding_length) log.debug("obfs3 handshake: %s queued %d bytes (padding_length: %d) (public key: %s).", "initiator" if self.we_are_initiator else "responder", len(handshake_message), padding_length, repr(self.dh.get_public())) self.circuit.downstream.write(handshake_message)
def __init__(self): # Generate private key self.priv_str = rand.random_bytes(self.group_len) self.priv = int(binascii.hexlify(self.priv_str), 16) # Make the private key even flip = self.priv % 2 self.priv -= flip # Generate public key self.pub = modexp.powMod(self.g, self.priv, self.mod) if flip == 1: self.pub = self.mod - self.pub self.pub_str = int_to_bytes(self.pub, self.group_len) self.shared_secret = None
def __init__(self): # Generate private key self.priv_str = rand.random_bytes(self.group_len) self.priv = int(binascii.hexlify(self.priv_str), 16) # Make the private key even flip = self.priv % 2 self.priv -= flip # Generate public key self.pub = pow(self.g, self.priv, self.mod) if flip == 1: self.pub = self.mod - self.pub self.pub_str = int_to_bytes(self.pub, self.group_len) self.shared_secret = None
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
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
def circuitConnected(self): """ Do the obfs2 handshake: SEED | E_PAD_KEY( UINT32(MAGIC_VALUE) | UINT32(PADLEN) | WR(PADLEN) ) """ # Generate keys for outgoing padding. self.send_padding_crypto = \ self._derive_padding_crypto(self.initiator_seed if self.we_are_initiator else self.responder_seed, self.send_pad_keytype) padding_length = random.randint(0, MAX_PADDING) seed = self.initiator_seed if self.we_are_initiator else self.responder_seed handshake_message = seed + self.send_padding_crypto.crypt(srlz.htonl(MAGIC_VALUE) + srlz.htonl(padding_length) + rand.random_bytes(padding_length)) log.debug("obfs2 handshake: %s queued %d bytes (padding_length: %d).", "initiator" if self.we_are_initiator else "responder", len(handshake_message), padding_length) self.circuit.downstream.write(handshake_message)