Beispiel #1
0
 def test_invalid_decoding(self):
     key = KEY_LENGTH * b'\x01'
     encoded = b58encode(
         key)  # 5HpjE2Hs7vjU4SN3YyPQCdhzCu92WoEeuE6PWNuiPyTu3ESGnzn
     changed = encoded[:-1] + 'a'
     with self.assertRaises(ValueError):
         b58decode(changed)
Beispiel #2
0
def determine_selector(selection: str, contact_list: 'ContactList',
                       group_list: 'GroupList') -> bytes:
    """Determine selector (group ID or Onion Service public key)."""
    if selection in contact_list.contact_selectors():
        selector = contact_list.get_contact_by_address_or_nick(
            selection).onion_pub_key

    elif selection in group_list.get_list_of_group_names():
        selector = group_list.get_group(selection).group_id

    elif len(selection) == ONION_ADDRESS_LENGTH:
        if validate_onion_addr(selection):
            raise SoftError("Error: Invalid account.", head_clear=True)
        selector = onion_address_to_pub_key(selection)

    elif len(selection) == GROUP_ID_ENC_LENGTH:
        try:
            selector = b58decode(selection)
        except ValueError:
            raise SoftError("Error: Invalid group ID.", head_clear=True)

    else:
        raise SoftError("Error: Unknown selector.", head_clear=True)

    return selector
Beispiel #3
0
def get_b58_key(k_type: str) -> bytes:
    """Ask user to input Base58 encoded public key from RxM."""
    if k_type == 'pubkey':
        clear_screen()
        c_print("Import public key from RxM", head=1, tail=1)
        c_print("WARNING")
        message_printer(
            "Key exchange will break the HW separation. "
            "Outside specific requests TxM (this computer) "
            "makes, you must never copy any data from "
            "NH/RxM to TxM. Doing so could infect TxM, that "
            "could then later covertly transmit private "
            "keys/messages to adversary on NH.",
            head=1,
            tail=1)
        box_msg = "Enter contact's public key from RxM"
    elif k_type == 'localkey':
        box_msg = "Enter local key decryption key from TxM"
    elif k_type == 'imported_file':
        box_msg = "Enter file decryption key"
    else:
        raise CriticalError("Invalid key type")

    while True:
        pub_key = box_input(box_msg, expected_len=59)
        pub_key = ''.join(pub_key.split())

        try:
            return b58decode(pub_key)
        except ValueError:
            c_print("Checksum error - Check that entered key is correct.",
                    head=1)
            print_on_previous_line(reps=4, delay=1.5)
Beispiel #4
0
def get_b58_key(key_type:      str,         # The type of Base58 key to be entered
                settings:      'Settings',  # Settings object
                short_address: str = ''     # The contact's short Onion address
                ) -> bytes:                 # The Base58 decoded key
    """Ask the user to input a Base58 encoded key."""
    if key_type == B58_PUBLIC_KEY:
        clear_screen()
        m_print(f"{ECDHE} key exchange", head=1, tail=1, bold=True)
        m_print("If needed, resend your public key to the contact by pressing <Enter>", tail=1)

        box_msg = f"Enter public key of {short_address} (from Relay)"
    elif key_type == B58_LOCAL_KEY:
        box_msg = "Enter local key decryption key (from Transmitter)"
    else:
        raise CriticalError("Invalid key type")

    while True:
        rx_pk = box_input(box_msg, key_type=key_type, guide=not (settings.local_testing_mode or settings.qubes))
        rx_pk = ''.join(rx_pk.split())

        if key_type == B58_PUBLIC_KEY and rx_pk == '':
            return rx_pk.encode()

        try:
            return b58decode(rx_pk, public_key=(key_type == B58_PUBLIC_KEY))
        except ValueError:
            m_print("Checksum error - Check that the entered key is correct.")
            print_on_previous_line(reps=(4 if settings.local_testing_mode else 5), delay=1)

            if key_type == B58_PUBLIC_KEY and len(rx_pk) == ENCODED_B58_PUB_KEY_LENGTH:
                raise ValueError(rx_pk)
