Ejemplo n.º 1
0
def parse_fragment(fragment):
    msg_id, frag_byte, rest = cut(fragment, FRAG_ID_SIZE, FRAG_FLAG_SIZE)

    i_frag_byte = b2i(frag_byte)

    fragment_id = i_frag_byte & 0b0011_1111

    is_last = (
        i_frag_byte
        & FragmentGenerator.LAST_FRAG_FLAG) == FragmentGenerator.LAST_FRAG_FLAG

    payload_len = len(rest)

    has_padding = (
        i_frag_byte
        & FragmentGenerator.PADDING_FLAG) == FragmentGenerator.PADDING_FLAG

    if has_padding:
        padding_len, padding_bytes = bytes_to_padding_length(rest)

        payload_len -= (padding_len + padding_bytes)

        _, payload, _ = cut(rest, padding_bytes, payload_len)
    else:
        payload = rest

    return b2i(msg_id), is_last, fragment_id, payload
Ejemplo n.º 2
0
def test_get_data_fragment():
    udp_payload = get_random_bytes(DATA_FRAG_PAYLOAD_SIZE)

    f = FragmentGenerator(udp_payload)

    fragment = f.get_data_fragment()

    _, frag_byte, payload = cut(fragment, FRAG_ID_SIZE, FRAG_FLAG_SIZE)

    assert b2i(frag_byte) & FragmentGenerator.LAST_FRAG_FLAG
    assert b2i(frag_byte) == 0b0100_0000
    assert payload[0:DATA_FRAG_PAYLOAD_SIZE] == udp_payload
    assert len(
        fragment) == DATA_FRAG_PAYLOAD_SIZE + FRAG_ID_SIZE + FRAG_FLAG_SIZE
Ejemplo n.º 3
0
    def parse_channel_init(self, channel_init):
        self.last_interaction = time()
        _, _, payload = cut_init_message(channel_init)

        ip, port, fragment = cut(payload, IPV4_LEN, PORT_LEN)

        ip = b2ip(ip)
        port = b2i(port)

        self.dest_addr = (ip, port)

        try:
            self.out_sock.connect(self.dest_addr)
        except OSError:
            # couldn't connect, maybe not a channel init message?
            print("Couldn't connect to destination. Dropped message.")
            self.out_sock.close()
            del ChannelExit.table[self.in_chan_id]

            return

        ChannelExit.sock_sel.register(self.out_sock, EVENT_READ, data=self)
        print(self, "Init", "->", len(channel_init))

        self.recv_request(fragment)
Ejemplo n.º 4
0
    def parse_channel_init(self, channel_init, priv_comp):
        """Takes an already decrypted channel init message and reads the key.
        """
        self.last_interaction = time()

        msg_ctr, channel_init = cut(channel_init, CTR_PREFIX_LEN)

        self.request_replay_detector.check_replay_window(b2i(msg_ctr))

        sym_key, _, channel_init = process(priv_comp, channel_init)

        if self.key is not None:
            assert self.key == sym_key
            self.initialized = True
        else:
            self.key = sym_key

        print(self, "Init", "->", len(channel_init))

        channel_init = msg_ctr + channel_init

        # we add an empty ctr prefix, because the link encryption expects there
        # to be one, even though the channel init wasn't sym encrypted

        # todo look at this one again
        packet = CHAN_INIT_MSG_FLAG + i2b(self.out_chan_id, CHAN_ID_SIZE) + channel_init

        ChannelMid.requests.append(packet)
Ejemplo n.º 5
0
    def forward_response(self, response):
        self.last_interaction = time()

        # cut the padding off
        response, _ = cut(response, -CTR_MODE_PADDING)

        msg_type, response = cut(response, MSG_TYPE_FLAG_LEN)

        msg_ctr, _ = cut(response, CTR_PREFIX_LEN)

        # todo find better way
        if msg_ctr != bytes(CTR_PREFIX_LEN):
            self.response_replay_detector.check_replay_window(b2i(msg_ctr))

        self.response_counter.next()

        cipher = ctr_cipher(self.key, int(self.response_counter))

        forward_msg = cipher.encrypt(response)

        print(self, "Data", "<-", len(forward_msg))

        response = msg_type + i2b(self.in_chan_id, CHAN_ID_SIZE) + bytes(self.response_counter) + forward_msg

        ChannelMid.responses.append(response)
Ejemplo n.º 6
0
    def decrypt(self, cipher_text):
        b_link_ctr, header, mac, fragment = cut(cipher_text, CTR_PREFIX_LEN,
                                                LINK_HEADER_LEN, GCM_MAC_LEN)

        link_ctr = b2i(b_link_ctr)

        cipher = gcm_cipher(self.key, link_ctr)

        plain_header = cipher.decrypt_and_verify(header, mac)

        chan_id, msg_ctr, msg_type, _ = cut(plain_header, CHAN_ID_SIZE,
                                            CTR_PREFIX_LEN, MSG_TYPE_FLAG_LEN)

        self.replay_detector.check_replay_window(link_ctr)

        return b2i(chan_id), msg_ctr, fragment, msg_type
