Exemple #1
0
 def test_successful_command_decryption(self):
     packet = assembly_packet_creator(COMMAND,
                                      payload=b"command_data",
                                      encrypt_packet=True)[0]
     self.assertEqual(
         decrypt_assembly_packet(packet, *self.args),
         assembly_packet_creator(COMMAND, payload=b"command_data")[0])
Exemple #2
0
 def test_successful_packet_decryption(self):
     packet = assembly_packet_creator(MESSAGE,
                                      payload="Test message",
                                      encrypt_packet=True)[0]
     self.assertEqual(
         decrypt_assembly_packet(packet, *self.args),
         assembly_packet_creator(MESSAGE, payload="Test message")[0])
Exemple #3
0
 def test_successful_packet_decryption_with_offset(self):
     packet = assembly_packet_creator(MESSAGE,
                                      payload="Test message",
                                      encrypt_packet=True,
                                      message_number=3)[0]
     self.assertEqual(
         decrypt_assembly_packet(packet, *self.args),
         assembly_packet_creator(MESSAGE,
                                 payload="Test message",
                                 message_number=3)[0])
Exemple #4
0
def process_message_packet(
        ts: 'datetime',  # Timestamp of received message packet
        assembly_packet_ct: bytes,  # Encrypted assembly packet
        window_list: 'WindowList',  # WindowList object
        packet_list: 'PacketList',  # PacketList object
        contact_list: 'ContactList',  # ContactList object
        key_list: 'KeyList',  # KeyList object
        group_list: 'GroupList',  # GroupList object
        settings: 'Settings',  # Settings object
        file_keys: Dict[bytes, bytes],  # Dictionary of file decryption keys
        message_log: 'MessageLog',  # MessageLog object
) -> None:
    """Process received message packet."""
    command_window = window_list.get_command_window()

    onion_pub_key, origin, assembly_packet_ct = separate_headers(
        assembly_packet_ct,
        [ONION_SERVICE_PUBLIC_KEY_LENGTH, ORIGIN_HEADER_LENGTH])

    if onion_pub_key == LOCAL_PUBKEY:
        raise SoftError("Warning! Received packet masqueraded as a command.",
                        window=command_window)

    if origin not in [ORIGIN_USER_HEADER, ORIGIN_CONTACT_HEADER]:
        raise SoftError("Error: Received packet had an invalid origin-header.",
                        window=command_window)

    assembly_packet = decrypt_assembly_packet(assembly_packet_ct,
                                              onion_pub_key, origin,
                                              window_list, contact_list,
                                              key_list)

    p_type = (FILE
              if assembly_packet[:ASSEMBLY_PACKET_HEADER_LENGTH].isupper() else
              MESSAGE)
    packet = packet_list.get_packet(onion_pub_key, origin, p_type)
    logging = contact_list.get_contact_by_pub_key(onion_pub_key).log_messages

    try:
        packet.add_packet(assembly_packet)
    except SoftError:
        log_masking_packets(onion_pub_key, origin, logging, settings, packet,
                            message_log)
        raise
    log_masking_packets(onion_pub_key, origin, logging, settings, packet,
                        message_log)

    if packet.is_complete:
        process_complete_message_packet(ts, onion_pub_key, p_type, origin,
                                        logging, packet, window_list,
                                        contact_list, group_list, settings,
                                        message_log, file_keys)
