def test_exchange(self): dh_x = obfs3_dh.UniformDH(self._x_str) dh_y = obfs3_dh.UniformDH(self._y_str) xY = dh_x.get_secret(dh_y.get_public()) yX = dh_y.get_secret(dh_x.get_public()) self.assertEqual(self._xYyX_str, xY) self.assertEqual(self._xYyX_str, yX)
def test_benchmark(self): start = time.clock() for i in range(0, 1000): dh_x = obfs3_dh.UniformDH() dh_y = obfs3_dh.UniformDH() xY = dh_x.get_secret(dh_y.get_public()) yX = dh_y.get_secret(dh_x.get_public()) self.assertEqual(xY, yX) end = time.clock() taken = (end - start) / 1000 / 2 log.msg("Generate + Exchange: %f sec" % taken)
def test_uniform_dh(self): alice = obfs3_dh.UniformDH() bob = obfs3_dh.UniformDH() alice_pub = alice.get_public() bob_pub = bob.get_public() alice_secret = alice.get_secret(bob_pub) bob_secret = bob.get_secret(alice_pub) self.assertEqual(alice_secret, bob_secret)
def receivePublicKey(self, data, callback, srvState=None): """ Extract the public key and invoke a callback with the master secret. First, the UniformDH public key is extracted out of `data'. Then, the shared master secret is computed and `callback' is invoked with the master secret as argument. If any of this fails, `False' is returned. """ # Extract the public key sent by the remote host. remotePublicKey = self.extractPublicKey(data, srvState) if not remotePublicKey: return False if self.weAreServer: self.remotePublicKey = remotePublicKey # As server, we need a DH object; as client, we already have one. self.udh = obfs3_dh.UniformDH() assert self.udh is not None try: uniformDHSecret = self.udh.get_secret(remotePublicKey) except ValueError: raise base.PluggableTransportError("Corrupted public key.") # First, hash the 4096-bit UniformDH secret to obtain the master key. masterKey = Crypto.Hash.SHA256.new(uniformDHSecret).digest() # Second, session keys are now derived from the master key. callback(masterKey) return True
def createHandshake(self): """ Create and return a ready-to-be-sent UniformDH handshake. The returned handshake data includes the public key, pseudo-random padding, the mark and the HMAC. If a UniformDH object has not been initialised yet, a new instance is created. """ assert self.sharedSecret is not None log.debug("Creating UniformDH handshake message.") if self.udh is None: self.udh = obfs3_dh.UniformDH() publicKey = self.udh.get_public() assert (const.MAX_PADDING_LENGTH - const.PUBLIC_KEY_LENGTH) >= 0 # Subtract the length of the public key to make the handshake on # average as long as a redeemed ticket. That should thwart statistical # length-based attacks. padding = mycrypto.strongRandom( random.randint(0, const.MAX_PADDING_LENGTH - const.PUBLIC_KEY_LENGTH)) # Add a mark which enables efficient location of the HMAC. mark = mycrypto.HMAC_SHA256_128(self.sharedSecret, publicKey) # Authenticate the handshake including the current approximate epoch. mac = mycrypto.HMAC_SHA256_128( self.sharedSecret, publicKey + padding + mark + util.getEpoch()) return publicKey + padding + mark + mac
def __init__(self): """Initialize the obfs3 pluggable transport.""" # Our state. self.state = ST_WAIT_FOR_KEY # Uniform-DH object self.dh = obfs3_dh.UniformDH() # DH shared secret self.shared_secret = None # Bytes of padding scanned so far. self.scanned_padding = 0 # Last padding bytes scanned. self.last_padding_chunk = '' # Magic value that the other party is going to send # (initialized after deriving shared secret) self.other_magic_value = None # Crypto to encrypt outgoing data. self.send_crypto = None # Crypto to decrypt incoming data. self.recv_crypto = None # Buffer for the first data, Tor is trying to send but can't right now # because we have to handle the DH handshake first. self.queued_data = '' # Attributes below are filled by classes that inherit Obfs3Transport. self.send_keytype = None self.recv_keytype = None self.send_magic_const = None self.recv_magic_const = None self.we_are_initiator = None
def createHandshake(self, srvState=None): """ Create and return a ready-to-be-sent UniformDH handshake. The returned handshake data includes the public key, pseudo-random padding, the mark and the HMAC. If a UniformDH object has not been initialised yet, a new instance is created. """ assert self.sharedSecret is not None log.debug("Creating UniformDH handshake message.") if self.udh is None: self.udh = obfs3_dh.UniformDH() publicKey = self.udh.get_public() assert (const.MAX_PADDING_LENGTH - const.PUBLIC_KEY_LENGTH) >= 0 # Subtract the length of the public key to make the handshake on # average as long as a redeemed ticket. That should thwart statistical # length-based attacks. padding = mycrypto.strongRandom( random.randint(0, const.MAX_PADDING_LENGTH - const.PUBLIC_KEY_LENGTH)) # Add a mark which enables efficient location of the HMAC. mark = mycrypto.HMAC_SHA256_128(self.sharedSecret, publicKey) if self.echoEpoch is None: epoch = util.getEpoch() else: epoch = self.echoEpoch log.debug("Echoing epoch rather than recreating it.") # Authenticate the handshake including the current approximate epoch. mac = mycrypto.HMAC_SHA256_128( self.sharedSecret, publicKey + padding + mark + epoch.encode('utf-8')) if self.weAreServer and (srvState is not None): log.debug("Adding the HMAC authenticating the server's UniformDH " "message to the replay table: %s." % mac.encode('hex')) srvState.registerKey(mac) return publicKey + padding + mark + mac
def test_even_key(self): dh_y = obfs3_dh.UniformDH(self._y_str) self.assertEqual(self._y_str, dh_y.priv_str) self.assertEqual(self._Y_str, dh_y.get_public())
def test_odd_key(self): dh_x = obfs3_dh.UniformDH(self._x_str) self.assertEqual(self._x_str, dh_x.priv_str) self.assertEqual(self._X_str, dh_x.get_public())