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 assemble_and_store_file(self, ts: 'datetime', onion_pub_key: bytes, window_list: 'WindowList' ) -> None: """Assemble file packet and store it.""" padded = b''.join([p[ASSEMBLY_PACKET_HEADER_LENGTH:] for p in self.assembly_pt_list]) payload = rm_padding_bytes(padded) process_assembled_file(ts, payload, onion_pub_key, self.contact.nick, self.settings, window_list)
def assemble_and_store_file(self, ts: 'datetime', onion_pub_key: bytes, window_list: 'WindowList') -> None: """Assemble file packet and store it.""" padded = b''.join( [p[ASSEMBLY_PACKET_HEADER_LENGTH:] for p in self.assembly_pt_list]) payload = rm_padding_bytes(padded) no_fields = 3 if len(self.assembly_pt_list) > 1 else 2 *_, payload = separate_headers(payload, no_fields * [ENCODED_INTEGER_LENGTH]) process_assembled_file(ts, payload, onion_pub_key, self.contact.nick, self.settings, window_list)
def assemble_command_packet(self) -> bytes: """Assemble command packet.""" padded = b''.join([p[ASSEMBLY_PACKET_HEADER_LENGTH:] for p in self.assembly_pt_list]) payload = rm_padding_bytes(padded) if len(self.assembly_pt_list) > 1: payload, cmd_hash = separate_trailer(payload, BLAKE2_DIGEST_LENGTH) if blake2b(payload) != cmd_hash: raise FunctionReturn("Error: Received an invalid command.") try: return decompress(payload, self.settings.max_decompress_size) except zlib.error: raise FunctionReturn("Error: Decompression of command failed.")
def assemble_command_packet(self) -> bytes: """Assemble command packet.""" padded = b''.join([p[1:] for p in self.assembly_pt_list]) payload = rm_padding_bytes(padded) if len(self.assembly_pt_list) > 1: cmd_hash = payload[-KEY_LENGTH:] payload = payload[:-KEY_LENGTH] if hash_chain(payload) != cmd_hash: raise FunctionReturn("Error: Received an invalid command.") try: return zlib.decompress(payload) except zlib.error: raise FunctionReturn("Error: Decompression of command failed.")
def assemble_message_packet(self) -> bytes: """Assemble message packet.""" padded = b''.join([p[ASSEMBLY_PACKET_HEADER_LENGTH:] for p in self.assembly_pt_list]) payload = rm_padding_bytes(padded) if len(self.assembly_pt_list) > 1: msg_ct, msg_key = separate_trailer(payload, SYMMETRIC_KEY_LENGTH) try: payload = auth_and_decrypt(msg_ct, msg_key) except nacl.exceptions.CryptoError: raise FunctionReturn("Error: Decryption of message failed.") try: return decompress(payload, MAX_MESSAGE_SIZE) except zlib.error: raise FunctionReturn("Error: Decompression of message failed.")
def assemble_message_packet(self) -> bytes: """Assemble message packet.""" padded = b''.join([p[1:] for p in self.assembly_pt_list]) payload = rm_padding_bytes(padded) if len(self.assembly_pt_list) > 1: msg_ct = payload[:-KEY_LENGTH] msg_key = payload[-KEY_LENGTH:] try: payload = auth_and_decrypt(msg_ct, msg_key, soft_e=True) except (nacl.exceptions.CryptoError, nacl.exceptions.ValueError): raise FunctionReturn("Error: Decryption of message failed.") try: return zlib.decompress(payload) except zlib.error: raise FunctionReturn("Error: Decompression of message failed.")
def test_padding_removal(self): for i in range(0, 1000): string = os.urandom(i) length = PADDING_LEN - (len(string) % PADDING_LEN) padded = string + length * bytes([length]) self.assertEqual(rm_padding_bytes(padded), string)
def test_removal_of_padding_does_not_alter_the_original_message( self) -> None: for message_length in range(4 * PADDING_LENGTH): message = os.urandom(message_length) padded = byte_padding(message) self.assertEqual(rm_padding_bytes(padded), message)
def access_history(window: Union['Window', 'Window_'], contact_list: 'ContactList', settings: 'Settings', master_key: 'MasterKey', msg_to_load: int = 0, export: bool = False) -> None: """Decrypt 'msg_to_load' last messages from log database and display/export it. :param window: Window object :param contact_list: ContactList object :param settings: Settings object :param master_key: Master key object :param msg_to_load: Number of messages to load :param export: When True, write logged messages into plaintext file instead of printing them. :return: None """ def read_entry(): """Read encrypted log entry. Length | Data type --------|-------------------------------- 24 | XSalsa20 nonce 4 | Timestamp 4 | UTF-32 BOM 4*255 | Padded account (UTF-32) 1 | Origin header 1 | Assembly packet header 255 | Padded assembly packet (UTF-8) 16 | Poly1305 tag """ return log_file.read(1325) ensure_dir(f'{DIR_USER_DATA}/') file_name = f'{DIR_USER_DATA}/{settings.software_operation}_logs' if not os.path.isfile(file_name): raise FunctionReturn(f"Error: Could not find '{file_name}'.") log_file = open(file_name, 'rb') ts_message_list = [] # type: List[Tuple[str, str, bytes, str]] assembly_p_buffer = dict() group_timestamp = b'' for ct in iter(read_entry, b''): pt = auth_and_decrypt(ct, key=master_key.master_key) account = bytes_to_str(pt[5:1029]) if window.type == 'contact' and window.uid != account: continue t_stamp = parse_ts_bytes(pt[0:4], settings) origin_byte = pt[4:5] origin = origin_byte.decode() assembly_header = pt[1029:1030] assembly_pt = pt[1030:] if assembly_header == M_S_HEADER: depadded = rm_padding_bytes(assembly_pt) decompressed = zlib.decompress(depadded) if decompressed[:1] == PRIVATE_MESSAGE_HEADER: if window.type == 'group': continue decoded = decompressed[1:].decode() elif decompressed[:1] == GROUP_MESSAGE_HEADER: group_name, decoded = [f.decode() for f in decompressed[9:].split(US_BYTE)] if group_name != window.name: continue if group_timestamp == decompressed[1:9]: continue else: group_timestamp = decompressed[1:9] ts_message_list.append((t_stamp, account, origin_byte, decoded)) elif assembly_header == M_L_HEADER: assembly_p_buffer[origin + account] = assembly_pt elif assembly_header == M_A_HEADER: if (origin + account) in assembly_p_buffer: assembly_p_buffer[origin + account] += assembly_pt elif assembly_header == M_E_HEADER: if (origin + account) in assembly_p_buffer: assembly_p_buffer[origin + account] += assembly_pt pt_buf = assembly_p_buffer.pop(origin + account) inner_l = rm_padding_bytes(pt_buf) msg_key = inner_l[-32:] enc_msg = inner_l[:-32] decrypted = auth_and_decrypt(enc_msg, key=msg_key) decompressed = zlib.decompress(decrypted) if decompressed[:1] == PRIVATE_MESSAGE_HEADER: if window.type == 'group': continue decoded = decompressed[1:].decode() elif decompressed[:1] == GROUP_MESSAGE_HEADER: group_name, decoded = [f.decode() for f in decompressed[9:].split(US_BYTE)] if group_name != window.name: continue if group_timestamp == decompressed[1:9]: # Skip duplicates of outgoing messages continue else: group_timestamp = decompressed[1:9] ts_message_list.append((t_stamp, account, origin_byte, decoded)) elif assembly_header == M_C_HEADER: assembly_p_buffer.pop(origin + account, None) log_file.close() if not export: clear_screen() print('') tty_w = get_tty_w() system = dict(tx="TxM", rx="RxM", ut="Unittest")[settings.software_operation] m_dir = dict(tx="sent to", rx="to/from", ut="to/from")[settings.software_operation] f_name = open(f"{system} - Plaintext log ({window.name})", 'w+') if export else sys.stdout subset = '' if msg_to_load == 0 else f"{msg_to_load} most recent " title = textwrap.fill(f"Log file of {subset}message(s) {m_dir} {window.name}", tty_w) print(title, file=f_name) print(tty_w * '═', file=f_name) for timestamp, account, origin_, message in ts_message_list[-msg_to_load:]: nick = "Me" if origin_ == ORIGIN_USER_HEADER else contact_list.get_contact(account).nick print(textwrap.fill(f"{timestamp} {nick}:", tty_w), file=f_name) print('', file=f_name) print(textwrap.fill(message, tty_w), file=f_name) print('', file=f_name) print(tty_w * '─', file=f_name) if export: f_name.close() else: print('')
def assemble_and_store_file(self) -> None: """Assemble file packet and store it.""" padded = b''.join([p[1:] for p in self.assembly_pt_list]) payload = rm_padding_bytes(padded) process_received_file(payload, self.contact.nick)
def test_removal_of_padding_does_not_alter_original_string(self): for length in range(1000): string = os.urandom(length) padded = byte_padding(string) self.assertEqual(rm_padding_bytes(padded), string)
def test_function(self): for i in range(0, 1000): string = i * b'm' length = 255 - (len(string) % 255) padded = string + length * bytes([length]) self.assertEqual(rm_padding_bytes(padded), string)