Ejemplo n.º 1
0
 def serialize_c(self) -> bytes:
     """Return contact data as constant length byte string."""
     return (str_to_bytes(self.rx_account)
             + str_to_bytes(self.tx_account)
             + str_to_bytes(self.nick)
             + self.tx_fingerprint
             + self.rx_fingerprint
             + bool_to_bytes(self.log_messages)
             + bool_to_bytes(self.file_reception)
             + bool_to_bytes(self.notifications))
Ejemplo n.º 2
0
    def store_settings(self) -> None:
        """Store persistent settings to file."""
        setting_data = int_to_bytes(self.serial_baudrate)
        setting_data += int_to_bytes(self.serial_error_correction)
        setting_data += bool_to_bytes(self.serial_usb_adapter)
        setting_data += bool_to_bytes(self.disable_gui_dialog)

        ensure_dir(DIR_USER_DATA)
        with open(self.file_name, 'wb+') as f:
            f.write(setting_data)
Ejemplo n.º 3
0
 def dump_c(self) -> bytes:
     """Return contact data as constant length byte string."""
     return   str_to_bytes(self.rx_account) \
            + str_to_bytes(self.tx_account) \
            + str_to_bytes(self.nick) \
            + self.tx_fingerprint \
            + self.rx_fingerprint \
            + bool_to_bytes(self.log_messages) \
            + bool_to_bytes(self.file_reception) \
            + bool_to_bytes(self.notifications)
Ejemplo n.º 4
0
    def serialize_g(self) -> bytes:
        """Return group data as constant length byte string."""
        name = str_to_bytes(self.name)
        log_messages = bool_to_bytes(self.log_messages)
        notifications = bool_to_bytes(self.notifications)
        members = self.get_list_of_member_accounts()
        num_of_dummies = self.settings.max_number_of_group_members - len(
            self.members)
        members += num_of_dummies * [DUMMY_MEMBER]
        member_bytes = b''.join([str_to_bytes(m) for m in members])

        return name + log_messages + notifications + member_bytes
Ejemplo n.º 5
0
    def generate_dummy_contact() -> bytes:
        """Generate byte string for dummy contact."""
        rx_account     = str_to_bytes('dummy_contact')
        tx_account     = str_to_bytes('dummy_user')
        nick           = str_to_bytes('dummy_nick')
        tx_fingerprint = bytes(32)
        rx_fingerprint = bytes(32)
        logging_bytes  = bool_to_bytes(False)
        file_r_bytes   = bool_to_bytes(False)
        notify_bytes   = bool_to_bytes(False)

        return rx_account + tx_account + nick \
               + tx_fingerprint + rx_fingerprint \
               + logging_bytes + file_r_bytes + notify_bytes
Ejemplo n.º 6
0
    def serialize_c(self) -> bytes:
        """Return contact data as a constant length byte string.

        This function serializes the contact's data into a byte string
        that has the exact length of 3*32 + 4*1 + 1024 = 1124 bytes. The
        length is guaranteed regardless of the content or length of the
        attributes' values, including the contact's nickname. The
        purpose of the constant length serialization is to hide any
        metadata about the contact the ciphertext length of the contact
        database would reveal.
        """
        return (self.onion_pub_key + self.tx_fingerprint +
                self.rx_fingerprint + self.kex_status +
                bool_to_bytes(self.log_messages) +
                bool_to_bytes(self.file_reception) +
                bool_to_bytes(self.notifications) + str_to_bytes(self.nick))
Ejemplo n.º 7
0
    def test_empty_whisper_msg_from_user(self, _):
        # Setup
        assembly_ct_list = assembly_packet_creator(MESSAGE, '', origin_header=ORIGIN_USER_HEADER,
                                                   encrypt_packet=True, onion_pub_key=nick_to_pub_key('Alice'),
                                                   whisper_header=bool_to_bytes(True))
        # Test
        for p in assembly_ct_list[:-1]:
            self.assertIsNone(process_message(self.ts, p, *self.args))

        for p in assembly_ct_list[-1:]:
            self.assert_fr("Whisper message complete.", process_message, self.ts, p, *self.args)

        self.assertEqual(os.path.getsize(self.file_name), len(assembly_ct_list)*LOG_ENTRY_LENGTH)
