def new_psk(account: str, user: str, nick: str, contact_list: 'ContactList', settings: 'Settings', queues: Dict[bytes, 'Queue']) -> None: """Generate new pre-shared key for manual key delivery. :param account: The contact's account name (e.g. [email protected]) :param user: The user's account name (e.g. [email protected]) :param nick: Nick of contact :param contact_list: Contact list object :param settings: Settings object :param queues: Dictionary of multiprocessing queues :return: None """ try: tx_key = keygen() tx_hek = keygen() salt = keygen() password = MasterKey.new_password("password for PSK") phase("Deriving key encryption key", head=2) kek, _ = argon2_kdf(password, salt, rounds=16, memory=128000, parallelism=1) phase('Done') ct_tag = encrypt_and_sign(tx_key + tx_hek, key=kek) store_d = ask_path_gui(f"Select removable media for {nick}", settings) f_name = f"{store_d}/{user}.psk - Give to {account}" try: with open(f_name, 'wb+') as f: f.write(salt + ct_tag) except PermissionError: raise FunctionReturn( "Error: Did not have permission to write to directory.") packet = KEY_EX_PSK_TX_HEADER \ + tx_key \ + tx_hek \ + account.encode() + US_BYTE + nick.encode() queue_command(packet, settings, queues[COMMAND_PACKET_QUEUE]) contact_list.add_contact(account, user, nick, bytes(32), bytes(32), settings.log_msg_by_default, settings.store_file_default, settings.n_m_notify_privacy) queues[KEY_MANAGEMENT_QUEUE].put( ('ADD', account, tx_key, bytes(32), tx_hek, bytes(32))) box_print([f"Successfully added {nick}."], head=1) clear_screen(delay=1) except KeyboardInterrupt: raise FunctionReturn("PSK generation aborted.")
def create_pre_shared_key( onion_pub_key: bytes, # Public key of contact's v3 Onion Service nick: str, # Nick of contact contact_list: 'ContactList', # Contact list object settings: 'Settings', # Settings object onion_service: 'OnionService', # OnionService object queues: 'QueueDict' # Dictionary of multiprocessing queues ) -> None: """Generate a new pre-shared key for manual key delivery. Pre-shared keys offer a low-tech solution against the slowly emerging threat of quantum computers. PSKs are less convenient and not usable in every scenario, but until a quantum-safe key exchange algorithm with reasonably short keys is standardized, TFC can't provide a better alternative against quantum computers. The generated keys are protected by a key encryption key, derived from a 256-bit salt and a password (that is to be shared with the recipient) using Argon2id key derivation function. The encrypted message and header keys are stored together with salt on a removable media. This media must be a never-before-used device from sealed packaging. Re-using an old device might infect Source Computer, and the malware could either copy sensitive data on that removable media, or Source Computer might start transmitting the sensitive data covertly over the serial interface to malware on Networked Computer. Once the key has been exported to the clean drive, contact data and keys are exported to the Receiver Program on Destination computer. The transmission is encrypted with the local key. """ try: tx_mk = csprng() tx_hk = csprng() salt = csprng() password = MasterKey.new_password("password for PSK") phase("Deriving key encryption key", head=2) kek = argon2_kdf(password, salt, ARGON2_PSK_TIME_COST, ARGON2_PSK_MEMORY_COST, ARGON2_PSK_PARALLELISM) phase(DONE) ct_tag = encrypt_and_sign(tx_mk + tx_hk, key=kek) store_keys_on_removable_drive(ct_tag, salt, nick, onion_pub_key, onion_service, settings) deliver_contact_data(KEY_EX_PSK_TX, nick, onion_pub_key, tx_mk, csprng(), tx_hk, csprng(), queues, settings) contact_list.add_contact(onion_pub_key, nick, bytes(FINGERPRINT_LENGTH), bytes(FINGERPRINT_LENGTH), KEX_STATUS_NO_RX_PSK, settings.log_messages_by_default, settings.accept_files_by_default, settings.show_notifications_by_default) queues[KEY_MANAGEMENT_QUEUE].put( (KDB_ADD_ENTRY_HEADER, onion_pub_key, tx_mk, csprng(), tx_hk, csprng())) m_print(f"Successfully added {nick}.", bold=True, tail_clear=True, delay=1, head=1) except (EOFError, KeyboardInterrupt): raise SoftError("PSK generation aborted.", tail_clear=True, delay=1, head=2)
def create_pre_shared_key( onion_pub_key: bytes, # Public key of contact's v3 Onion Service nick: str, # Nick of contact contact_list: 'ContactList', # Contact list object settings: 'Settings', # Settings object onion_service: 'OnionService', # OnionService object queues: 'QueueDict' # Dictionary of multiprocessing queues ) -> None: """Generate a new pre-shared key for manual key delivery. Pre-shared keys offer a low-tech solution against the slowly emerging threat of quantum computers. PSKs are less convenient and not usable in every scenario, but until a quantum-safe key exchange algorithm with reasonably short keys is standardized, TFC can't provide a better alternative against quantum computers. The generated keys are protected by a key encryption key, derived from a 256-bit salt and a password (that is to be shared with the recipient) using Argon2id key derivation function. The encrypted message and header keys are stored together with salt on a removable media. This media must be a never-before-used device from sealed packaging. Re-using an old device might infect Source Computer, and the malware could either copy sensitive data on that removable media, or Source Computer might start transmitting the sensitive data covertly over the serial interface to malware on Networked Computer. Once the key has been exported to the clean drive, contact data and keys are exported to the Receiver Program on Destination computer. The transmission is encrypted with the local key. """ try: tx_mk = csprng() tx_hk = csprng() salt = csprng() password = MasterKey.new_password("password for PSK") phase("Deriving key encryption key", head=2) kek = argon2_kdf(password, salt, ARGON2_PSK_TIME_COST, ARGON2_PSK_MEMORY_COST, ARGON2_PSK_PARALLELISM) phase(DONE) ct_tag = encrypt_and_sign(tx_mk + tx_hk, key=kek) while True: trunc_addr = pub_key_to_short_address(onion_pub_key) store_d = ask_path_gui(f"Select removable media for {nick}", settings) f_name = f"{store_d}/{onion_service.user_short_address}.psk - Give to {trunc_addr}" try: with open(f_name, 'wb+') as f: f.write(salt + ct_tag) break except PermissionError: m_print( "Error: Did not have permission to write to the directory.", delay=0.5) continue c_code = blake2b(onion_pub_key, digest_size=CONFIRM_CODE_LENGTH) command = (KEY_EX_PSK_TX + onion_pub_key + tx_mk + csprng() + tx_hk + csprng() + str_to_bytes(nick)) queue_command(command, settings, queues) while True: purp_code = ask_confirmation_code('Receiver') if purp_code == c_code.hex(): break elif purp_code == '': phase("Resending contact data", head=2) queue_command(command, settings, queues) phase(DONE) print_on_previous_line(reps=5) else: m_print("Incorrect confirmation code.", head=1) print_on_previous_line(reps=4, delay=2) contact_list.add_contact(onion_pub_key, nick, bytes(FINGERPRINT_LENGTH), bytes(FINGERPRINT_LENGTH), KEX_STATUS_NO_RX_PSK, settings.log_messages_by_default, settings.accept_files_by_default, settings.show_notifications_by_default) queues[KEY_MANAGEMENT_QUEUE].put( (KDB_ADD_ENTRY_HEADER, onion_pub_key, tx_mk, csprng(), tx_hk, csprng())) m_print(f"Successfully added {nick}.", bold=True, tail_clear=True, delay=1, head=1) except (EOFError, KeyboardInterrupt): raise FunctionReturn("PSK generation aborted.", tail_clear=True, delay=1, head=2)
def create_pre_shared_key(account: str, user: str, nick: str, contact_list: 'ContactList', settings: 'Settings', queues: Dict[bytes, 'Queue']) -> None: """Generate new pre-shared key for manual key delivery. :param account: The contact's account name (e.g. [email protected]) :param user: The user's account name (e.g. [email protected]) :param nick: Nick of contact :param contact_list: Contact list object :param settings: Settings object :param queues: Dictionary of multiprocessing queues :return: None """ try: tx_key = csprng() tx_hek = csprng() salt = csprng() password = MasterKey.new_password("password for PSK") phase("Deriving key encryption key", head=2) kek, _ = argon2_kdf(password, salt, parallelism=1) phase(DONE) ct_tag = encrypt_and_sign(tx_key + tx_hek, key=kek) while True: store_d = ask_path_gui(f"Select removable media for {nick}", settings) f_name = f"{store_d}/{user}.psk - Give to {account}" try: with open(f_name, 'wb+') as f: f.write(salt + ct_tag) break except PermissionError: c_print("Error: Did not have permission to write to directory.") time.sleep(0.5) continue packet = KEY_EX_PSK_TX_HEADER \ + tx_key \ + tx_hek \ + account.encode() + US_BYTE + nick.encode() queue_command(packet, settings, queues[COMMAND_PACKET_QUEUE]) contact_list.add_contact(account, user, nick, bytes(FINGERPRINT_LEN), bytes(FINGERPRINT_LEN), settings.log_messages_by_default, settings.accept_files_by_default, settings.show_notifications_by_default) queues[KEY_MANAGEMENT_QUEUE].put((KDB_ADD_ENTRY_HEADER, account, tx_key, csprng(), tx_hek, csprng())) box_print(f"Successfully added {nick}.", head=1) clear_screen(delay=1) except KeyboardInterrupt: raise FunctionReturn("PSK generation aborted.", delay=1, head=2, tail_clear=True)