Beispiel #5
0
def process_group_command(user_input:   'UserInput',
                          contact_list: 'ContactList',
                          group_list:   'GroupList',
                          settings:     'Settings',
                          queues:       'QueueDict',
                          master_key:   'MasterKey'
                          ) -> None:
    """Parse a group command and process it accordingly."""
    if settings.traffic_masking:
        raise FunctionReturn("Error: Command is disabled during traffic masking.", head_clear=True)

    input_parameters = user_input.plaintext.split()  # type: List[str]

    try:
        command_type = input_parameters[1]
    except IndexError:
        raise FunctionReturn("Error: Invalid group command.", head_clear=True)

    if command_type not in ['create', 'join', 'add', 'rm']:
        raise FunctionReturn("Error: Invalid group command.")

    group_id = None  # type: Optional[bytes]
    if command_type == 'join':
        try:
            group_id_s = input_parameters[2]
        except IndexError:
            raise FunctionReturn("Error: No group ID specified.", head_clear=True)
        try:
            group_id = b58decode(group_id_s)
        except ValueError:
            raise FunctionReturn("Error: Invalid group ID.", head_clear=True)

        if group_id in group_list.get_list_of_group_ids():
            raise FunctionReturn("Error: Group with matching ID already exists.", head_clear=True)

    try:
        name_index = 3 if command_type == 'join' else 2
        group_name = input_parameters[name_index]
    except IndexError:
        raise FunctionReturn("Error: No group name specified.", head_clear=True)

    member_index = 4 if command_type == 'join' else 3
    purp_members = input_parameters[member_index:]

    # Swap specified strings to public keys
    selectors = contact_list.contact_selectors()
    pub_keys  = [contact_list.get_contact_by_address_or_nick(m).onion_pub_key for m in purp_members if m in selectors]

    func = dict(create=group_create,
                join  =group_create,
                add   =group_add_member,
                rm    =group_rm_member)[command_type]  # type: Callable

    func(group_name, pub_keys, contact_list, group_list, settings, queues, master_key, group_id)
    print('')
Beispiel #6
0
    def test_bitcoin_wif_test_vectors(self):
        """Test vectors are available at
            https://en.bitcoin.it/wiki/Wallet_import_format
        """
        byte_key = bytes.fromhex("0C28FCA386C7A227600B2FE50B7CAE11"
                                 "EC86D3BF1FBE471BE89827E19D72AA1D")

        b58_key = "5HueCGU8rMjxEXxiPuD5BDku4MkFqeZyd4dZ1jvhTVqvbTLvyTJ"

        self.assertEqual(b58encode(byte_key), b58_key)
        self.assertEqual(b58decode(b58_key), byte_key)
Beispiel #7
0
def group_rm_group(group_name: str,
                   contact_list: 'ContactList',
                   group_list: 'GroupList',
                   settings: 'Settings',
                   queues: 'QueueDict',
                   master_key: 'MasterKey',
                   _: Optional[bytes] = None) -> None:
    """Remove the group with its members."""
    if not yes(f"Remove group '{group_name}'?", abort=False):
        raise FunctionReturn("Group removal aborted.",
                             head=0,
                             delay=1,
                             tail_clear=True)

    if group_name in group_list.get_list_of_group_names():
        group_id = group_list.get_group(group_name).group_id
    else:
        try:
            group_id = b58decode(group_name)
        except ValueError:
            raise FunctionReturn("Error: Invalid group name/ID.",
                                 head_clear=True)

    command = LOG_REMOVE + group_id
    queue_command(command, settings, queues)

    command = GROUP_DELETE + group_id
    queue_command(command, settings, queues)

    if group_list.has_group(group_name):
        with ignored(FunctionReturn):
            remove_logs(contact_list, group_list, settings, master_key,
                        group_id)
    else:
        raise FunctionReturn(
            f"Transmitter has no group '{group_name}' to remove.")

    group = group_list.get_group(group_name)
    if not group.empty() and yes("Notify members about leaving the group?",
                                 abort=False):
        exit_packet = (GROUP_MSG_EXIT_GROUP_HEADER + group.group_id +
                       b''.join(group.get_list_of_member_pub_keys()))
        queue_to_nc(exit_packet, queues[RELAY_PACKET_QUEUE])

    group_list.remove_group_by_name(group_name)
    raise FunctionReturn(f"Removed group '{group_name}'.",
                         head=0,
                         delay=1,
                         tail_clear=True,
                         bold=True)
Beispiel #8
0
def get_b58_key(key_type: str, settings: 'Settings') -> bytes:
    """Ask user to input Base58 encoded public key from RxM.

    For file keys, use testnet address format instead to
    prevent file injected via import from accidentally
    being decrypted with public key from adversary.
    """
    if key_type == B58_PUB_KEY:
        clear_screen()
        c_print("Import public key from RxM", head=1, tail=1)
        c_print("WARNING")
        message_printer(
            "Outside specific requests TxM (this computer) "
            "makes, you must never copy any data from "
            "NH/RxM to TxM. Doing so could infect TxM, that "
            "could then later covertly transmit private "
            "keys/messages to attacker.",
            head=1,
            tail=1)
        message_printer("You can resend your public key by typing 'resend'",
                        tail=1)
        box_msg = "Enter contact's public key from RxM"
    elif key_type == B58_LOCAL_KEY:
        box_msg = "Enter local key decryption key from TxM"
    elif key_type == B58_FILE_KEY:
        box_msg = "Enter file decryption key"
    else:
        raise CriticalError("Invalid key type")

    while True:
        if settings.local_testing_mode or key_type == B58_FILE_KEY:
            pub_key = box_input(box_msg, expected_len=51)
            small = True
        else:
            pub_key = box_input(box_msg, expected_len=65, key_input=True)
            small = False
        pub_key = ''.join(pub_key.split())

        if key_type == B58_PUB_KEY and pub_key == RESEND:
            return pub_key.encode()

        try:
            return b58decode(pub_key, file_key=(key_type == B58_FILE_KEY))
        except ValueError:
            c_print("Checksum error - Check that entered key is correct.",
                    head=1)
            print_on_previous_line(reps=5 if small else 6, delay=1.5)