Exemple #5
0
def process_message(ts: 'datetime', assembly_packet_ct: bytes,
                    window_list: 'WindowList', packet_list: 'PacketList',
                    contact_list: 'ContactList', key_list: 'KeyList',
                    group_list: 'GroupList', settings: 'Settings',
                    master_key: 'MasterKey', file_keys: Dict[bytes,
                                                             bytes]) -> None:
    """Process received private / group message."""
    local_window = window_list.get_local_window()

    onion_pub_key, origin, assembly_packet_ct = separate_headers(
        assembly_packet_ct,
        [ONION_SERVICE_PUBLIC_KEY_LENGTH, ORIGIN_HEADER_LENGTH])

    if onion_pub_key == LOCAL_PUBKEY:
        raise FunctionReturn(
            "Warning! Received packet masqueraded as a command.",
            window=local_window)
    if origin not in [ORIGIN_USER_HEADER, ORIGIN_CONTACT_HEADER]:
        raise FunctionReturn(
            "Error: Received packet had an invalid origin-header.",
            window=local_window)

    assembly_packet = decrypt_assembly_packet(assembly_packet_ct,
                                              onion_pub_key, origin,
                                              window_list, contact_list,
                                              key_list)

    p_type = FILE if assembly_packet[:ASSEMBLY_PACKET_HEADER_LENGTH].isupper(
    ) else MESSAGE
    packet = packet_list.get_packet(onion_pub_key, origin, p_type)
    logging = contact_list.get_contact_by_pub_key(onion_pub_key).log_messages

    def log_masking_packets(completed: bool = False) -> None:
        """Add masking packets to log file.

        If logging and log file masking are enabled, this function will
        in case of erroneous transmissions, store the correct number of
        placeholder data packets to log file to hide the quantity of
        communication that log file observation would otherwise reveal.
        """
        if logging and settings.log_file_masking and (packet.log_masking_ctr
                                                      or completed):
            no_masking_packets = len(packet.assembly_pt_list
                                     ) if completed else packet.log_masking_ctr
            for _ in range(no_masking_packets):
                write_log_entry(PLACEHOLDER_DATA, onion_pub_key, settings,
                                master_key, origin)
        packet.log_masking_ctr = 0

    try:
        packet.add_packet(assembly_packet)
    except FunctionReturn:
        log_masking_packets()
        raise
    log_masking_packets()

    if not packet.is_complete:
        return None

    try:
        if p_type == FILE:
            packet.assemble_and_store_file(ts, onion_pub_key, window_list)
            raise FunctionReturn(
                "File storage complete.",
                output=False)  # Raising allows calling log_masking_packets

        elif p_type == MESSAGE:
            whisper_byte, header, assembled = separate_headers(
                packet.assemble_message_packet(),
                [WHISPER_FIELD_LENGTH, MESSAGE_HEADER_LENGTH])
            if len(whisper_byte) != WHISPER_FIELD_LENGTH:
                raise FunctionReturn(
                    "Error: Message from contact had an invalid whisper header."
                )

            whisper = bytes_to_bool(whisper_byte)

            if header == GROUP_MESSAGE_HEADER:
                logging = process_group_message(assembled, ts, onion_pub_key,
                                                origin, whisper, group_list,
                                                window_list)

            elif header == PRIVATE_MESSAGE_HEADER:
                window = window_list.get_window(onion_pub_key)
                window.add_new(ts,
                               assembled.decode(),
                               onion_pub_key,
                               origin,
                               output=True,
                               whisper=whisper)

            elif header == FILE_KEY_HEADER:
                nick = process_file_key_message(assembled, onion_pub_key,
                                                origin, contact_list,
                                                file_keys)
                raise FunctionReturn(
                    f"Received file decryption key from {nick}",
                    window=local_window)

            else:
                raise FunctionReturn(
                    "Error: Message from contact had an invalid header.")

            # Logging
            if whisper:
                raise FunctionReturn("Whisper message complete.", output=False)

            if logging:
                for p in packet.assembly_pt_list:
                    write_log_entry(p, onion_pub_key, settings, master_key,
                                    origin)

    except (FunctionReturn, UnicodeError):
        log_masking_packets(completed=True)
        raise
    finally:
        packet.clear_assembly_packets()
