Exemple #1
0
def change_master_key(user_input: 'UserInput', contact_list: 'ContactList',
                      group_list: 'GroupList', settings: 'Settings',
                      queues: 'QueueDict', master_key: 'MasterKey',
                      onion_service: 'OnionService') -> None:
    """Change the master key on Transmitter/Receiver Program."""
    try:
        if settings.traffic_masking:
            raise FunctionReturn(
                "Error: Command is disabled during traffic masking.",
                head_clear=True)

        try:
            device = user_input.plaintext.split()[1].lower()
        except IndexError:
            raise FunctionReturn(
                f"Error: No target-system ('{TX}' or '{RX}') specified.",
                head_clear=True)

        if device not in [TX, RX]:
            raise FunctionReturn(f"Error: Invalid target system '{device}'.",
                                 head_clear=True)

        if device == RX:
            queue_command(CH_MASTER_KEY, settings, queues)
            return None

        old_master_key = master_key.master_key[:]
        new_master_key = master_key.master_key = master_key.new_master_key()

        phase("Re-encrypting databases")

        queues[KEY_MANAGEMENT_QUEUE].put(
            (KDB_CHANGE_MASTER_KEY_HEADER, master_key))

        ensure_dir(DIR_USER_DATA)
        if os.path.isfile(
                f'{DIR_USER_DATA}{settings.software_operation}_logs'):
            change_log_db_key(old_master_key, new_master_key, settings)

        contact_list.store_contacts()
        group_list.store_groups()
        settings.store_settings()
        onion_service.store_onion_service_private_key()

        phase(DONE)
        m_print("Master key successfully changed.",
                bold=True,
                tail_clear=True,
                delay=1,
                head=1)

    except (EOFError, KeyboardInterrupt):
        raise FunctionReturn("Password change aborted.",
                             tail_clear=True,
                             delay=1,
                             head=2)
Exemple #2
0
def ch_master_key(ts: 'datetime', window_list: 'WindowList',
                  contact_list: 'ContactList', group_list: 'GroupList',
                  key_list: 'KeyList', settings: 'Settings',
                  master_key: 'MasterKey') -> None:
    """Prompt the user for a new master password and derive a new master key from that."""
    if not master_key.authenticate_action():
        raise SoftError("Error: Invalid password.",
                        tail_clear=True,
                        delay=1,
                        head=2)

    # Cache old master key to allow log file re-encryption.
    old_master_key = master_key.master_key[:]

    # Create new master key but do not store new master key data into any database.
    new_master_key = master_key.master_key = master_key.new_master_key(
        replace=False)
    phase("Re-encrypting databases")

    # Update encryption keys for databases
    contact_list.database.database_key = new_master_key
    key_list.database.database_key = new_master_key
    group_list.database.database_key = new_master_key
    settings.database.database_key = new_master_key

    # Create temp databases for each database, do not replace original.
    with ignored(SoftError):
        change_log_db_key(old_master_key, new_master_key, settings)
    contact_list.store_contacts(replace=False)
    key_list.store_keys(replace=False)
    group_list.store_groups(replace=False)
    settings.store_settings(replace=False)

    # At this point all temp files exist and they have been checked to be valid by the respective
    # temp file writing function. It's now time to create a temp file for the new master key
    # database. Once the temp master key database is created, the `replace_database_data()` method
    # will also run the atomic `os.replace()` command for the master key database.
    master_key.replace_database_data()

    # Next we do the atomic `os.replace()` for all other files too.
    replace_log_db(settings)
    contact_list.database.replace_database()
    key_list.database.replace_database()
    group_list.database.replace_database()
    settings.database.replace_database()

    phase(DONE)
    m_print("Master password successfully changed.",
            bold=True,
            tail_clear=True,
            delay=1,
            head=1)

    cmd_win = window_list.get_command_window()
    cmd_win.add_new(ts, "Changed Receiver master password.")
Exemple #3
0
    def test_database_encryption_with_another_key(self, _: Any) -> None:
        # Setup
        window = RxWindow(type=WIN_TYPE_CONTACT,
                          uid=nick_to_pub_key('Alice'),
                          name='Alice',
                          type_print='contact')
        contact_list = ContactList(self.old_master_key, self.settings)
        contact_list.contacts = [create_contact('Alice')]
        group_list = GroupList()

        # Create temp file that must be removed.
        temp_file_data = os.urandom(LOG_ENTRY_LENGTH)
        with open(self.tmp_file_name, 'wb+') as f:
            f.write(temp_file_data)

        # Add a message from contact Alice to user (Bob).
        for p in assembly_packet_creator(MESSAGE, 'This is a short message'):
            write_log_entry(p,
                            nick_to_pub_key('Alice'),
                            self.message_log,
                            origin=ORIGIN_CONTACT_HEADER)

        # Add a message from user (Bob) to Alice.
        for p in assembly_packet_creator(MESSAGE, 'This is a short message'):
            write_log_entry(p, nick_to_pub_key('Alice'), self.message_log)

        # Check logfile content.
        message = (CLEAR_ENTIRE_SCREEN + CURSOR_LEFT_UP_CORNER + f"""\
Log file of message(s) sent to contact Alice
════════════════════════════════════════════════════════════════════════════════
{self.time} Alice: This is a short message
{self.time}    Me: This is a short message
<End of log file>

""")
        self.assertIsNone(
            change_log_db_key(self.old_master_key.master_key,
                              self.new_master_key.master_key, self.settings))

        with open(self.tmp_file_name, 'rb') as f:
            purp_temp_data = f.read()
        self.assertNotEqual(purp_temp_data, temp_file_data)

        # Test that decryption with new key is identical.
        replace_log_db(self.settings)
        self.assert_prints(message, access_logs, window, contact_list,
                           group_list, self.settings, self.new_master_key)

        # Test that temp file is removed.
        self.assertFalse(os.path.isfile(self.tmp_file_name))