Ejemplo n.º 8
0
    def test_successful_export_command(self, *_):
        # Setup
        self.window.type = WIN_TYPE_CONTACT
        self.window.uid = nick_to_pub_key('Alice')
        whisper_header = bool_to_bytes(False)
        packet = split_to_assembly_packets(
            whisper_header + PRIVATE_MESSAGE_HEADER + b'test', MESSAGE)[0]
        write_log_entry(packet, nick_to_pub_key('Alice'), self.settings,
                        self.master_key)

        # Test
        for command in ['export', 'export 1']:
            self.assert_fr(f"Exported log file of contact 'Alice'.",
                           log_command, UserInput(command), self.window,
                           ContactList(nicks=['Alice']), self.group_list,
                           self.settings, self.queues, self.master_key)
Ejemplo n.º 9
0
    def store_settings(self) -> None:
        """Store settings to encrypted database."""
        attribute_list = [self.__getattribute__(k) for k in self.key_list]

        # Convert attributes into constant length byte string
        pt_bytes = b''
        for a in attribute_list:
            if isinstance(a, bool): pt_bytes += bool_to_bytes(a)
            elif isinstance(a, int): pt_bytes += int_to_bytes(a)
            elif isinstance(a, float): pt_bytes += double_to_bytes(a)
            elif isinstance(a, str): pt_bytes += str_to_bytes(a)
            else: raise CriticalError("Invalid attribute type in settings.")

        ct_bytes = encrypt_and_sign(pt_bytes, self.master_key.master_key)

        ensure_dir(f'{DIR_USER_DATA}/')
        with open(self.file_name, 'wb+') as f:
            f.write(ct_bytes)
Ejemplo n.º 10
0
def change_setting(user_input: 'UserInput', window: 'TxWindow',
                   contact_list: 'ContactList', group_list: 'GroupList',
                   settings: 'Settings', queues: 'QueueDict',
                   master_key: 'MasterKey', gateway: 'Gateway') -> None:
    """Change setting on Transmitter and Receiver Program."""
    # Validate the KV-pair
    try:
        setting = user_input.plaintext.split()[1]
    except IndexError:
        raise FunctionReturn("Error: No setting specified.", head_clear=True)

    if setting not in (settings.key_list + gateway.settings.key_list):
        raise FunctionReturn(f"Error: Invalid setting '{setting}'.",
                             head_clear=True)

    try:
        value = user_input.plaintext.split()[2]
    except IndexError:
        raise FunctionReturn("Error: No value for setting specified.",
                             head_clear=True)

    # Check if the setting can be changed
    relay_settings = dict(
        serial_error_correction=UNENCRYPTED_EC_RATIO,
        serial_baudrate=UNENCRYPTED_BAUDRATE,
        allow_contact_requests=UNENCRYPTED_MANAGE_CONTACT_REQ)
    if settings.traffic_masking and (setting in relay_settings
                                     or setting == 'max_number_of_contacts'):
        raise FunctionReturn(
            "Error: Can't change this setting during traffic masking.",
            head_clear=True)

    if setting in ['use_serial_usb_adapter', 'built_in_serial_interface']:
        raise FunctionReturn(
            "Error: Serial interface setting can only be changed manually.",
            head_clear=True)

    if setting == 'ask_password_for_log_access':
        try:
            authenticated = master_key.load_master_key(
            ) == master_key.master_key
        except (EOFError, KeyboardInterrupt):
            raise FunctionReturn(f"Setting change aborted.",
                                 tail_clear=True,
                                 head=2,
                                 delay=1)

        if not authenticated:
            raise FunctionReturn("Error: No permission to change setting.",
                                 head_clear=True)

    # Change the setting
    if setting in gateway.settings.key_list:
        gateway.settings.change_setting(setting, value)
    else:
        settings.change_setting(setting, value, contact_list, group_list)

    receiver_command = CH_SETTING + setting.encode() + US_BYTE + value.encode()
    queue_command(receiver_command, settings, queues)

    if setting in relay_settings:
        if setting == 'allow_contact_requests':
            value = bool_to_bytes(settings.allow_contact_requests).decode()
        relay_command = UNENCRYPTED_DATAGRAM_HEADER + relay_settings[
            setting] + value.encode()
        queue_to_nc(relay_command, queues[RELAY_PACKET_QUEUE])

    # Propagate the effects of the setting
    if setting == 'max_number_of_contacts':
        contact_list.store_contacts()
        queues[KEY_MANAGEMENT_QUEUE].put((KDB_UPDATE_SIZE_HEADER, settings))

    if setting in ['max_number_of_group_members', 'max_number_of_groups']:
        group_list.store_groups()

    if setting == 'traffic_masking':
        queues[SENDER_MODE_QUEUE].put(settings)
        queues[TRAFFIC_MASKING_QUEUE].put(settings.traffic_masking)
        window.deselect()

    if setting == 'log_file_masking':
        queues[LOGFILE_MASKING_QUEUE].put(settings.log_file_masking)