Ejemplo n.º 7
0
def test_get_data_fragment_with_padding():
    udp_payload = get_random_bytes(DATA_FRAG_PAYLOAD_SIZE - 1)

    f = FragmentGenerator(udp_payload)

    fragment = f.get_data_fragment()

    _, frag_byte, _, payload = cut(fragment, FRAG_ID_SIZE, FRAG_FLAG_SIZE, 1)

    assert b2i(frag_byte) & FragmentGenerator.LAST_FRAG_FLAG
    assert b2i(frag_byte) & FragmentGenerator.PADDING_FLAG
    assert b2i(frag_byte) == 0b1100_0000
    assert payload[0:DATA_FRAG_PAYLOAD_SIZE - 1] == udp_payload
    assert len(
        fragment) == DATA_FRAG_PAYLOAD_SIZE + FRAG_ID_SIZE + FRAG_FLAG_SIZE

    udp_payload = get_random_bytes(1)

    f = FragmentGenerator(udp_payload)

    fragment = f.get_data_fragment()

    _, frag_byte, _, payload = cut(fragment, FRAG_ID_SIZE, FRAG_FLAG_SIZE, 2)

    assert b2i(frag_byte) & FragmentGenerator.LAST_FRAG_FLAG
    assert b2i(frag_byte) & FragmentGenerator.PADDING_FLAG
    assert b2i(frag_byte) == 0b1100_0000
    assert payload[0:1] == udp_payload
    assert len(
        fragment) == DATA_FRAG_PAYLOAD_SIZE + FRAG_ID_SIZE + FRAG_FLAG_SIZE
Ejemplo n.º 8
0
    def _decrypt_fragment(self, fragment):
        ctr = 0

        for key in self.sym_keys:
            ctr, cipher_text = cut(fragment, CTR_PREFIX_LEN)

            ctr = b2i(ctr)

            cipher = ctr_cipher(key, ctr)

            fragment = cipher.decrypt(cipher_text)

        self.replay_detector.check_replay_window(ctr)

        return fragment
Ejemplo n.º 9
0
    def handle_client_request(self, request, src_addr):
        """Takes a message and the source address it came from. The destination
        header is cut off, parsed and mapped to a channel. Then the payload is
        separated into mix fragments and sent out with the channel id in front.
        """
        dest_ip, dest_port, payload = cut(request, IPV4_LEN, PORT_LEN)

        dest_addr = (b2ip(dest_ip), b2i(dest_port))

        if (src_addr, dest_addr) not in self.ips2id:
            channel = self.make_new_channel(src_addr, dest_addr)
        else:
            try:
                channel_id = self.ips2id[src_addr, dest_addr]

                channel = ChannelEntry.table[channel_id]
            except KeyError:
                del self.ips2id[src_addr, dest_addr]
                channel = self.make_new_channel(src_addr, dest_addr)

        # add fragments to internal packet list
        channel.request(payload)
Ejemplo n.º 10
0
def test_decrypt_fragment():
    channel = ChannelEntry(src_addr, dest_addr, public_keys)

    sym_key = gen_sym_key()
    channel.sym_keys = [sym_key] * MIX_COUNT

    fragment = FragmentGenerator(bytes(100)).get_data_fragment()

    fragment = channel._encrypt_fragment(fragment)

    packet1 = channel._decrypt_fragment(fragment)

    for _ in range(MIX_COUNT):
        msg_ctr, fragment = cut(fragment, CTR_PREFIX_LEN)

        cipher = ctr_cipher(sym_key, b2i(msg_ctr))

        fragment = cipher.decrypt(fragment)

    packet2 = fragment

    assert packet1 == packet2
Ejemplo n.º 11
0
    def forward_request(self, request):
        """Takes a mix fragment, already stripped of the channel id."""
        self.last_interaction = time()

        ctr, cipher_text = cut(request, CTR_PREFIX_LEN)
        ctr = b2i(ctr)

        self.request_replay_detector.check_replay_window(ctr)

        cipher = ctr_cipher(self.key, ctr)

        forward_msg = cipher.decrypt(cipher_text) + get_random_bytes(CTR_MODE_PADDING)

        print(self, "Data", "->", len(forward_msg) - CTR_PREFIX_LEN)

        ChannelMid.requests.append(DATA_MSG_FLAG + i2b(self.out_chan_id, CHAN_ID_SIZE) + forward_msg)

        timed_out = check_for_timed_out_channels(ChannelMid.table_in)

        for in_id in timed_out:
            out_id = ChannelMid.table_in[in_id].out_chan_id

            del ChannelMid.table_in[in_id]
            del ChannelMid.table_out[out_id]
Ejemplo n.º 12
0
    "Receives data on the specified ip:port using UDP and prints it on stdout."
)
parser.add_argument("ip:port",
                    help="IP and Port pair to listen for datagrams on.")

BUFFER_SIZE = 65535

if __name__ == "__main__":
    args = parser.parse_args()

    ip, port = getattr(args, "ip:port").split(":")
    port = int(port)

    sock = socket(AF_INET, UDP)
    sock.bind((ip, port))

    packets = 0

    start_time = None

    while True:
        try:
            data, addr = sock.recvfrom(BUFFER_SIZE)

            packets += 1

            print(str(b2i(data[0:4])).rjust(7), "{:.9f}".format(time()))

        except KeyboardInterrupt:
            break
Ejemplo n.º 13
0
output_file = argv[1]

for port_number in argv[2:]:
    listener_socket = socket(AF_INET, SOCK_DGRAM)
    listener_socket.bind(("127.0.0.1", int(port_number)))

    socket_selector.register(listener_socket, EVENT_READ)


def set_killed(signal, stackframe):
    global killed

    killed = True


signal(SIGTERM, set_killed)

killed = False

with open(output_file, "w") as f:
    while not killed:
        events = socket_selector.select(timeout=2)

        for key, _ in events:
            sock = key.fileobj

            data = sock.recv(UDP_MTU)

            f.write("{} {:.9f}\n".format(str(b2i(data[0:4])).rjust(7), time()))
            f.flush()