def receivedDownstream(self, data):
        log_prefix = "obfs2 receivedDownstream" # used in logs

        if self.state == ST_WAIT_FOR_KEY:
            log.debug("%s: Waiting for key." % log_prefix)
            if len(data) < SEED_LENGTH + 8:
                log.debug("%s: Not enough bytes for key (%d)." % (log_prefix, len(data)))
                return data # incomplete

            if self.we_are_initiator:
                self.responder_seed = data.read(SEED_LENGTH)
            else:
                self.initiator_seed = data.read(SEED_LENGTH)

            # Now that we got the other seed, let's set up our crypto.
            self.send_crypto = self._derive_crypto(self.send_keytype)
            self.recv_crypto = self._derive_crypto(self.recv_keytype)
            self.recv_padding_crypto = \
                self._derive_padding_crypto(self.responder_seed if self.we_are_initiator else self.initiator_seed,
                                            self.recv_pad_keytype)

            # XXX maybe faster with a single d() instead of two.
            magic = srlz.ntohl(self.recv_padding_crypto.crypt(data.read(4)))
            padding_length = srlz.ntohl(self.recv_padding_crypto.crypt(data.read(4)))

            log.debug("%s: Got %d bytes of handshake data (padding_length: %d, magic: %s)" % \
                          (log_prefix, len(data), padding_length, hex(magic)))

            if magic != MAGIC_VALUE:
                raise base.PluggableTransportError("obfs2: Corrupted magic value '%s'" % hex(magic))
            if padding_length > MAX_PADDING:
                raise base.PluggableTransportError("obfs2: Too big padding length '%s'" % padding_length)

            self.padding_left_to_read = padding_length
            self.state = ST_WAIT_FOR_PADDING

        while self.padding_left_to_read:
            if not data: return

            n_to_drain = self.padding_left_to_read
            if (self.padding_left_to_read > len(data)):
                n_to_drain = len(data)

            data.drain(n_to_drain)
            self.padding_left_to_read -= n_to_drain
            log.debug("%s: Consumed %d bytes of padding, %d still to come (%d).",
                      log_prefix, n_to_drain, self.padding_left_to_read, len(data))

        self.state = ST_OPEN
        log.debug("%s: Processing %d bytes of application data.",
                  log_prefix, len(data))

        if self.pending_data_to_send:
            log.debug("%s: We got pending data to send and our crypto is ready. Pushing!" % log_prefix)
            self.receivedUpstream(self.circuit.upstream.buffer) # XXX touching guts of network.py
            self.pending_data_to_send = False

        self.circuit.upstream.write(self.recv_crypto.crypt(data.read()))
Got data from downstream. We need to de-obfuscate them and
dataset/ETHPy150Open isislovecruft/obfsproxy/obfsproxy/transports/obfs2.py/Obfs2Transport.receivedDownstream