Ejemplo n.º 11
0
        def queue_delayer():
            """Place datagrams into queue after delay."""
            o_sleep(test_delay)
            local_harac = INITIAL_HARAC
            tx_harac = INITIAL_HARAC
            local_hek = SYMMETRIC_KEY_LENGTH * b'a'
            file_key = SYMMETRIC_KEY_LENGTH * b'b'
            local_key = SYMMETRIC_KEY_LENGTH * b'a'
            tx_mk = SYMMETRIC_KEY_LENGTH * b'a'
            tx_hk = SYMMETRIC_KEY_LENGTH * b'a'

            # Queue local key packet
            local_key_packet = encrypt_and_sign(local_key + local_hek +
                                                conf_code,
                                                key=kek)
            queues[LOCAL_KEY_DATAGRAM_HEADER].put(
                (datetime.datetime.now(), local_key_packet))
            o_sleep(test_delay)

            # Select file window
            command = WIN_SELECT + WIN_UID_FILE
            queue_packet(local_key, tx_hk, local_harac, command)
            local_key, local_harac = rotate_key(local_key, local_harac)
            o_sleep(test_delay)

            # Select local window
            command = WIN_SELECT + WIN_UID_LOCAL
            queue_packet(local_key, tx_hk, local_harac, command)
            local_key, local_harac = rotate_key(local_key, local_harac)
            o_sleep(test_delay)

            # A message that goes to buffer
            queue_packet(
                tx_mk, tx_hk, tx_harac,
                bool_to_bytes(False) + PRIVATE_MESSAGE_HEADER + b'Hi Bob',
                tx_pub_key)
            tx_mk, tx_harac = rotate_key(tx_mk, tx_harac)

            # ECDHE keyset for Bob
            command = KEY_EX_ECDHE + nick_to_pub_key("Bob") + (
                4 * SYMMETRIC_KEY_LENGTH * b'a') + str_to_bytes('Bob')
            queue_packet(local_key, tx_hk, local_harac, command)
            local_key, local_harac = rotate_key(local_key, local_harac)
            o_sleep(test_delay)

            # Message for Bob
            queue_packet(
                tx_mk, tx_hk, tx_harac,
                bool_to_bytes(False) + PRIVATE_MESSAGE_HEADER + b'Hi Bob',
                tx_pub_key)
            tx_mk, tx_harac = rotate_key(tx_mk, tx_harac)
            o_sleep(test_delay)

            # Enable file reception for Bob
            command = CH_FILE_RECV + ENABLE.upper() + US_BYTE
            queue_packet(local_key, tx_hk, local_harac, command)
            o_sleep(test_delay)

            # File packet from Bob
            ct = encrypt_and_sign(b'test', file_key)
            f_hash = blake2b(ct)
            packet = nick_to_pub_key('Bob') + ORIGIN_CONTACT_HEADER + ct
            queues[FILE_DATAGRAM_HEADER].put((datetime.datetime.now(), packet))
            o_sleep(test_delay)

            # File key packet from Bob
            queue_packet(
                tx_mk, tx_hk, tx_harac,
                bool_to_bytes(False) + FILE_KEY_HEADER +
                base64.b85encode(f_hash + file_key), tx_pub_key)
            o_sleep(test_delay)

            # Queue exit message to break the loop
            o_sleep(0.5)
            queues[UNITTEST_QUEUE].put(EXIT)
            o_sleep(test_delay)