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))
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 test2_getPadding( self ): pm = packetmorpher.new() sendCrypter = mycrypto.PayloadCrypter() sendCrypter.setSessionKey("A" * 32, "A" * 8) sendHMAC = "A" * 32 for i in xrange(0, const.MTU + 2): padLen = len(pm.getPadding(sendCrypter, sendHMAC, i)) self.assertTrue(const.HDR_LENGTH <= padLen < const.MTU + \ const.HDR_LENGTH)
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, 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