def genState(self): """ Populate all the local variables with values. """ log.info("Generating parameters for the server's state file.") # PRNG seed for the client to reproduce the packet and IAT morpher. self.prngSeed = mycrypto.strongRandom(const.PRNG_SEED_LENGTH) # HMAC and AES key used to encrypt and authenticate tickets. self.hmacKey = mycrypto.strongRandom(const.TICKET_HMAC_KEY_LENGTH) self.aesKey = mycrypto.strongRandom(const.TICKET_AES_KEY_LENGTH) self.keyCreation = int(time.time()) # The previous HMAC and AES keys. self.oldHmacKey = None self.oldAesKey = None # Replay dictionary for both authentication mechanisms. self.replayTracker = replay.Tracker() # Distributions for packet lengths and inter arrival times. prng = random.Random(self.prngSeed) self.pktDist = probdist.new( lambda: prng.randint(const.HDR_LENGTH, const.MTU), seed=self.prngSeed) self.iatDist = probdist.new( lambda: prng.random() % const.MAX_PACKET_DELAY, seed=self.prngSeed) # Fallback UniformDH shared secret. Only used if the bridge operator # did not set `ServerTransportOptions'. self.fallbackPassword = os.urandom(const.SHARED_SECRET_LENGTH) self.writeState()
def genState( self ): """ Populate all the local variables with values. """ log.info("Generating parameters for the server's state file.") # PRNG seed for the client to reproduce the packet and IAT morpher. self.prngSeed = mycrypto.strongRandom(const.PRNG_SEED_LENGTH) # HMAC and AES key used to encrypt and authenticate tickets. self.hmacKey = mycrypto.strongRandom(const.TICKET_HMAC_KEY_LENGTH) self.aesKey = mycrypto.strongRandom(const.TICKET_AES_KEY_LENGTH) self.keyCreation = int(time.time()) # The previous HMAC and AES keys. self.oldHmacKey = None self.oldAesKey = None # Replay dictionary for both authentication mechanisms. self.replayTracker = replay.Tracker() # Distributions for packet lengths and inter arrival times. prng = random.Random(self.prngSeed) self.pktDist = probdist.new(lambda: prng.randint(const.HDR_LENGTH, const.MTU), seed=self.prngSeed) self.iatDist = probdist.new(lambda: prng.random() % const.MAX_PACKET_DELAY, seed=self.prngSeed) self.writeState()
def processMessages( self, circuit, data ): """ Acts on extracted protocol messages based on header flags. After the incoming `data' is decrypted and authenticated, this method processes the received data based on the header flags. Payload is written to the local application using `circuit', new tickets are stored or keys are added to the replay table. """ assert circuit if (data is None) or (len(data) == 0): return # Try to extract protocol messages from the encrypted blurb. msgs = self.extractMessages(data, self.recvCrypter) if (msgs is None) or (len(msgs) == 0): return for msg in msgs: # Forward data to the application. if msg.flags & const.FLAG_PAYLOAD: circuit.upstream.write(msg.payload) # Store newly received ticket and send ACK to the server. elif self.weAreClient and msg.flags == const.FLAG_NEW_TICKET: assert len(msg) == (const.HDR_LENGTH + const.TICKET_LENGTH + const.MASTER_KEY_LENGTH) peer = circuit.downstream.transport.getPeer() ticket.storeNewTicket(msg.payload[0:const.MASTER_KEY_LENGTH], msg.payload[const.MASTER_KEY_LENGTH: const.MASTER_KEY_LENGTH + const.TICKET_LENGTH], peer) # Use the PRNG seed to generate the same probability distributions # as the server. That's where the polymorphism comes from. elif self.weAreClient and msg.flags == const.FLAG_PRNG_SEED: assert len(msg.payload) == const.PRNG_SEED_LENGTH log.debug("Obtained PRNG seed.") prng = random.Random(msg.payload) pktDist = probdist.new(lambda: prng.randint(const.HDR_LENGTH, const.MTU), seed=msg.payload) self.pktMorpher = packetmorpher.new(pktDist) self.iatMorpher = probdist.new(lambda: prng.random() % const.MAX_PACKET_DELAY, seed=msg.payload) else: log.warning("Invalid message flags: %d." % msg.flags)
def processMessages(self, data): """ Acts on extracted protocol messages based on header flags. After the incoming `data' is decrypted and authenticated, this method processes the received data based on the header flags. Payload is written to the local application, new tickets are stored, or keys are added to the replay table. """ if (data is None) or (len(data) == 0): return # Try to extract protocol messages from the encrypted blurb. msgs = self.protoMsg.extract(data, self.recvCrypter, self.recvHMAC) if (msgs is None) or (len(msgs) == 0): return for msg in msgs: # Forward data to the application. if msg.flags == const.FLAG_PAYLOAD: self.circuit.upstream.write(msg.payload) # Store newly received ticket. elif self.weAreClient and (msg.flags == const.FLAG_NEW_TICKET): assert len(msg.payload) == (const.TICKET_LENGTH + const.MASTER_KEY_LENGTH) peer = self.circuit.downstream.transport.getPeer() ticket.storeNewTicket( msg.payload[0:const.MASTER_KEY_LENGTH], msg. payload[const.MASTER_KEY_LENGTH:const.MASTER_KEY_LENGTH + const.TICKET_LENGTH], peer) # Use the PRNG seed to generate the same probability distributions # as the server. That's where the polymorphism comes from. elif self.weAreClient and (msg.flags == const.FLAG_PRNG_SEED): assert len(msg.payload) == const.PRNG_SEED_LENGTH #log.debug("Obtained PRNG seed.") prng = random.Random(msg.payload) pktDist = probdist.new( lambda: prng.randint(const.HDR_LENGTH, const.MTU), seed=msg.payload) self.pktMorpher = packetmorpher.new(pktDist) self.iatMorpher = probdist.new( lambda: prng.random() % const.MAX_PACKET_DELAY, seed=msg.payload) else: #log.warning("Invalid message flags: %d." % msg.flags) pass
def __init__( self ): """ Initialise a ScrambleSuitTransport object. """ log.error("\n\n################################################\n" "Do NOT rely on ScrambleSuit for strong security!\n" "################################################\n") log.debug("Initialising %s." % const.TRANSPORT_NAME) super(ScrambleSuitTransport, self).__init__() # Load the server's persistent state from file. if self.weAreServer: self.srvState = state.load() # Initialise the protocol's state machine. log.debug("Switching to state ST_WAIT_FOR_AUTH.") self.protoState = const.ST_WAIT_FOR_AUTH # Buffer for outgoing data. self.sendBuf = "" # Buffer for inter-arrival time obfuscation. self.choppingBuf = fifobuf.Buffer() # AES instances to decrypt incoming and encrypt outgoing data. self.sendCrypter = mycrypto.PayloadCrypter() self.recvCrypter = mycrypto.PayloadCrypter() # Packet morpher to modify the protocol's packet length distribution. self.pktMorpher = packetmorpher.new(self.srvState.pktDist if self.weAreServer else None) # Inter-arrival time morpher to obfuscate inter arrival times. self.iatMorpher = self.srvState.iatDist if self.weAreServer else \ probdist.new(lambda: random.random() % const.MAX_PACKET_DELAY) # Used to extract protocol messages from encrypted data. self.protoMsg = message.MessageExtractor() # Used by the server-side: `True' if the ticket is already # decrypted but not yet authenticated. self.decryptedTicket = False # If we are in external mode we should already have a shared # secret set up because of validate_external_mode_cli(). if self.weAreExternal: assert(self.uniformDHSecret) if self.weAreClient and not self.weAreExternal: # As a client in managed mode, we get the shared secret # from callback `handle_socks_args()' per-connection. Set # the shared secret to None for now. self.uniformDHSecret = None self.uniformdh = uniformdh.new(self.uniformDHSecret, self.weAreServer)
def test1_calcPadding( self ): def checkDistribution( dist ): pm = packetmorpher.new(dist) for i in xrange(0, const.MTU + 2): padLen = pm.calcPadding(i) self.assertTrue(const.HDR_LENGTH <= \ padLen < \ (const.MTU + const.HDR_LENGTH)) # Test randomly generated distributions. for i in xrange(0, 100): checkDistribution(None) # Test border-case distributions. checkDistribution(probdist.new(lambda: 0)) checkDistribution(probdist.new(lambda: 1)) checkDistribution(probdist.new(lambda: const.MTU)) checkDistribution(probdist.new(lambda: const.MTU + 1))
def genState( self ): """ Populate all the local variables with values. """ log.info("Generating parameters for the server's state file.") # PRNG seed for the client to reproduce the packet and IAT morpher. self.prngSeed = mycrypto.strongRandom(const.PRNG_SEED_LENGTH) # HMAC and AES key used to encrypt and authenticate tickets. self.hmacKey = mycrypto.strongRandom(const.TICKET_HMAC_KEY_LENGTH) self.aesKey = mycrypto.strongRandom(const.TICKET_AES_KEY_LENGTH) self.keyCreation = int(time.time()) # The previous HMAC and AES keys. self.oldHmacKey = None self.oldAesKey = None # Replay dictionary for both authentication mechanisms. self.replayTracker = replay.Tracker() # Distributions for packet lengths and inter arrival times. prng = random.Random(self.prngSeed) self.pktDist = probdist.new(lambda: prng.randint(const.HDR_LENGTH, const.MTU), seed=self.prngSeed) self.iatDist = probdist.new(lambda: prng.random() % const.MAX_PACKET_DELAY, seed=self.prngSeed) # Fallback UniformDH shared secret. Only used if the bridge operator # did not set `ServerTransportOptions'. self.fallbackPassword = os.urandom(const.SHARED_SECRET_LENGTH) # Unauthenticated connections are closed after having received the # following amount of bytes. self.closingThreshold = prng.randint(const.MAX_HANDSHAKE_LENGTH, const.MAX_HANDSHAKE_LENGTH * 5) self.writeState()
def __init__(self, dist=None): """ Initialise the packet morpher with the given distribution `dist'. If `dist' is `None', a new discrete probability distribution is generated randomly. """ if dist: self.dist = dist else: self.dist = probdist.new(lambda: random.randint(const.HDR_LENGTH, const.MTU))
def __init__(self, dist=None): """ Initialise the packet morpher with the given distribution `dist'. If `dist' is `None', a new discrete probability distribution is generated randomly. """ if dist: self.dist = dist else: self.dist = probdist.new( lambda: random.randint(const.HDR_LENGTH, const.MTU))
def __init__( self, transportConfig ): """ Initialise a ScrambleSuitTransport object. """ log.error("\n\n################################################\n" "Do NOT rely on ScrambleSuit for strong security!\n" "################################################\n") log.debug("Initialising %s." % const.TRANSPORT_NAME) util.setStateLocation(transportConfig.getStateLocation()) # Load the server's persistent state from file. if self.weAreServer: self.srvState = state.load() # Initialise the protocol's state machine. log.debug("Switching to state ST_WAIT_FOR_AUTH.") self.protoState = const.ST_WAIT_FOR_AUTH # Buffers for incoming and outgoing data. self.sendBuf = self.recvBuf = "" # Buffer for inter-arrival time obfuscation. self.choppingBuf = "" # AES instances to decrypt incoming and encrypt outgoing data. self.sendCrypter = mycrypto.PayloadCrypter() self.recvCrypter = mycrypto.PayloadCrypter() # Packet morpher to modify the protocol's packet length distribution. self.pktMorpher = packetmorpher.new(self.srvState.pktDist if self.weAreServer else None) # Inter-arrival time morpher to obfuscate inter arrival times. self.iatMorpher = self.srvState.iatDist if self.weAreServer else \ probdist.new(lambda: random.random() % const.MAX_PACKET_DELAY) if self.weAreServer: # `True' if the ticket is already decrypted but not yet # authenticated. self.decryptedTicket = False if not hasattr(self, 'uniformDHSecret'): # As the server, we get the shared secret from the constructor. cfg = transportConfig.getServerTransportOptions() self.uniformDHSecret = base64.b32decode(cfg["password"]) self.uniformDHSecret = self.uniformDHSecret.strip() else: # As the client, we get the shared secret from obfsproxy calling # `handle_socks_args()'. if not hasattr(self, 'uniformDHSecret'): self.uniformDHSecret = None self.uniformdh = uniformdh.new(self.uniformDHSecret, self.weAreServer) # Variables used to unpack protocol messages. self.totalLen = self.payloadLen = self.flags = None