def test_invalid_group_message_header(self): # Setup message = b'testgroup' ts = datetime.datetime.now() apct_list = self.create_message_apct(ORIGIN_CONTACT_HEADER, message, header=GROUP_MESSAGE_HEADER) contact_list = ContactList(nicks=['Alice', 'Bob', 'local']) key_list = KeyList(nicks=['Alice', 'Bob', 'local']) keyset = key_list.get_keyset('*****@*****.**') keyset.rx_harac = 1 keyset.rx_key = 32 * b'\x01' keyset.rx_hek = 32 * b'\x01' group_list = GroupList(groups=['testgroup']) settings = Settings() packet_list = PacketList(contact_list=contact_list, settings=settings) window_list = WindowList(contact_list=contact_list, group_list=group_list, packet_list=packet_list, settings=settings) master_key = MasterKey() # Test for p in apct_list: self.assertFR("Received an invalid group message.", process_message, ts, p, window_list, packet_list, contact_list, key_list, group_list, settings, master_key)
def test_valid_psk(self): # Setup packet = b'*****@*****.**' contact_list = ContactList(nicks=['Alice', 'local']) key_list = KeyList(nicks=['Alice', 'local']) keyset = key_list.get_keyset('*****@*****.**') keyset.rx_key = bytes(32) keyset.rx_hek = bytes(32) window_list = WindowList(nicks=['Alice', 'local']) ts = datetime.datetime.now() settings = Settings(disable_gui_dialog=True) o_input = builtins.input o_getpass = getpass.getpass builtins.input = lambda x: 'ut_psk' getpass.getpass = lambda x: 'testpassword' password = '******' salt = os.urandom(32) rx_key = os.urandom(32) rx_hek = os.urandom(32) kek, _ = argon2_kdf(password, salt, rounds=16, memory=128000, parallelism=1) ct_tag = encrypt_and_sign(rx_key + rx_hek, key=kek) with open('ut_psk', 'wb+') as f: f.write(salt + ct_tag) # Test self.assertTrue(os.path.isfile('ut_psk')) self.assertIsNone(psk_import(packet, ts, window_list, contact_list, key_list, settings)) self.assertFalse(os.path.isfile('ut_psk')) self.assertEqual(keyset.rx_key, rx_key) self.assertEqual(keyset.rx_hek, rx_hek) # Teardown builtins.input = o_input getpass.getpass = o_getpass
def test_invalid_window_raises_fr(self): # Setup message = b'testgroup' ts = datetime.datetime.now() timestamp = double_to_bytes(time.time() * 1000) header = GROUP_MESSAGE_HEADER + timestamp + b'test_group' + US_BYTE apct_list = self.create_message_apct(ORIGIN_CONTACT_HEADER, message, header=header) contact_list = ContactList(nicks=['Alice', 'Bob', 'local']) key_list = KeyList(nicks=['Alice', 'Bob', 'local']) keyset = key_list.get_keyset('*****@*****.**') keyset.rx_harac = 1 keyset.rx_key = 32 * b'\x01' keyset.rx_hek = 32 * b'\x01' group_list = GroupList(groups=['testgroup']) settings = Settings() packet_list = PacketList(contact_list=contact_list, settings=settings) window_list = WindowList(contact_list=contact_list, group_list=group_list, packet_list=packet_list, settings=settings) master_key = MasterKey() # Test for p in apct_list: self.assertFR("Received message to unknown group.", process_message, ts, p, window_list, packet_list, contact_list, key_list, group_list, settings, master_key) # Teardown cleanup()
def test_function(self): # Setup packet = 32 * b'\x01' + 32 * b'\x02' + b'*****@*****.**' + US_BYTE + b'Alice' ts = datetime.datetime.now() window_list = WindowList(nicks=['local']) settings = Settings() pubkey_buf = dict() contact_list = ContactList() key_list = KeyList() # Test self.assertIsNone(psk_command(packet, ts, window_list, contact_list, key_list, settings, pubkey_buf)) keyset = key_list.get_keyset('*****@*****.**') self.assertIsInstance(keyset, KeySet) self.assertEqual(keyset.rx_account, '*****@*****.**') self.assertEqual(keyset.tx_key, 32 * b'\x01') self.assertEqual(keyset.tx_hek, 32 * b'\x02') self.assertEqual(keyset.rx_key, bytes(32)) self.assertEqual(keyset.rx_hek, bytes(32)) contact = contact_list.get_contact('*****@*****.**') self.assertIsInstance(contact, Contact) self.assertEqual(contact.rx_account, '*****@*****.**') self.assertEqual(contact.nick, 'Alice') self.assertEqual(contact.rx_fingerprint, bytes(32)) self.assertEqual(contact.tx_fingerprint, bytes(32))
def test_group_msg(self): # Setup ts = datetime.datetime.now() apct_list = self.create_message_apct(ORIGIN_CONTACT_HEADER, b'testmessage', group_name=b'testgroup') contact_list = ContactList(nicks=['Alice', 'Bob', 'local']) key_list = KeyList(nicks=['Alice', 'Bob', 'local']) keyset = key_list.get_keyset('*****@*****.**') keyset.rx_harac = 1 keyset.rx_key = 32 * b'\x01' keyset.rx_hek = 32 * b'\x01' group_list = GroupList(groups=['testgroup']) group = group_list.get_group('testgroup') group.log_messages = True settings = Settings() packet_list = PacketList(contact_list=contact_list, settings=settings) window_list = WindowList(contact_list=contact_list, group_list=group_list, packet_list=packet_list, settings=settings) master_key = MasterKey() # Test for p in apct_list: self.assertIsNone( process_message(ts, p, window_list, packet_list, contact_list, key_list, group_list, settings, master_key)) # Teardown cleanup()
class TestAddPSKTxKeys(unittest.TestCase): def setUp(self): self.ts = datetime.datetime.now() self.window_list = WindowList(nicks=[LOCAL_ID]) self.contact_list = ContactList() self.key_list = KeyList() self.settings = Settings() self.pubkey_buf = {'*****@*****.**' : KEY_LENGTH*b'a'} self.packet = KEY_LENGTH * b'\x01' + KEY_LENGTH * b'\x02' + b'*****@*****.**' + US_BYTE + b'Alice' def test_add_psk_tx_keys(self): self.assertIsNone(add_psk_tx_keys(self.packet, self.ts, self.window_list, self.contact_list, self.key_list, self.settings, self.pubkey_buf)) keyset = self.key_list.get_keyset('*****@*****.**') self.assertIsInstance(keyset, KeySet) self.assertEqual(keyset.rx_account, '*****@*****.**') self.assertEqual(keyset.tx_key, KEY_LENGTH * b'\x01') self.assertEqual(keyset.tx_hek, KEY_LENGTH * b'\x02') self.assertEqual(keyset.rx_key, bytes(KEY_LENGTH)) self.assertEqual(keyset.rx_hek, bytes(KEY_LENGTH)) contact = self.contact_list.get_contact('*****@*****.**') self.assertIsInstance(contact, Contact) self.assertEqual(contact.rx_account, '*****@*****.**') self.assertEqual(contact.nick, 'Alice') self.assertEqual(contact.rx_fingerprint, bytes(FINGERPRINT_LEN)) self.assertEqual(contact.tx_fingerprint, bytes(FINGERPRINT_LEN)) self.assertFalse('*****@*****.**' in self.pubkey_buf)
def test_file(self): # Setup ts = datetime.datetime.now() apct_list = self.create_file_apct() contact_list = ContactList(nicks=['Alice', 'Bob', 'local']) key_list = KeyList(nicks=['Alice', 'Bob', 'local']) keyset = key_list.get_keyset('*****@*****.**') keyset.rx_harac = 1 keyset.rx_key = 32 * b'\x01' keyset.rx_hek = 32 * b'\x01' group_list = GroupList(groups=['testgroup']) settings = Settings() packet_list = PacketList(contact_list=contact_list, settings=settings) window_list = WindowList(contact_list=contact_list, group_list=group_list, packet_list=packet_list, settings=settings) master_key = MasterKey() # Test for p in apct_list: self.assertIsNone( process_message(ts, p, window_list, packet_list, contact_list, key_list, group_list, settings, master_key)) # Teardown shutil.rmtree('received_files/')
def test_group_remove_member_msg(self): # Setup message = b'testgroup' + US_BYTE + b'*****@*****.**' + US_BYTE + b'*****@*****.**' ts = datetime.datetime.now() apct_list = self.create_message_apct(ORIGIN_CONTACT_HEADER, message, header=GROUP_MSG_MEMBER_RM_HEADER) contact_list = ContactList(nicks=['Alice', 'Bob', 'local']) key_list = KeyList(nicks=['Alice', 'Bob', 'local']) keyset = key_list.get_keyset('*****@*****.**') keyset.rx_harac = 1 keyset.rx_key = 32 * b'\x01' keyset.rx_hek = 32 * b'\x01' group_list = GroupList(groups=['testgroup']) settings = Settings() packet_list = PacketList(contact_list=contact_list, settings=settings) window_list = WindowList(contact_list=contact_list, group_list=group_list, packet_list=packet_list, settings=settings) master_key = MasterKey() # Test for p in apct_list: self.assertIsNone( process_message(ts, p, window_list, packet_list, contact_list, key_list, group_list, settings, master_key)) # Teardown cleanup()
class TestProcessCommand(TFCTestCase): def setUp(self): self.unittest_dir = cd_unittest() self.ts = datetime.now() self.settings = Settings() self.master_key = MasterKey() self.group_list = GroupList() self.exit_queue = Queue() self.gateway = Gateway() self.window_list = WindowList(nicks=[LOCAL_ID]) self.contact_list = ContactList(nicks=[LOCAL_ID]) self.packet_list = PacketList(self.settings, self.contact_list) self.key_list = KeyList(nicks=[LOCAL_ID]) self.key_set = self.key_list.get_keyset(LOCAL_PUBKEY) self.args = (self.window_list, self.packet_list, self.contact_list, self.key_list, self.group_list, self.settings, self.master_key, self.gateway, self.exit_queue) def tearDown(self): cleanup(self.unittest_dir) def test_incomplete_command_raises_fr(self): packet = assembly_packet_creator(COMMAND, b'test_command', s_header_override=C_L_HEADER, encrypt_packet=True)[0] self.assert_fr("Incomplete command.", process_command, self.ts, packet, *self.args) def test_invalid_command_header(self): packet = assembly_packet_creator(COMMAND, b'invalid_header', encrypt_packet=True)[0] self.assert_fr("Error: Received an invalid command.", process_command, self.ts, packet, *self.args) def test_process_command(self): packet = assembly_packet_creator(COMMAND, LOG_REMOVE, encrypt_packet=True)[0] self.assert_fr(f"No log database available.", process_command, self.ts, packet, *self.args)
def test_missing_rx_psk_raises_fr(self): # Setup packet = MESSAGE_PACKET_HEADER + 344 * b'a' + ORIGIN_CONTACT_HEADER + b'*****@*****.**' window_list = WindowList(nicks=['Alice', 'local']) contact_list = ContactList(nicks=['Alice', 'local']) key_list = KeyList(nicks=['Alice', 'local']) keyset = key_list.get_keyset('*****@*****.**') keyset.rx_hek = bytes(32) # Set to identify missing PSK # Test self.assertFR("Warning! Received packet from Alice but no PSK exists.", decrypt_assembly_packet, packet, window_list, contact_list, key_list)
class TestKeyExPSKTx(TFCTestCase): def setUp(self): """Pre-test actions.""" self.ts = datetime.fromtimestamp(1502750000) self.window_list = WindowList(nicks=[LOCAL_ID]) self.contact_list = ContactList() self.key_list = KeyList() self.settings = Settings() self.packet = (nick_to_pub_key("Alice") + SYMMETRIC_KEY_LENGTH * b'\x01' + bytes(SYMMETRIC_KEY_LENGTH) + SYMMETRIC_KEY_LENGTH * b'\x02' + bytes(SYMMETRIC_KEY_LENGTH) + str_to_bytes('Alice')) self.args = self.packet, self.ts, self.window_list, self.contact_list, self.key_list, self.settings @mock.patch('time.sleep', return_value=None) def test_invalid_nick_raises_fr(self, _): self.packet = (nick_to_pub_key("Alice") + SYMMETRIC_KEY_LENGTH * b'\x01' + bytes(SYMMETRIC_KEY_LENGTH) + SYMMETRIC_KEY_LENGTH * b'\x02' + bytes(SYMMETRIC_KEY_LENGTH) + UNDECODABLE_UNICODE) self.args = self.packet, self.ts, self.window_list, self.contact_list, self.key_list, self.settings self.assert_fr("Error: Received invalid contact data", key_ex_psk_tx, *self.args) @mock.patch('time.sleep', return_value=None) def test_add_psk_tx_keys(self, _): self.assertIsNone(key_ex_psk_tx(*self.args)) keyset = self.key_list.get_keyset(nick_to_pub_key("Alice")) self.assertIsInstance(keyset, KeySet) self.assertEqual(keyset.onion_pub_key, nick_to_pub_key("Alice")) self.assertEqual(keyset.tx_mk, SYMMETRIC_KEY_LENGTH * b'\x01') self.assertEqual(keyset.rx_mk, bytes(SYMMETRIC_KEY_LENGTH)) self.assertEqual(keyset.tx_hk, SYMMETRIC_KEY_LENGTH * b'\x02') self.assertEqual(keyset.rx_hk, bytes(SYMMETRIC_KEY_LENGTH)) contact = self.contact_list.get_contact_by_pub_key(nick_to_pub_key("Alice")) self.assertIsInstance(contact, Contact) self.assertEqual(contact.onion_pub_key, nick_to_pub_key("Alice")) self.assertEqual(contact.nick, 'Alice') self.assertEqual(contact.tx_fingerprint, bytes(FINGERPRINT_LENGTH)) self.assertEqual(contact.rx_fingerprint, bytes(FINGERPRINT_LENGTH))
def test_expired_harac_raises_fr(self): # Setup encrypted_message = encrypt_and_sign(PRIVATE_MESSAGE_HEADER + byte_padding(b'test'), 32 * b'\x01') harac_in_bytes = int_to_bytes(1) encrypted_harac = encrypt_and_sign(harac_in_bytes, 32 * b'\x01') packet = MESSAGE_PACKET_HEADER + encrypted_harac + encrypted_message + ORIGIN_CONTACT_HEADER + b'*****@*****.**' window_list = WindowList(nicks=['Alice', 'local']) contact_list = ContactList(nicks=['Alice', 'local']) key_list = KeyList(nicks=['Alice', 'local']) keyset = key_list.get_keyset('*****@*****.**') keyset.rx_harac = 3 # Test self.assertFR("Warning! Received packet from Alice had an expired hash ratchet counter.", decrypt_assembly_packet, packet, window_list, contact_list, key_list)
class TestProcessCommand(TFCTestCase): def setUp(self): self.ts = datetime.now() self.settings = Settings() self.master_key = MasterKey() self.group_list = GroupList() self.exit_queue = Queue() self.pubkey_buf = dict() self.window_list = WindowList(nicks=[LOCAL_ID]) self.contact_list = ContactList(nicks=[LOCAL_ID]) self.packet_list = PacketList(self.settings, self.contact_list) self.key_list = KeyList(nicks=[LOCAL_ID]) self.key_set = self.key_list.get_keyset(LOCAL_ID) self.key_set.rx_key = bytes(KEY_LENGTH) self.key_set.rx_hek = bytes(KEY_LENGTH) self.key_set.tx_harac = 1 self.key_set.rx_harac = 1 def create_packet(self, data, header=C_S_HEADER): payload = zlib.compress(data, level=COMPRESSION_LEVEL) packet = header + byte_padding(payload) harac_in_bytes = int_to_bytes(self.key_set.tx_harac) encrypted_harac = encrypt_and_sign(harac_in_bytes, self.key_set.tx_hek) encrypted_message = encrypt_and_sign(packet, self.key_set.tx_key) return COMMAND_PACKET_HEADER + encrypted_harac + encrypted_message def test_incomplete_command_raises_fr(self): self.assertFR("Incomplete command.", process_command, self.ts, self.create_packet(b'ZZ', header=C_L_HEADER), self.window_list, self.packet_list, self.contact_list, self.key_list, self.group_list, self.settings, self.master_key, self.pubkey_buf, self.exit_queue) def test_invalid_command_header(self): self.assertFR("Error: Received an invalid command.", process_command, self.ts, self.create_packet(b'ZZ'), self.window_list, self.packet_list, self.contact_list, self.key_list, self.group_list, self.settings, self.master_key, self.pubkey_buf, self.exit_queue) def test_process_command(self): self.assertFR(f"Error: Could not find log database.", process_command, self.ts, self.create_packet(LOG_REMOVE_HEADER), self.window_list, self.packet_list, self.contact_list, self.key_list, self.group_list, self.settings, self.master_key, self.pubkey_buf, self.exit_queue)
class TestProcessCommand(TFCTestCase): def setUp(self) -> None: """Pre-test actions.""" self.unit_test_dir = cd_unit_test() self.ts = datetime.now() self.settings = Settings() self.master_key = MasterKey() self.group_list = GroupList() self.exit_queue = Queue() self.gateway = Gateway() self.window_list = WindowList(nicks=[LOCAL_ID]) self.contact_list = ContactList(nicks=[LOCAL_ID]) self.packet_list = PacketList(self.settings, self.contact_list) self.key_list = KeyList(nicks=[LOCAL_ID]) self.key_set = self.key_list.get_keyset(LOCAL_PUBKEY) self.args = (self.window_list, self.packet_list, self.contact_list, self.key_list, self.group_list, self.settings, self.master_key, self.gateway, self.exit_queue) def tearDown(self) -> None: """Post-test actions.""" cleanup(self.unit_test_dir) tear_queue(self.exit_queue) def test_incomplete_command_raises_soft_error(self) -> None: packet = assembly_packet_creator(COMMAND, b'test_command', s_header_override=C_L_HEADER, encrypt_packet=True)[0] self.assert_se("Incomplete command.", process_command, self.ts, packet, *self.args) def test_invalid_command_header(self) -> None: packet = assembly_packet_creator(COMMAND, b'invalid_header', encrypt_packet=True)[0] self.assert_se("Error: Received an invalid command.", process_command, self.ts, packet, *self.args) def test_process_command(self) -> None: packet = assembly_packet_creator(COMMAND, CLEAR_SCREEN, encrypt_packet=True)[0] self.assert_se(f"Command completed.", process_command, self.ts, packet, *self.args)
def test_successful_packet_decryption_with_offset(self): # Setup message = PRIVATE_MESSAGE_HEADER + byte_padding(b'test') encrypted_message = encrypt_and_sign(message, hash_chain(32 * b'\x01')) harac_in_bytes = int_to_bytes(2) encrypted_harac = encrypt_and_sign(harac_in_bytes, 32 * b'\x01') packet = MESSAGE_PACKET_HEADER + encrypted_harac + encrypted_message + ORIGIN_CONTACT_HEADER + b'*****@*****.**' window_list = WindowList(nicks=['Alice', 'local']) contact_list = ContactList(nicks=['Alice', 'local']) key_list = KeyList(nicks=['Alice', 'local']) keyset = key_list.get_keyset('*****@*****.**') keyset.rx_harac = 1 # Test assembly_pt, account, origin = decrypt_assembly_packet(packet, window_list, contact_list, key_list) self.assertEqual(assembly_pt, message) self.assertEqual(account, '*****@*****.**') self.assertEqual(origin, ORIGIN_CONTACT_HEADER)
def test_successful_command_decryption(self): # Setup command = byte_padding(b'test') encrypted_message = encrypt_and_sign(command, 32 * b'\x01') harac_in_bytes = int_to_bytes(1) encrypted_harac = encrypt_and_sign(harac_in_bytes, 32 * b'\x01') packet = COMMAND_PACKET_HEADER + encrypted_harac + encrypted_message window_list = WindowList(nicks=['Alice', 'local']) contact_list = ContactList(nicks=['Alice', 'local']) key_list = KeyList(nicks=['Alice', 'local']) keyset = key_list.get_keyset('local') keyset.tx_harac = 1 # Test assembly_pt, account, origin = decrypt_assembly_packet(packet, window_list, contact_list, key_list) self.assertEqual(assembly_pt, command) self.assertEqual(account, 'local') self.assertEqual(origin, ORIGIN_USER_HEADER)
def test_harac_dos_can_be_interrupted(self): # Setup encrypted_message = encrypt_and_sign(PRIVATE_MESSAGE_HEADER + byte_padding(b'test'), 32 * b'\x01') harac_in_bytes = int_to_bytes(10000) encrypted_harac = encrypt_and_sign(harac_in_bytes, 32 * b'\x01') packet = MESSAGE_PACKET_HEADER + encrypted_harac + encrypted_message + ORIGIN_CONTACT_HEADER + b'*****@*****.**' o_input = builtins.input builtins.input = lambda x: 'No' window_list = WindowList(nicks=['Alice', 'local']) contact_list = ContactList(nicks=['Alice', 'local']) key_list = KeyList(nicks=['Alice', 'local']) keyset = key_list.get_keyset('*****@*****.**') keyset.rx_harac = 3 # Test self.assertFR("Dropped packet from Alice.", decrypt_assembly_packet, packet, window_list, contact_list, key_list) # Teardown builtins.input = o_input
def test_normal_msg(self): # Setup message = ( "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean condimentum consectetur purus quis" " dapibus. Fusce venenatis lacus ut rhoncus faucibus. Cras sollicitudin commodo sapien, sed bibendu" "m velit maximus in. Aliquam ac metus risus. Sed cursus ornare luctus. Integer aliquet lectus id ma" "ssa blandit imperdiet. Ut sed massa eget quam facilisis rutrum. Mauris eget luctus nisl. Sed ut el" "it iaculis, faucibus lacus eget, sodales magna. Nunc sed commodo arcu. In hac habitasse platea dic" "tumst. Integer luctus aliquam justo, at vestibulum dolor iaculis ac. Etiam laoreet est eget odio r" "utrum, vel malesuada lorem rhoncus. Cras finibus in neque eu euismod. Nulla facilisi. Nunc nec ali" "quam quam, quis ullamcorper leo. Nunc egestas lectus eget est porttitor, in iaculis felis sceleris" "que. In sem elit, fringilla id viverra commodo, sagittis varius purus. Pellentesque rutrum loborti" "s neque a facilisis. Mauris id tortor placerat, aliquam dolor ac, venenatis arcu." .encode()) ts = datetime.datetime.now() apct_list = self.create_message_apct(ORIGIN_CONTACT_HEADER, message) contact_list = ContactList(nicks=['Alice', 'Bob', 'local']) key_list = KeyList(nicks=['Alice', 'Bob', 'local']) keyset = key_list.get_keyset('*****@*****.**') keyset.rx_harac = 1 keyset.rx_key = 32 * b'\x01' keyset.rx_hek = 32 * b'\x01' group_list = GroupList(groups=['testgroup']) settings = Settings() packet_list = PacketList(contact_list=contact_list, settings=settings) window_list = WindowList(contact_list=contact_list, group_list=group_list, packet_list=packet_list, settings=settings) master_key = MasterKey() # Test for p in apct_list: self.assertIsNone( process_message(ts, p, window_list, packet_list, contact_list, key_list, group_list, settings, master_key)) # Teardown cleanup()
def test_invalid_keys_raise_fr(self): # Setup packet = b'*****@*****.**' contact_list = ContactList(nicks=['Alice', 'local']) key_list = KeyList(nicks=['Alice', 'local']) keyset = key_list.get_keyset('*****@*****.**') keyset.rx_key = bytes(32) keyset.rx_hek = bytes(32) window_list = WindowList(nicks=['Alice', 'local']) ts = datetime.datetime.now() settings = Settings(disable_gui_dialog=True) o_input = builtins.input o_getpass = getpass.getpass builtins.input = lambda x: 'ut_psk' input_list = ['bad', 'testpassword'] gen = iter(input_list) def mock_input(_): return str(next(gen)) getpass.getpass = mock_input password = '******' salt = os.urandom(32) rx_key = bytes(32) rx_hek = os.urandom(32) kek, _ = argon2_kdf(password, salt, rounds=16, memory=128000, parallelism=1) ct_tag = encrypt_and_sign(rx_key + rx_hek, key=kek) with open('ut_psk', 'wb+') as f: f.write(salt + ct_tag) # Test self.assertFR("Keys from contact are not valid.", psk_import, packet, ts, window_list, contact_list, key_list, settings) # Teardown os.remove('ut_psk') builtins.input = o_input getpass.getpass = o_getpass
class TestImportPSKRxKeys(TFCTestCase): class MockPopen(object): def __init__(self, cmd, shell): self.cmd = cmd self.shell = shell def wait(self): pass def setUp(self): self.o_input = builtins.input self.o_getpass = getpass.getpass self.o_sp = subprocess.Popen self.packet = b'*****@*****.**' self.ts = datetime.datetime.now() self.window_list = WindowList( nicks=['Alice', LOCAL_ID]) self.contact_list = ContactList(nicks=['Alice', LOCAL_ID]) self.key_list = KeyList( nicks=['Alice', LOCAL_ID]) self.settings = Settings(disable_gui_dialog=True) builtins.input = lambda _: 'ut_psk' def tearDown(self): builtins.input = self.o_input getpass.getpass = self.o_getpass subprocess.Popen = self.o_sp with ignored(OSError): os.remove('ut_psk') def test_unknown_account_raises_fr(self): self.assertFR("Error: Unknown account '*****@*****.**'", import_psk_rx_keys, b'*****@*****.**', self.ts, self.window_list, self.contact_list, self.key_list, self.settings) def test_invalid_psk_data_raises_fr(self): # Setup with open('ut_psk', 'wb+') as f: f.write(os.urandom(135)) # Test self.assertFR("Error: Invalid PSK data in file.", import_psk_rx_keys, self.packet, self.ts, self.window_list, self.contact_list, self.key_list, self.settings) def test_invalid_keys_raise_fr(self): # Setup keyset = self.key_list.get_keyset('*****@*****.**') keyset.rx_key = bytes(KEY_LENGTH) keyset.rx_hek = bytes(KEY_LENGTH) password = '******' input_list = ['bad', password] gen = iter(input_list) getpass.getpass = lambda _: str(next(gen)) salt = os.urandom(ARGON2_SALT_LEN) rx_key = bytes(KEY_LENGTH) rx_hek = os.urandom(KEY_LENGTH) kek, _ = argon2_kdf(password, salt, parallelism=1) ct_tag = encrypt_and_sign(rx_key + rx_hek, key=kek) with open('ut_psk', 'wb+') as f: f.write(salt + ct_tag) # Test self.assertFR("Error: Received invalid keys from contact.", import_psk_rx_keys, self.packet, self.ts, self.window_list, self.contact_list, self.key_list, self.settings) def test_valid_psk(self): # Setup keyset = self.key_list.get_keyset('*****@*****.**') keyset.rx_key = bytes(KEY_LENGTH) keyset.rx_hek = bytes(KEY_LENGTH) getpass.getpass = lambda _: 'testpassword' password = '******' salt = os.urandom(ARGON2_SALT_LEN) rx_key = os.urandom(KEY_LENGTH) rx_hek = os.urandom(KEY_LENGTH) kek, _ = argon2_kdf(password, salt, parallelism=1) ct_tag = encrypt_and_sign(rx_key + rx_hek, key=kek) with open('ut_psk', 'wb+') as f: f.write(salt + ct_tag) # Test self.assertTrue(os.path.isfile('ut_psk')) self.assertIsNone(import_psk_rx_keys(self.packet, self.ts, self.window_list, self.contact_list, self.key_list, self.settings)) self.assertFalse(os.path.isfile('ut_psk')) self.assertEqual(keyset.rx_key, rx_key) self.assertEqual(keyset.rx_hek, rx_hek) def test_valid_psk_overwrite_failure(self): # Setup keyset = self.key_list.get_keyset('*****@*****.**') keyset.rx_key = bytes(KEY_LENGTH) keyset.rx_hek = bytes(KEY_LENGTH) input_list = ['ut_psk', ''] gen = iter(input_list) builtins.input = lambda _: next(gen) subprocess.Popen = TestImportPSKRxKeys.MockPopen getpass.getpass = lambda _: 'testpassword' password = '******' salt = os.urandom(ARGON2_SALT_LEN) rx_key = os.urandom(KEY_LENGTH) rx_hek = os.urandom(KEY_LENGTH) kek, _ = argon2_kdf(password, salt, parallelism=1) ct_tag = encrypt_and_sign(rx_key + rx_hek, key=kek) with open('ut_psk', 'wb+') as f: f.write(salt + ct_tag) # Test self.assertTrue(os.path.isfile('ut_psk')) self.assertIsNone(import_psk_rx_keys(self.packet, self.ts, self.window_list, self.contact_list, self.key_list, self.settings)) self.assertTrue(os.path.isfile('ut_psk')) self.assertEqual(keyset.rx_key, rx_key) self.assertEqual(keyset.rx_hek, rx_hek)
class TestKeyExPSKRx(TFCTestCase): file_name = f"{nick_to_short_address('User')}.psk - give to {nick_to_short_address('Alice')}" def setUp(self): self.unittest_dir = cd_unittest() self.packet = b'\x00' + nick_to_pub_key("Alice") self.ts = datetime.now() self.window_list = WindowList(nicks=['Alice', LOCAL_ID]) self.contact_list = ContactList(nicks=['Alice', LOCAL_ID]) self.key_list = KeyList(nicks=['Alice', LOCAL_ID]) self.settings = Settings(disable_gui_dialog=True) self.file_name = self.file_name self.args = self.packet, self.ts, self.window_list, self.contact_list, self.key_list, self.settings def tearDown(self): cleanup(self.unittest_dir) def test_unknown_account_raises_fr(self): self.assert_fr( f"Error: Unknown account '{nick_to_short_address('Bob')}'.", key_ex_psk_rx, b'\x00' + nick_to_pub_key("Bob"), self.ts, self.window_list, self.contact_list, self.key_list, self.settings) @mock.patch('builtins.input', return_value=file_name) def test_invalid_psk_data_raises_fr(self, _): # Setup with open(self.file_name, 'wb+') as f: f.write(os.urandom(135)) # Test self.assert_fr("Error: The PSK data in the file was invalid.", key_ex_psk_rx, *self.args) @mock.patch('time.sleep', return_value=None) @mock.patch('builtins.input', return_value=file_name) def test_permission_error_raises_fr(self, *_): # Setup with open(self.file_name, 'wb+') as f: f.write(os.urandom(PSK_FILE_SIZE)) # Test e_raised = False try: with mock.patch('builtins.open', side_effect=PermissionError): key_ex_psk_rx(*self.args) except FunctionReturn as inst: e_raised = True self.assertEqual("Error: No read permission for the PSK file.", inst.message) self.assertTrue(e_raised) @mock.patch('src.receiver.key_exchanges.ARGON2_ROUNDS', 1) @mock.patch('src.receiver.key_exchanges.ARGON2_MIN_MEMORY', 100) @mock.patch('getpass.getpass', side_effect=['invalid', 'password']) @mock.patch('time.sleep', return_value=None) @mock.patch('os.urandom', side_effect=[bytes(XCHACHA20_NONCE_LENGTH)]) @mock.patch('builtins.input', return_value=file_name) def test_invalid_keys_raise_fr(self, *_): # Setup keyset = self.key_list.get_keyset(nick_to_pub_key("Alice")) keyset.rx_mk = bytes(SYMMETRIC_KEY_LENGTH) keyset.rx_hk = bytes(SYMMETRIC_KEY_LENGTH) salt = bytes(ARGON2_SALT_LENGTH) rx_key = bytes(SYMMETRIC_KEY_LENGTH) rx_hek = bytes(SYMMETRIC_KEY_LENGTH) kek = argon2_kdf('password', salt, rounds=1, memory=100) ct_tag = encrypt_and_sign(rx_key + rx_hek, key=kek) with open(self.file_name, 'wb+') as f: f.write(salt + ct_tag) # Test self.assert_fr("Error: Received invalid keys from contact.", key_ex_psk_rx, *self.args) @mock.patch('src.receiver.key_exchanges.ARGON2_ROUNDS', 1) @mock.patch('src.receiver.key_exchanges.ARGON2_MIN_MEMORY', 100) @mock.patch('time.sleep', return_value=None) @mock.patch('builtins.input', return_value=file_name) @mock.patch('getpass.getpass', return_value='test_password') def test_valid_psk(self, *_): # Setup keyset = self.key_list.get_keyset(nick_to_pub_key("Alice")) keyset.rx_mk = bytes(SYMMETRIC_KEY_LENGTH) keyset.rx_hk = bytes(SYMMETRIC_KEY_LENGTH) salt = os.urandom(ARGON2_SALT_LENGTH) rx_key = os.urandom(SYMMETRIC_KEY_LENGTH) rx_hek = os.urandom(SYMMETRIC_KEY_LENGTH) kek = argon2_kdf('test_password', salt, rounds=1, memory=100) ct_tag = encrypt_and_sign(rx_key + rx_hek, key=kek) with open(self.file_name, 'wb+') as f: f.write(salt + ct_tag) # Test self.assertTrue(os.path.isfile(self.file_name)) self.assertIsNone(key_ex_psk_rx(*self.args)) self.assertFalse(os.path.isfile(self.file_name)) self.assertEqual(keyset.rx_mk, rx_key) self.assertEqual(keyset.rx_hk, rx_hek) @mock.patch('src.receiver.key_exchanges.ARGON2_ROUNDS', 1) @mock.patch('src.receiver.key_exchanges.ARGON2_MIN_MEMORY', 100) @mock.patch('subprocess.Popen') @mock.patch('time.sleep', return_value=None) @mock.patch('builtins.input', side_effect=[file_name, '']) @mock.patch('getpass.getpass', return_value='test_password') def test_valid_psk_overwrite_failure(self, *_): # Setup keyset = self.key_list.get_keyset(nick_to_pub_key("Alice")) keyset.rx_mk = bytes(SYMMETRIC_KEY_LENGTH) keyset.rx_hk = bytes(SYMMETRIC_KEY_LENGTH) salt = os.urandom(ARGON2_SALT_LENGTH) rx_key = os.urandom(SYMMETRIC_KEY_LENGTH) rx_hek = os.urandom(SYMMETRIC_KEY_LENGTH) kek = argon2_kdf('test_password', salt, rounds=1, memory=100) ct_tag = encrypt_and_sign(rx_key + rx_hek, key=kek) with open(self.file_name, 'wb+') as f: f.write(salt + ct_tag) # Test self.assertTrue(os.path.isfile(self.file_name)) self.assertIsNone(key_ex_psk_rx(*self.args)) self.assertTrue(os.path.isfile(self.file_name)) self.assertEqual(keyset.rx_mk, rx_key) self.assertEqual(keyset.rx_hk, rx_hek) @mock.patch('src.receiver.key_exchanges.ARGON2_ROUNDS', 1) @mock.patch('src.receiver.key_exchanges.ARGON2_MIN_MEMORY', 100) @mock.patch('subprocess.Popen') @mock.patch('time.sleep', return_value=None) @mock.patch('builtins.input', side_effect=[file_name, '']) @mock.patch('getpass.getpass', side_effect=[KeyboardInterrupt]) def test_valid_psk_keyboard_interrupt_raises_fr(self, *_): with open(self.file_name, 'wb+') as f: f.write(bytes(PSK_FILE_SIZE)) self.assert_fr("PSK import aborted.", key_ex_psk_rx, *self.args)
class TestDecryptAssemblyPacket(TFCTestCase): def setUp(self): self.onion_pub_key = nick_to_pub_key("Alice") self.origin = ORIGIN_CONTACT_HEADER self.window_list = WindowList(nicks=['Alice', LOCAL_ID]) self.contact_list = ContactList(nicks=['Alice', LOCAL_ID]) self.key_list = KeyList(nicks=['Alice', LOCAL_ID]) self.keyset = self.key_list.get_keyset(nick_to_pub_key("Alice")) self.args = self.onion_pub_key, self.origin, self.window_list, self.contact_list, self.key_list def test_decryption_with_zero_rx_key_raises_fr(self): # Setup keyset = self.key_list.get_keyset(nick_to_pub_key("Alice")) keyset.rx_mk = bytes(SYMMETRIC_KEY_LENGTH) packet = assembly_packet_creator(MESSAGE, payload="Test message", encrypt_packet=True)[0] # Test self.assert_fr("Warning! Loaded zero-key for packet decryption.", decrypt_assembly_packet, packet, *self.args) def test_invalid_harac_ct_raises_fr(self): packet = assembly_packet_creator(MESSAGE, payload="Test message", encrypt_packet=True, tamper_harac=True)[0] self.assert_fr("Warning! Received packet from Alice had an invalid hash ratchet MAC.", decrypt_assembly_packet, packet, *self.args) def test_decryption_with_zero_rx_hek_raises_fr(self): # Setup keyset = self.key_list.get_keyset(nick_to_pub_key("Alice")) keyset.rx_hk = bytes(SYMMETRIC_KEY_LENGTH) packet = assembly_packet_creator(MESSAGE, payload="Test message", encrypt_packet=True)[0] # Test self.assert_fr("Warning! Loaded zero-key for packet decryption.", decrypt_assembly_packet, packet, *self.args) def test_expired_harac_raises_fr(self): # Setup self.keyset.rx_harac = 1 # Test packet = assembly_packet_creator(MESSAGE, payload="Test message", encrypt_packet=True, harac=0)[0] self.assert_fr("Warning! Received packet from Alice had an expired hash ratchet counter.", decrypt_assembly_packet, packet, *self.args) @mock.patch('builtins.input', return_value='No') def test_harac_dos_can_be_interrupted(self, _): packet = assembly_packet_creator(MESSAGE, payload="Test message", encrypt_packet=True, harac=100_001)[0] self.assert_fr("Dropped packet from Alice.", decrypt_assembly_packet, packet, *self.args) def test_invalid_packet_ct_raises_fr(self): packet = assembly_packet_creator(MESSAGE, payload="Test message", encrypt_packet=True, tamper_message=True)[0] self.assert_fr("Warning! Received packet from Alice had an invalid MAC.", decrypt_assembly_packet, packet, *self.args) 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]) 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]) 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])
class TestProcessMessage(TFCTestCase): def setUp(self): self.msg = ("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean condimentum consectetur purus quis" " dapibus. Fusce venenatis lacus ut rhoncus faucibus. Cras sollicitudin commodo sapien, sed bibendu" "m velit maximus in. Aliquam ac metus risus. Sed cursus ornare luctus. Integer aliquet lectus id ma" "ssa blandit imperdiet. Ut sed massa eget quam facilisis rutrum. Mauris eget luctus nisl. Sed ut el" "it iaculis, faucibus lacus eget, sodales magna. Nunc sed commodo arcu. In hac habitasse platea dic" "tumst. Integer luctus aliquam justo, at vestibulum dolor iaculis ac. Etiam laoreet est eget odio r" "utrum, vel malesuada lorem rhoncus. Cras finibus in neque eu euismod. Nulla facilisi. Nunc nec ali" "quam quam, quis ullamcorper leo. Nunc egestas lectus eget est porttitor, in iaculis felis sceleris" "que. In sem elit, fringilla id viverra commodo, sagittis varius purus. Pellentesque rutrum loborti" "s neque a facilisis. Mauris id tortor placerat, aliquam dolor ac, venenatis arcu.").encode() self.ts = datetime.now() self.master_key = MasterKey() self.settings = Settings(logfile_masking=True) self.contact_list = ContactList(nicks=['Alice', 'Bob', 'Charlie', LOCAL_ID]) self.key_list = KeyList( nicks=['Alice', 'Bob', 'Charlie', LOCAL_ID]) self.group_list = GroupList( groups=['testgroup']) self.packet_list = PacketList(contact_list=self.contact_list, settings=self.settings) self.window_list = WindowList(contact_list=self.contact_list, settings=self.settings, group_list=self.group_list, packet_list=self.packet_list) self.group_list.get_group('testgroup').log_messages = True for account in self.contact_list.get_list_of_accounts(): keyset = self.key_list.get_keyset(account) keyset.tx_harac = 1 keyset.rx_harac = 1 keyset.tx_hek = KEY_LENGTH * b'\x01' keyset.rx_hek = KEY_LENGTH * b'\x01' keyset.tx_key = KEY_LENGTH * b'\x01' keyset.rx_key = KEY_LENGTH * b'\x01' self.message = b'testgroup' + US_BYTE + b'*****@*****.**' + US_BYTE + b'*****@*****.**' def tearDown(self): cleanup() with ignored(FileNotFoundError): shutil.rmtree(DIR_RX_FILES) # Private messages def test_private_msg_from_contact(self): # Setup assembly_ct_list = assembly_packet_creator(MESSAGE, self.msg, ORIGIN_CONTACT_HEADER, encrypt=True) # Test for p in assembly_ct_list: self.assertIsNone(process_message(self.ts, p, self.window_list, self.packet_list, self.contact_list, self.key_list, self.group_list, self.settings, self.master_key)) self.assertEqual(os.path.getsize(f'{DIR_USER_DATA}ut_logs'), len(assembly_ct_list)*LOG_ENTRY_LENGTH) def test_private_msg_from_user(self): # Setup assembly_ct_list = assembly_packet_creator(MESSAGE, self.msg, ORIGIN_USER_HEADER, encrypt=True) # Test for p in assembly_ct_list: self.assertIsNone(process_message(self.ts, p, self.window_list, self.packet_list, self.contact_list, self.key_list, self.group_list, self.settings, self.master_key)) self.assertEqual(os.path.getsize(f'{DIR_USER_DATA}ut_logs'), len(assembly_ct_list) * LOG_ENTRY_LENGTH) # Whispered messages def test_whisper_msg_from_contact(self): # Setup assembly_ct_list = assembly_packet_creator(MESSAGE, self.msg, ORIGIN_CONTACT_HEADER, encrypt=True, header=WHISPER_MESSAGE_HEADER) # Test for p in assembly_ct_list[:-1]: self.assertIsNone(process_message(self.ts, p, self.window_list, self.packet_list, self.contact_list, self.key_list, self.group_list, self.settings, self.master_key)) for p in assembly_ct_list[-1:]: self.assertFR("Key message message complete.", process_message, self.ts, p, self.window_list, self.packet_list, self.contact_list, self.key_list, self.group_list, self.settings, self.master_key) self.assertEqual(os.path.getsize(f'{DIR_USER_DATA}ut_logs'), len(assembly_ct_list)*LOG_ENTRY_LENGTH) def test_whisper_msg_from_user(self): # Setup assembly_ct_list = assembly_packet_creator(MESSAGE, self.msg, ORIGIN_USER_HEADER, encrypt=True, header=WHISPER_MESSAGE_HEADER) # Test for p in assembly_ct_list[:-1]: self.assertIsNone(process_message(self.ts, p, self.window_list, self.packet_list, self.contact_list, self.key_list, self.group_list, self.settings, self.master_key)) for p in assembly_ct_list[-1:]: self.assertFR("Key message message complete.", process_message, self.ts, p, self.window_list, self.packet_list, self.contact_list, self.key_list, self.group_list, self.settings, self.master_key) self.assertEqual(os.path.getsize(f'{DIR_USER_DATA}ut_logs'), len(assembly_ct_list)*LOG_ENTRY_LENGTH) def test_empty_whisper_msg_from_user(self): # Setup assembly_ct_list = assembly_packet_creator(MESSAGE, b' ', ORIGIN_USER_HEADER, encrypt=True, header=WHISPER_MESSAGE_HEADER) # Test for p in assembly_ct_list[:-1]: self.assertIsNone(process_message(self.ts, p, self.window_list, self.packet_list, self.contact_list, self.key_list, self.group_list, self.settings, self.master_key)) for p in assembly_ct_list[-1:]: self.assertFR("Key message message complete.", process_message, self.ts, p, self.window_list, self.packet_list, self.contact_list, self.key_list, self.group_list, self.settings, self.master_key) self.assertEqual(os.path.getsize(f'{DIR_USER_DATA}ut_logs'), len(assembly_ct_list)*LOG_ENTRY_LENGTH) # Group messages def test_invalid_encoding_raises_fr(self): encrypted_packet = assembly_packet_creator(MESSAGE, b'test', ORIGIN_CONTACT_HEADER, group_name='testgroup', encrypt=True, break_g_name=True)[0] # Test self.assertFR("Error: Received an invalid group message.", process_message, self.ts, encrypted_packet, self.window_list, self.packet_list, self.contact_list, self.key_list, self.group_list, self.settings, self.master_key) self.assertEqual(os.path.getsize(f'{DIR_USER_DATA}ut_logs'), LOG_ENTRY_LENGTH) def test_invalid_message_header_raises_fr(self): # Setup encrypted_packet = assembly_packet_creator(MESSAGE, b'testgroup', ORIGIN_CONTACT_HEADER, header=b'Z', encrypt=True)[0] # Test self.assertFR("Error: Message from contact had an invalid header.", process_message, self.ts, encrypted_packet, self.window_list, self.packet_list, self.contact_list, self.key_list, self.group_list, self.settings, self.master_key) self.assertEqual(os.path.getsize(f'{DIR_USER_DATA}ut_logs'), LOG_ENTRY_LENGTH) def test_invalid_window_raises_fr(self): # Setup encrypted_packet = assembly_packet_creator(MESSAGE, b'test', ORIGIN_CONTACT_HEADER, group_name='test_group', encrypt=True)[0] # Test self.assertFR("Error: Received message to unknown group.", process_message, self.ts, encrypted_packet, self.window_list, self.packet_list, self.contact_list, self.key_list, self.group_list, self.settings, self.master_key) self.assertEqual(os.path.getsize(f'{DIR_USER_DATA}ut_logs'), LOG_ENTRY_LENGTH) def test_contact_not_in_group_raises_fr(self): # Setup encrypted_packet = assembly_packet_creator(MESSAGE, b'test', ORIGIN_CONTACT_HEADER, group_name='testgroup', encrypt=True, origin_acco=b'*****@*****.**')[0] # Test self.assertFR("Error: Account is not member of group.", process_message, self.ts, encrypted_packet, self.window_list, self.packet_list, self.contact_list, self.key_list, self.group_list, self.settings, self.master_key) self.assertEqual(os.path.getsize(f'{DIR_USER_DATA}ut_logs'), LOG_ENTRY_LENGTH) def test_normal_group_msg_from_contact(self): # Setup assembly_ct_list = assembly_packet_creator(MESSAGE, self.msg, ORIGIN_CONTACT_HEADER, group_name='testgroup', encrypt=True) for p in assembly_ct_list: self.assertIsNone(process_message(self.ts, p, self.window_list, self.packet_list, self.contact_list, self.key_list, self.group_list, self.settings, self.master_key)) self.assertEqual(os.path.getsize(f'{DIR_USER_DATA}ut_logs'), len(assembly_ct_list)*LOG_ENTRY_LENGTH) def test_normal_group_msg_from_user(self): # Setup assembly_ct_list = assembly_packet_creator(MESSAGE, self.msg, ORIGIN_USER_HEADER, group_name='testgroup', encrypt=True) for p in assembly_ct_list: self.assertIsNone(process_message(self.ts, p, self.window_list, self.packet_list, self.contact_list, self.key_list, self.group_list, self.settings, self.master_key)) self.assertEqual(os.path.getsize(f'{DIR_USER_DATA}ut_logs'), len(assembly_ct_list)*LOG_ENTRY_LENGTH) # Group management messages def test_group_invitation_msg_from_contact(self): # Setup assembly_ct_list = assembly_packet_creator(MESSAGE, self.message, ORIGIN_CONTACT_HEADER, header=GROUP_MSG_INVITEJOIN_HEADER, encrypt=True) # Test for p in assembly_ct_list[:-1]: self.assertIsNone(process_message(self.ts, p, self.window_list, self.packet_list, self.contact_list, self.key_list, self.group_list, self.settings, self.master_key)) for p in assembly_ct_list[-1:]: self.assertFR("Group management message complete.", process_message, self.ts, p, self.window_list, self.packet_list, self.contact_list, self.key_list, self.group_list, self.settings, self.master_key) self.assertEqual(os.path.getsize(f'{DIR_USER_DATA}ut_logs'), len(assembly_ct_list)*LOG_ENTRY_LENGTH) def test_group_invitation_msg_from_user(self): # Setup assembly_ct_list = assembly_packet_creator(MESSAGE, self.message, ORIGIN_USER_HEADER, header=GROUP_MSG_INVITEJOIN_HEADER, encrypt=True) # Test for p in assembly_ct_list[:-1]: self.assertIsNone(process_message(self.ts, p, self.window_list, self.packet_list, self.contact_list, self.key_list, self.group_list, self.settings, self.master_key)) for p in assembly_ct_list[-1:]: self.assertFR("Ignored group management message from user.", process_message, self.ts, p, self.window_list, self.packet_list, self.contact_list, self.key_list, self.group_list, self.settings, self.master_key) self.assertEqual(os.path.getsize(f'{DIR_USER_DATA}ut_logs'), len(assembly_ct_list)*LOG_ENTRY_LENGTH) def test_group_add_member_msg_from_contact(self): # Setup assembly_ct_list = assembly_packet_creator(MESSAGE, self.message, ORIGIN_CONTACT_HEADER, header=GROUP_MSG_MEMBER_ADD_HEADER, encrypt=True) # Test for p in assembly_ct_list[:-1]: self.assertIsNone(process_message(self.ts, p, self.window_list, self.packet_list, self.contact_list, self.key_list, self.group_list, self.settings, self.master_key)) for p in assembly_ct_list[-1:]: self.assertFR("Group management message complete.", process_message, self.ts, p, self.window_list, self.packet_list, self.contact_list, self.key_list, self.group_list, self.settings, self.master_key) self.assertEqual(os.path.getsize(f'{DIR_USER_DATA}ut_logs'), len(assembly_ct_list)*LOG_ENTRY_LENGTH) def test_group_remove_member_msg_from_contact(self): # Setup assembly_ct_list = assembly_packet_creator(MESSAGE, self.message, ORIGIN_CONTACT_HEADER, header=GROUP_MSG_MEMBER_REM_HEADER, encrypt=True) # Test for p in assembly_ct_list[:-1]: self.assertIsNone(process_message(self.ts, p, self.window_list, self.packet_list, self.contact_list, self.key_list, self.group_list, self.settings, self.master_key)) for p in assembly_ct_list[-1:]: self.assertFR("Group management message complete.", process_message, self.ts, p, self.window_list, self.packet_list, self.contact_list, self.key_list, self.group_list, self.settings, self.master_key) self.assertEqual(os.path.getsize(f'{DIR_USER_DATA}ut_logs'), len(assembly_ct_list)*LOG_ENTRY_LENGTH) def test_group_exit_msg_from_contact(self): # Setup assembly_ct_list = assembly_packet_creator(MESSAGE, b'testgroup', ORIGIN_CONTACT_HEADER, header=GROUP_MSG_EXIT_GROUP_HEADER, encrypt=True) # Test for p in assembly_ct_list[:-1]: self.assertIsNone(process_message(self.ts, p, self.window_list, self.packet_list, self.contact_list, self.key_list, self.group_list, self.settings, self.master_key)) for p in assembly_ct_list[-1:]: self.assertFR("Group management message complete.", process_message, self.ts, p, self.window_list, self.packet_list, self.contact_list, self.key_list, self.group_list, self.settings, self.master_key) self.assertEqual(os.path.getsize(f'{DIR_USER_DATA}ut_logs'), len(assembly_ct_list)*LOG_ENTRY_LENGTH) def test_invalid_encoding_in_group_management_message_raises_fr_but_is_logged(self): # Setup message = b'testgroup' + US_BYTE + b'*****@*****.**' + US_BYTE + binascii.unhexlify('a466c02c221cb135') encrypted_packet = assembly_packet_creator(MESSAGE, message, ORIGIN_CONTACT_HEADER, header=GROUP_MSG_INVITEJOIN_HEADER, encrypt=True)[0] self.settings.logfile_masking = True self.contact_list.get_contact('*****@*****.**').log_messages = True # Test self.assertFR("Error: Received group management message had invalid encoding.", process_message, self.ts, encrypted_packet, self.window_list, self.packet_list, self.contact_list, self.key_list, self.group_list, self.settings, self.master_key) self.assertEqual(os.path.getsize(f'{DIR_USER_DATA}ut_logs'), LOG_ENTRY_LENGTH) # Files def test_file(self): # Setup assembly_ct_list = assembly_packet_creator(FILE, origin=ORIGIN_CONTACT_HEADER, encrypt=True) # Test for p in assembly_ct_list[:-1]: self.assertIsNone(process_message(self.ts, p, self.window_list, self.packet_list, self.contact_list, self.key_list, self.group_list, self.settings, self.master_key)) for p in assembly_ct_list[-1:]: self.assertFR("File storage complete.", process_message, self.ts, p, self.window_list, self.packet_list, self.contact_list, self.key_list, self.group_list, self.settings, self.master_key) self.assertEqual(os.path.getsize(f'{DIR_USER_DATA}ut_logs'), len(assembly_ct_list)*LOG_ENTRY_LENGTH) def test_file_file_reception_is_disabled(self): # Setup payload = int_to_bytes(1) + int_to_bytes(2) + b'testfile.txt' + US_BYTE + os.urandom(50) encrypted_packet = assembly_packet_creator(FILE, payload=payload, origin=ORIGIN_CONTACT_HEADER, encrypt=True)[0] self.contact_list.get_contact('*****@*****.**').file_reception = False # Test self.assertFR("Alert! File transmission from Alice but reception is disabled.", process_message, self.ts, encrypted_packet, self.window_list, self.packet_list, self.contact_list, self.key_list, self.group_list, self.settings, self.master_key) self.assertEqual(os.path.getsize(f'{DIR_USER_DATA}ut_logs'), LOG_ENTRY_LENGTH)
class TestDecryptAssemblyPacket(TFCTestCase): def setUp(self): self.o_input = builtins.input self.window_list = WindowList( nicks=['Alice', LOCAL_ID]) self.contact_list = ContactList(nicks=['Alice', LOCAL_ID]) self.key_list = KeyList( nicks=['Alice', LOCAL_ID]) self.keyset = self.key_list.get_keyset('*****@*****.**') self.packet = None def tearDown(self): builtins.input = self.o_input def create_encrypted_packet(self, tx_harac, rx_harac, hek=KEY_LENGTH*b'\x01', key=KEY_LENGTH*b'\x01'): encrypted_message = encrypt_and_sign(PRIVATE_MESSAGE_HEADER + byte_padding(b'test'), key) encrypted_harac = encrypt_and_sign(int_to_bytes(tx_harac), hek) self.packet = MESSAGE_PACKET_HEADER + encrypted_harac + encrypted_message + ORIGIN_CONTACT_HEADER + b'*****@*****.**' self.keyset.rx_harac = rx_harac def test_invalid_origin_header_raises_fr(self): # Setup packet = MESSAGE_PACKET_HEADER + MESSAGE_LENGTH*b'm' + b'e' # Test self.assertFR("Error: Received packet had an invalid origin-header.", decrypt_assembly_packet, packet, self.window_list, self.contact_list, self.key_list) def test_masqueraded_command_raises_fr(self): for o in [ORIGIN_USER_HEADER, ORIGIN_CONTACT_HEADER]: # Setup packet = MESSAGE_PACKET_HEADER + MESSAGE_LENGTH*b'm' + o + LOCAL_ID.encode() # Test self.assertFR("Warning! Received packet masqueraded as command.", decrypt_assembly_packet, packet, self.window_list, self.contact_list, self.key_list) def test_invalid_harac_ct_raises_fr(self): # Setup packet = MESSAGE_PACKET_HEADER + MESSAGE_LENGTH*b'm' + ORIGIN_CONTACT_HEADER + b'*****@*****.**' # Test self.assertFR("Warning! Received packet from Alice had an invalid hash ratchet MAC.", decrypt_assembly_packet, packet, self.window_list, self.contact_list, self.key_list) def test_decryption_with_zero_rx_key_raises_fr(self): # Setup self.create_encrypted_packet(tx_harac=2, rx_harac=1, key=(hash_chain(KEY_LENGTH*b'\x01'))) keyset = self.key_list.get_keyset('*****@*****.**') keyset.rx_key = bytes(KEY_LENGTH) # Test self.assertFR("Warning! Loaded zero-key for packet decryption.", decrypt_assembly_packet, self.packet, self.window_list, self.contact_list, self.key_list) def test_decryption_with_zero_rx_hek_raises_fr(self): # Setup self.create_encrypted_packet(tx_harac=2, rx_harac=1, key=(hash_chain(KEY_LENGTH*b'\x01'))) keyset = self.key_list.get_keyset('*****@*****.**') keyset.rx_hek = bytes(KEY_LENGTH) # Test self.assertFR("Warning! Loaded zero-key for packet decryption.", decrypt_assembly_packet, self.packet, self.window_list, self.contact_list, self.key_list) def test_invalid_harac_raises_fr(self): # Setup self.create_encrypted_packet(tx_harac=3, rx_harac=3, hek=KEY_LENGTH*b'\x02') # Test self.assertFR("Warning! Received packet from Alice had an invalid hash ratchet MAC.", decrypt_assembly_packet, self.packet, self.window_list, self.contact_list, self.key_list) def test_expired_harac_raises_fr(self): # Setup self.create_encrypted_packet(tx_harac=1, rx_harac=3) # Test self.assertFR("Warning! Received packet from Alice had an expired hash ratchet counter.", decrypt_assembly_packet, self.packet, self.window_list, self.contact_list, self.key_list) def test_harac_dos_can_be_interrupted(self): # Setup self.create_encrypted_packet(tx_harac=10000, rx_harac=3) builtins.input = lambda _: 'No' # Test self.assertFR("Dropped packet from Alice.", decrypt_assembly_packet, self.packet, self.window_list, self.contact_list, self.key_list) def test_invalid_packet_ct_raises_fr(self): # Setup self.create_encrypted_packet(tx_harac=5, rx_harac=3) # Test self.assertFR("Warning! Received packet from Alice had an invalid MAC.", decrypt_assembly_packet, self.packet, self.window_list, self.contact_list, self.key_list) def test_successful_packet_decryption(self): # Setup self.create_encrypted_packet(tx_harac=1, rx_harac=1) # Test assembly_pt, account, origin = decrypt_assembly_packet(self.packet, self.window_list, self.contact_list, self.key_list) self.assertEqual(rm_padding_bytes(assembly_pt), PRIVATE_MESSAGE_HEADER + b'test') self.assertEqual(account, '*****@*****.**') self.assertEqual(origin, ORIGIN_CONTACT_HEADER) def test_successful_packet_decryption_with_offset(self): # Setup self.create_encrypted_packet(tx_harac=2, rx_harac=1, key=(hash_chain(KEY_LENGTH*b'\x01'))) # Test assembly_pt, account, origin = decrypt_assembly_packet(self.packet, self.window_list, self.contact_list, self.key_list) self.assertEqual(rm_padding_bytes(assembly_pt), PRIVATE_MESSAGE_HEADER + b'test') self.assertEqual(account, '*****@*****.**') self.assertEqual(origin, ORIGIN_CONTACT_HEADER) def test_successful_command_decryption(self): # Setup command = byte_padding(b'test') encrypted_message = encrypt_and_sign(command, KEY_LENGTH*b'\x01') encrypted_harac = encrypt_and_sign(int_to_bytes(1), KEY_LENGTH*b'\x01') packet = COMMAND_PACKET_HEADER + encrypted_harac + encrypted_message keyset = self.key_list.get_keyset(LOCAL_ID) keyset.tx_harac = 1 # Test assembly_pt, account, origin = decrypt_assembly_packet(packet, self.window_list, self.contact_list, self.key_list) self.assertEqual(assembly_pt, command) self.assertEqual(account, LOCAL_ID) self.assertEqual(origin, ORIGIN_USER_HEADER)