Exemple #4
0
def ch_master_key(ts: 'datetime', window_list: 'WindowList',
                  contact_list: 'ContactList', group_list: 'GroupList',
                  key_list: 'KeyList', settings: 'Settings',
                  master_key: 'MasterKey') -> None:
    """Prompt the user for a new master password and derive a new master key from that."""
    try:
        old_master_key = master_key.master_key[:]
        master_key.master_key = master_key.new_master_key()

        phase("Re-encrypting databases")

        ensure_dir(DIR_USER_DATA)
        file_name = f'{DIR_USER_DATA}{settings.software_operation}_logs'
        if os.path.isfile(file_name):
            change_log_db_key(old_master_key, master_key.master_key, settings)

        key_list.store_keys()
        settings.store_settings()
        contact_list.store_contacts()
        group_list.store_groups()

        phase(DONE)
        m_print("Master password successfully changed.",
                bold=True,
                tail_clear=True,
                delay=1,
                head=1)

        local_win = window_list.get_local_window()
        local_win.add_new(ts, "Changed Receiver master password.")

    except (EOFError, KeyboardInterrupt):
        raise FunctionReturn("Password change aborted.",
                             tail_clear=True,
                             delay=1,
                             head=2)
Exemple #5
0
def change_master_key(user_input: 'UserInput', contact_list: 'ContactList',
                      group_list: 'GroupList', settings: 'Settings',
                      queues: 'QueueDict', master_key: 'MasterKey',
                      onion_service: 'OnionService') -> None:
    """Change the master key on Transmitter/Receiver Program."""
    if settings.traffic_masking:
        raise SoftError("Error: Command is disabled during traffic masking.",
                        head_clear=True)

    try:
        device = user_input.plaintext.split()[1].lower()
    except IndexError:
        raise SoftError(
            f"Error: No target-system ('{TX}' or '{RX}') specified.",
            head_clear=True)

    if device not in [TX, RX]:
        raise SoftError(f"Error: Invalid target system '{device}'.",
                        head_clear=True)

    if device == RX:
        queue_command(CH_MASTER_KEY, settings, queues)
        return None

    authenticated = master_key.authenticate_action()

    if authenticated:
        # Cache old master key to allow log file re-encryption.
        old_master_key = master_key.master_key[:]

        # Create new master key but do not store new master key data into any database.
        new_master_key = master_key.master_key = master_key.new_master_key(
            replace=False)
        phase("Re-encrypting databases")

        # Halt `sender_loop` for the duration of database re-encryption.
        queues[KEY_MANAGEMENT_QUEUE].put((KDB_M_KEY_CHANGE_HALT_HEADER, ))
        wait_for_key_db_halt(queues)

        # Load old key_list from database file as it's not used on input_loop side.
        key_list = KeyList(master_key, settings)

        # Update encryption keys for databases
        contact_list.database.database_key = new_master_key
        key_list.database.database_key = new_master_key
        group_list.database.database_key = new_master_key
        settings.database.database_key = new_master_key
        onion_service.database.database_key = new_master_key

        # Create temp databases for each database, do not replace original.
        with ignored(SoftError):
            change_log_db_key(old_master_key, new_master_key, settings)
        contact_list.store_contacts(replace=False)
        key_list.store_keys(replace=False)
        group_list.store_groups(replace=False)
        settings.store_settings(replace=False)
        onion_service.store_onion_service_private_key(replace=False)

        # At this point all temp files exist and they have been checked to be valid by the respective
        # temp file writing function. It's now time to create a temp file for the new master key
        # database. Once the temp master key database is created, the `replace_database_data()` method
        # will also run the atomic `os.replace()` command for the master key database.
        master_key.replace_database_data()

        # Next we do the atomic `os.replace()` for all other files too.
        replace_log_db(settings)
        contact_list.database.replace_database()
        key_list.database.replace_database()
        group_list.database.replace_database()
        settings.database.replace_database()
        onion_service.database.replace_database()

        # Now all databases have been updated. It's time to let
        # the key database know what the new master key is.
        queues[KEY_MANAGEMENT_QUEUE].put(new_master_key)

        wait_for_key_db_ack(new_master_key, queues)

        phase(DONE)
        m_print("Master key successfully changed.",
                bold=True,
                tail_clear=True,
                delay=1,
                head=1)