1+ """
2+ logic/message.py
3+ -----------
4+ Message sending, receiving, and one-time-pad key exchange logic.
5+ Handles:
6+ - Generation and transmission of Kyber-encrypted OTP batches
7+ - Ephemeral key rotation enforcement for PFS
8+ - Message encryption/decryption with hash chain integrity checks
9+ - Incoming message processing and replay/tampering protection
10+ """
11+
112from core .requests import http_request
213from logic .storage import save_account_data
314from logic .pfs import send_new_ephemeral_keys
415from core .trad_crypto import sha3_512
5- from core .crypto import *
6- from core .constants import *
16+ from core .crypto import (
17+ generate_kyber_shared_secrets ,
18+ decrypt_kyber_shared_secrets ,
19+ create_signature ,
20+ verify_signature ,
21+ otp_encrypt_with_padding ,
22+ otp_decrypt_with_padding
23+ )
24+ from core .constants import (
25+ OTP_PADDING_LIMIT ,
26+ OTP_PADDING_LENGTH ,
27+ ML_KEM_1024_NAME ,
28+ ML_DSA_87_NAME ,
29+ )
730from base64 import b64decode , b64encode
831import copy
932import json
1336
1437
1538def generate_and_send_pads (user_data , user_data_lock , contact_id : str , ui_queue ) -> bool :
39+ """
40+ Generates a new Kyber OTP batch, signs it with Dilithium, and sends it to the server.
41+ Updates local pad and hash chain state upon success.
42+ Returns:
43+ bool: True if successful, False otherwise.
44+ """
1645 with user_data_lock :
1746 server_url = user_data ["server_url" ]
1847 auth_token = user_data ["token" ]
@@ -23,7 +52,7 @@ def generate_and_send_pads(user_data, user_data_lock, contact_id: str, ui_queue)
2352
2453 ciphertext_blob , pads = generate_kyber_shared_secrets (contact_kyber_public_key )
2554
26- otp_batch_signature = create_signature ("Dilithium5" , ciphertext_blob , our_lt_private_key )
55+ otp_batch_signature = create_signature (ML_DSA_87_NAME , ciphertext_blob , our_lt_private_key )
2756 otp_batch_signature = b64encode (otp_batch_signature ).decode ()
2857
2958 payload = {
@@ -48,6 +77,16 @@ def generate_and_send_pads(user_data, user_data_lock, contact_id: str, ui_queue)
4877
4978
5079def send_message_processor (user_data , user_data_lock , contact_id : str , message : str , ui_queue ) -> bool :
80+ """
81+ Encrypts and sends a message to the contact.
82+ Handles:
83+ - OTP pad consumption and regeneration
84+ - Ephemeral key rotation
85+ - Hash chain integrity
86+ - Server transmission
87+ Returns:
88+ bool: True if successful, False otherwise.
89+ """
5190 # We don't deepcopy here as real-time states are required here for maximum future-proofing.
5291
5392 with user_data_lock :
@@ -189,7 +228,12 @@ def send_message_processor(user_data, user_data_lock, contact_id: str, message:
189228
190229
191230
192- def messages_data_handler (user_data , user_data_lock , user_data_copied , ui_queue , message ):
231+ def messages_data_handler (user_data : dict , user_data_lock , user_data_copied : dict , ui_queue , message : dict ) -> None :
232+ """
233+ Handles incoming messages and OTP batches.
234+ Verifies signatures, decrypts payloads, updates pads/hash chain, and forwards plaintext to UI.
235+ Skips or logs suspicious or invalid messages.
236+ """
193237 contact_id = message ["sender" ]
194238
195239 if (not (contact_id in user_data_copied ["contacts" ])):
@@ -206,7 +250,7 @@ def messages_data_handler(user_data, user_data_lock, user_data_copied, ui_queue,
206250 contact_public_key = user_data_copied ["contacts" ][contact_id ]["lt_sign_keys" ]["contact_public_key" ]
207251
208252 if not contact_public_key :
209- logger .warning ("Contact per-contact Dilithium5 public key is missing.. skipping message" )
253+ logger .warning ("Contact per-contact Dilithium 5 public key is missing.. skipping message" )
210254 return
211255
212256
@@ -216,7 +260,7 @@ def messages_data_handler(user_data, user_data_lock, user_data_copied, ui_queue,
216260 otp_hashchain_signature = b64decode (message ["otp_hashchain_signature" ], validate = True )
217261 otp_hashchain_ciphertext = b64decode (message ["otp_hashchain_ciphertext" ], validate = True )
218262
219- valid_signature = verify_signature ("Dilithium5" , otp_hashchain_ciphertext , otp_hashchain_signature , contact_public_key )
263+ valid_signature = verify_signature (ML_DSA_87_NAME , otp_hashchain_ciphertext , otp_hashchain_signature , contact_public_key )
220264 if not valid_signature :
221265 logger .debug ("Invalid OTP_hashchain_ciphertext signature.. possible MiTM ?" )
222266 return
@@ -246,6 +290,7 @@ def messages_data_handler(user_data, user_data_lock, user_data_copied, ui_queue,
246290 contact_hash_chain = user_data ["contacts" ][contact_id ]["contact_pads" ]["hash_chain" ]
247291
248292 if (not contact_pads ) or (len (message_encrypted ) > len (contact_pads )):
293+ # TODO: Maybe reset our local pads as well?
249294 logger .warning ("Message payload is larger than our local pads for the contact, we are skipping this message.." )
250295 return
251296
0 commit comments