Exemple #6
0
def process_command(ts: 'datetime', assembly_ct: bytes,
                    window_list: 'WindowList', packet_list: 'PacketList',
                    contact_list: 'ContactList', key_list: 'KeyList',
                    group_list: 'GroupList', settings: 'Settings',
                    master_key: 'MasterKey', gateway: 'Gateway',
                    exit_queue: 'Queue[bytes]') -> None:
    """Decrypt command assembly packet and process command."""
    assembly_packet = decrypt_assembly_packet(assembly_ct, LOCAL_PUBKEY,
                                              ORIGIN_USER_HEADER, window_list,
                                              contact_list, key_list)

    cmd_packet = packet_list.get_packet(LOCAL_PUBKEY, ORIGIN_USER_HEADER,
                                        COMMAND)
    cmd_packet.add_packet(assembly_packet)

    if not cmd_packet.is_complete:
        raise FunctionReturn("Incomplete command.", output=False)

    header, cmd = separate_header(cmd_packet.assemble_command_packet(),
                                  ENCRYPTED_COMMAND_HEADER_LENGTH)
    no = None

    #    Keyword        Function to run (                                 Parameters                                  )
    #    --------------------------------------------------------------------------------------------------------------
    d = {
        LOCAL_KEY_RDY: (local_key_rdy, ts, window_list, contact_list),
        WIN_ACTIVITY: (win_activity, window_list),
        WIN_SELECT: (win_select, cmd, window_list),
        CLEAR_SCREEN: (clear_screen, ),
        RESET_SCREEN: (reset_screen, cmd, window_list),
        EXIT_PROGRAM: (exit_tfc, exit_queue),
        LOG_DISPLAY: (log_command, cmd, no, window_list, contact_list,
                      group_list, settings, master_key),
        LOG_EXPORT: (log_command, cmd, ts, window_list, contact_list,
                     group_list, settings, master_key),
        LOG_REMOVE:
        (remove_log, cmd, contact_list, group_list, settings, master_key),
        CH_MASTER_KEY: (ch_master_key, ts, window_list, contact_list,
                        group_list, key_list, settings, master_key),
        CH_NICKNAME: (
            ch_nick,
            cmd,
            ts,
            window_list,
            contact_list,
        ),
        CH_SETTING: (ch_setting, cmd, ts, window_list, contact_list,
                     group_list, key_list, settings, gateway),
        CH_LOGGING:
        (ch_contact_s, cmd, ts, window_list, contact_list, group_list, header),
        CH_FILE_RECV:
        (ch_contact_s, cmd, ts, window_list, contact_list, group_list, header),
        CH_NOTIFY:
        (ch_contact_s, cmd, ts, window_list, contact_list, group_list, header),
        GROUP_CREATE: (group_create, cmd, ts, window_list, contact_list,
                       group_list, settings),
        GROUP_ADD: (group_add, cmd, ts, window_list, contact_list, group_list,
                    settings),
        GROUP_REMOVE: (group_remove, cmd, ts, window_list, contact_list,
                       group_list),
        GROUP_DELETE: (group_delete, cmd, ts, window_list, group_list),
        GROUP_RENAME: (group_rename, cmd, ts, window_list, contact_list,
                       group_list),
        KEY_EX_ECDHE: (key_ex_ecdhe, cmd, ts, window_list, contact_list,
                       key_list, settings),
        KEY_EX_PSK_TX: (key_ex_psk_tx, cmd, ts, window_list, contact_list,
                        key_list, settings),
        KEY_EX_PSK_RX: (key_ex_psk_rx, cmd, ts, window_list, contact_list,
                        key_list, settings),
        CONTACT_REM: (contact_rem, cmd, ts, window_list, contact_list,
                      group_list, key_list, settings, master_key),
        WIPE_USR_DATA: (wipe, exit_queue)
    }  # type: Dict[bytes, Any]

    try:
        from_dict = d[header]
    except KeyError:
        raise FunctionReturn("Error: Received an invalid command.")

    func = from_dict[0]
    parameters = from_dict[1:]
    func(*parameters)