Beispiel #9
0
def remove_log(user_input: 'UserInput', contact_list: 'ContactList',
               group_list: 'GroupList', settings: 'Settings',
               queues: 'QueueDict', master_key: 'MasterKey') -> None:
    """Remove log entries for contact or group."""
    try:
        selection = user_input.plaintext.split()[1]
    except IndexError:
        raise FunctionReturn("Error: No contact/group specified.",
                             head_clear=True)

    if not yes(f"Remove logs for {selection}?", abort=False, head=1):
        raise FunctionReturn("Log file removal aborted.",
                             tail_clear=True,
                             delay=1,
                             head=0)

    # Determine selector (group ID or Onion Service public key) from command parameters
    if selection in contact_list.contact_selectors():
        selector = contact_list.get_contact_by_address_or_nick(
            selection).onion_pub_key

    elif selection in group_list.get_list_of_group_names():
        selector = group_list.get_group(selection).group_id

    elif len(selection) == ONION_ADDRESS_LENGTH:
        if validate_onion_addr(selection):
            raise FunctionReturn("Error: Invalid account.", head_clear=True)
        selector = onion_address_to_pub_key(selection)

    elif len(selection) == GROUP_ID_ENC_LENGTH:
        try:
            selector = b58decode(selection)
        except ValueError:
            raise FunctionReturn("Error: Invalid group ID.", head_clear=True)

    else:
        raise FunctionReturn("Error: Unknown selector.", head_clear=True)

    # Remove logs that match the selector
    command = LOG_REMOVE + selector
    queue_command(command, settings, queues)

    remove_logs(contact_list, group_list, settings, master_key, selector)
Beispiel #10
0
def validate_group_id(input_parameters: List[str], command_type: str,
                      group_list: 'GroupList') -> Optional[bytes]:
    """Validate group ID for group command."""
    group_id = None  # type: Optional[bytes]
    if command_type == 'join':
        try:
            group_id_s = input_parameters[2]
        except IndexError:
            raise SoftError("Error: No group ID specified.", head_clear=True)
        try:
            group_id = b58decode(group_id_s)
        except ValueError:
            raise SoftError("Error: Invalid group ID.", head_clear=True)

        if group_id in group_list.get_list_of_group_ids():
            raise SoftError("Error: Group with matching ID already exists.",
                            head_clear=True)

    return group_id
Beispiel #11
0
 def test_local_keys_raise_value_error_when_expecting_public_key(self):
     b58_file_key = b58encode(self.key, public_key=True)
     with self.assertRaises(ValueError):
         b58decode(b58_file_key)
Beispiel #12
0
 def test_encoding_and_decoding_of_random_public_keys(self):
     for _ in range(100):
         key = os.urandom(TFC_PUBLIC_KEY_LENGTH)
         encoded = b58encode(key, public_key=True)
         decoded = b58decode(encoded, public_key=True)
         self.assertEqual(key, decoded)
Beispiel #13
0
 def test_encoding_and_decoding_of_random_local_keys(self):
     for _ in range(100):
         key = os.urandom(SYMMETRIC_KEY_LENGTH)
         encoded = b58encode(key)
         decoded = b58decode(encoded)
         self.assertEqual(key, decoded)
Beispiel #14
0
    def test_file_keys_raise_value_error_when_expecting_public_key(self):
        file_key = KEY_LENGTH * b'\x01'
        b58_file_key = b58encode(file_key, file_key=True)

        with self.assertRaises(ValueError):
            b58decode(b58_file_key)
Beispiel #15
0
 def test_encoding_and_decoding_of_random_file_keys(self):
     for _ in range(1000):
         key = os.urandom(KEY_LENGTH)
         encoded = b58encode(key, file_key=True)
         decoded = b58decode(encoded, file_key=True)
         self.assertEqual(key, decoded)
Beispiel #16
0
 def test_invalid_decoding(self):
     key     = 32 * b'\x01'
     encoded = b58encode(key)  # SeLqn3UAUoRymWmwW7axrzJK7JfNaBR2cHCryA6cFsiJ67Em
     changed = encoded[:-1] + 'a'
     with self.assertRaises(ValueError):
         b58decode(changed)
Beispiel #17
0
 def test_function(self):
     for _ in range(1000):
         key     = os.urandom(32)
         encoded = b58encode(key)
         decoded = b58decode(encoded)
         self.assertEqual(key, decoded)
Beispiel #18
0
 def test_invalid_decoding(self) -> None:
     encoded = b58encode(
         self.key)  # 5HpjE2Hs7vjU4SN3YyPQCdhzCu92WoEeuE6PWNuiPyTu3ESGnzn
     changed = encoded[:-1] + 'a'
     with self.assertRaises(ValueError):
         b58decode(changed)