Skip to content
This repository was archived by the owner on Mar 10, 2026. It is now read-only.

Commit c249147

Browse files
committed
refactor: code cleanup
1 parent 1d990f3 commit c249147

File tree

5 files changed

+29
-50
lines changed

5 files changed

+29
-50
lines changed

core/constants.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,12 @@
3636
OTP_MAX_MESSAGE_LEN = OTP_PAD_SIZE - OTP_SIZE_LENGTH
3737

3838
XCHACHA20POLY1305_NONCE_LEN = 24
39-
XCHACHA20POLY1305_SIZE_LEN = 3
39+
XCHACHA20POLY1305_SIZE_LEN = 4
4040
XCHACHA20POLY1305_MAX_RANODM_PAD = OTP_PAD_SIZE
4141

4242
CHACHA20POLY1305_NONCE_LEN = 12
43-
CHACHA20POLY1305_SIZE_LEN = 2
44-
CHACHA20POLY1305_MAX_RANODM_PAD = OTP_PAD_SIZE
43+
CHACHA20POLY1305_SIZE_LEN = 4
44+
CHACHA20POLY1305_MAX_RANODM_PAD = 64 # DEBUG
4545

4646

4747

@@ -72,7 +72,6 @@
7272
CLASSIC_MCELIECE_8_PK_LEN = 1357824
7373
CLASSIC_MCELIECE_8_CT_LEN = 208
7474

75-
CLASSIC_MCELIECE_8_ROTATE_AT = 3 # Default OTP batches needed to be sent for a key rotation to occur
7675

7776

7877

@@ -95,7 +94,11 @@
9594
}
9695

9796
# hash parameters
98-
ARGON2_MEMORY = 1 * 1024**3 # GB
97+
98+
ARGON2_MEMORY = 4 * 1024**3 # GB
99+
100+
# ARGON2_MEMORY = 1 * 1024**2 # Debug
101+
99102
ARGON2_ITERS = 3
100103
ARGON2_OUTPUT_LEN = 64 # bytes
101104
ARGON2_SALT_LEN = 16 # bytes (Must be always 16 for interoperability with implementations using libsodium.)

core/trad_crypto.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ def decrypt_xchacha20poly1305(key: bytes, nonce: bytes, ciphertext: bytes) -> by
143143

144144

145145

146-
def encrypt_chacha20poly1305(key: bytes, plaintext: bytes, nonce: bytes = None, max_padding: int = XCHACHA20POLY1305_MAX_RANODM_PAD) -> tuple[bytes, bytes]:
146+
def encrypt_chacha20poly1305(key: bytes, plaintext: bytes, nonce: bytes = None, max_padding: int = CHACHA20POLY1305_MAX_RANODM_PAD) -> tuple[bytes, bytes]:
147147
"""
148148
Encrypt plaintext using ChaCha20Poly1305.
149149
@@ -153,7 +153,7 @@ def encrypt_chacha20poly1305(key: bytes, plaintext: bytes, nonce: bytes = None,
153153
key: A 32-byte ChaCha20Poly1305 key.
154154
plaintext: Data to encrypt.
155155
nonce: An (optional) nonce to be used.
156-
max_padding: an (optional) maximum padding limit number to message. Cannot be larger than what `XCHACHA20POLY1305_MAX_RANODM_PAD` could store. Set to 0 for no padding.
156+
max_padding: an (optional) maximum padding limit number to message. Cannot be larger than what `CHACHA20POLY1305_MAX_RANODM_PAD` could store. Set to 0 for no padding.
157157
Returns:
158158
A tuple (nonce, ciphertext) where:
159159
- nonce: The randomly generated nonce or the same given nonce.

logic/contacts.py

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,7 @@
55

66
from core.constants import (
77
ML_KEM_1024_NAME,
8-
CLASSIC_MCELIECE_8_NAME,
9-
CLASSIC_MCELIECE_8_ROTATE_AT
8+
CLASSIC_MCELIECE_8_NAME
109
)
1110

1211
def generate_nickname_id(length: int = 4) -> str:
@@ -75,9 +74,7 @@ def save_contact(user_data: dict, user_data_lock, contact_id: str) -> None:
7574
"our_keys": {
7675
CLASSIC_MCELIECE_8_NAME: {
7776
"public_key": None,
78-
"private_key": None,
79-
"rotation_counter": 0,
80-
"rotate_at": CLASSIC_MCELIECE_8_ROTATE_AT,
77+
"private_key": None
8178
},
8279
ML_KEM_1024_NAME: {
8380
"public_key": None,

logic/message.py

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -319,21 +319,18 @@ def messages_data_handler(user_data: dict, user_data_lock, user_data_copied: dic
319319

320320
user_data["contacts"][contact_id]["contact_next_strand_key"] = contact_next_strand_key
321321

322-
user_data["contacts"][contact_id]["ephemeral_keys"]["our_keys"][CLASSIC_MCELIECE_8_NAME]["rotation_counter"] += 1
323-
324322
staged_kyber_private_key = bool(user_data["contacts"][contact_id]["ephemeral_keys"]["staged_keys"][ML_KEM_1024_NAME]["private_key"])
323+
staged_mceliece_private_key = bool(user_data["contacts"][contact_id]["ephemeral_keys"]["staged_keys"][CLASSIC_MCELIECE_8_NAME]["private_key"])
325324

326-
rotation_counter = user_data["contacts"][contact_id]["ephemeral_keys"]["our_keys"][CLASSIC_MCELIECE_8_NAME]["rotation_counter"]
327325

328326

329-
logger.debug("Incremented McEliece's rotation_counter by 1 (now is %d) for contact (%s)", rotation_counter, contact_id)
330327

331328
logger.info("Saved contact (%s) new batch of One-Time-Pads, new strand key, and new hash chain seed", contact_id)
332329
save_account_data(user_data, user_data_lock)
333330

334331
# Why ???????
335332
# Nvm, I know why, PFS.
336-
if not staged_kyber_private_key:
333+
if (not staged_kyber_private_key) and (not staged_mceliece_private_key):
337334
logger.info("Rotating our ephemeral keys")
338335
send_new_ephemeral_keys(user_data, user_data_lock, contact_id, ui_queue)
339336
save_account_data(user_data, user_data_lock)

logic/pfs.py

Lines changed: 15 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
Handles Perfect Forward Secrecy (PFS) ephemeral keys exchange and rotation for contacts.
33
44
Handles:
5-
- Generates and rotates ephemeral (one-time use) ML-KEM-1024 keys and (medium-term) Classic McEliece keys.
5+
- Generates and rotates ephemeral (one-time use) ML-KEM-1024 and Classic McEliece keys.
66
- Uses per-contact hash chains to prevent replay attacks, and verifies authenticity using ML-DSA-87.
77
- Sends and receives signed ephemeral keys using long-term signing keys.
88
- Updates local account storage with new key material after successful exchange.
@@ -24,7 +24,6 @@
2424
CHACHA20POLY1305_NONCE_LEN,
2525
CLASSIC_MCELIECE_8_NAME,
2626
CLASSIC_MCELIECE_8_PK_LEN,
27-
CLASSIC_MCELIECE_8_ROTATE_AT,
2827
KEYS_HASH_CHAIN_LEN
2928
)
3029
from core.trad_crypto import (
@@ -86,8 +85,7 @@ def send_new_ephemeral_keys(user_data: dict, user_data_lock: threading.Lock, con
8685
Generate, encrypt, and send fresh ephemeral keys to a contact.
8786
8887
- Maintains a per-contact hash chain for signing key material.
89-
- Generates new Kyber1024 keys every call.
90-
- Optionally rotates McEliece keys if rotation threshold is reached.
88+
- Generates new Kyber1024 and McEliece keys every call.
9189
- Signs all key material with the long-term signing key.
9290
- Sends to the server using an authenticated HTTP request.
9391
- If successful, stores new keys in `user_data["tmp"]` for later update.
@@ -112,8 +110,6 @@ def send_new_ephemeral_keys(user_data: dict, user_data_lock: threading.Lock, con
112110
session_headers = user_data_copied["tmp"]["session_headers"]
113111

114112

115-
rotation_counter = user_data_copied["contacts"][contact_id]["ephemeral_keys"]["our_keys"][CLASSIC_MCELIECE_8_NAME]["rotation_counter"]
116-
rotate_at = user_data_copied["contacts"][contact_id]["ephemeral_keys"]["our_keys"][CLASSIC_MCELIECE_8_NAME]["rotate_at"]
117113

118114
lt_sign_private_key = user_data_copied["contacts"][contact_id]["lt_sign_keys"]["our_keys"]["private_key"]
119115

@@ -131,14 +127,11 @@ def send_new_ephemeral_keys(user_data: dict, user_data_lock: threading.Lock, con
131127

132128
# Generate new ML-KEM-1024 keys for us
133129
kyber_private_key, kyber_public_key = generate_kem_keys(ML_KEM_1024_NAME)
134-
publickeys_hashchain = our_hash_chain + kyber_public_key
135130

136-
rotate_mceliece = False
137-
if (rotate_at == rotation_counter) or (user_data["contacts"][contact_id]["ephemeral_keys"]["our_keys"][CLASSIC_MCELIECE_8_NAME]["private_key"] is None):
138-
# Generate Classic McEliece 8192128f keys
139-
mceliece_private_key, mceliece_public_key = generate_kem_keys(CLASSIC_MCELIECE_8_NAME)
140-
publickeys_hashchain += mceliece_public_key
141-
rotate_mceliece = True
131+
# Generate Classic McEliece 8192128 keys
132+
mceliece_private_key, mceliece_public_key = generate_kem_keys(CLASSIC_MCELIECE_8_NAME)
133+
134+
publickeys_hashchain = our_hash_chain + kyber_public_key + mceliece_public_key
142135

143136
# Sign them with our per-contact long-term private key
144137
publickeys_hashchain_signature = create_signature(ML_DSA_87_NAME, publickeys_hashchain, lt_sign_private_key)
@@ -174,13 +167,8 @@ def send_new_ephemeral_keys(user_data: dict, user_data_lock: threading.Lock, con
174167
user_data["contacts"][contact_id]["ephemeral_keys"]["staged_keys"][ML_KEM_1024_NAME]["public_key"] = kyber_public_key
175168

176169

177-
if rotate_mceliece:
178-
user_data["contacts"][contact_id]["ephemeral_keys"]["staged_keys"][CLASSIC_MCELIECE_8_NAME]["private_key"] = mceliece_private_key
179-
user_data["contacts"][contact_id]["ephemeral_keys"]["staged_keys"][CLASSIC_MCELIECE_8_NAME]["public_key"] = mceliece_public_key
180-
181-
182-
user_data["contacts"][contact_id]["ephemeral_keys"]["our_keys"][CLASSIC_MCELIECE_8_NAME]["rotation_counter"] = 0
183-
user_data["contacts"][contact_id]["ephemeral_keys"]["our_keys"][CLASSIC_MCELIECE_8_NAME]["rotate_at"] = CLASSIC_MCELIECE_8_ROTATE_AT
170+
user_data["contacts"][contact_id]["ephemeral_keys"]["staged_keys"][CLASSIC_MCELIECE_8_NAME]["private_key"] = mceliece_private_key
171+
user_data["contacts"][contact_id]["ephemeral_keys"]["staged_keys"][CLASSIC_MCELIECE_8_NAME]["public_key"] = mceliece_public_key
184172

185173

186174

@@ -260,9 +248,7 @@ def pfs_data_handler(user_data: dict, user_data_lock: threading.Lock, user_data_
260248

261249

262250
if (
263-
(len(pfs_plaintext) < ML_KEM_1024_PK_LEN + ML_DSA_87_SIGN_LEN + KEYS_HASH_CHAIN_LEN)
264-
or
265-
len(pfs_plaintext) > ML_KEM_1024_PK_LEN + ML_DSA_87_SIGN_LEN + CLASSIC_MCELIECE_8_PK_LEN + KEYS_HASH_CHAIN_LEN
251+
len(pfs_plaintext) != ML_KEM_1024_PK_LEN + ML_DSA_87_SIGN_LEN + CLASSIC_MCELIECE_8_PK_LEN + KEYS_HASH_CHAIN_LEN
266252
):
267253
logger.error("Contact (%s) gave us a PFS request with malformed strand plaintext length (%d)", contact_id, len(pfs_plaintext))
268254
return
@@ -295,17 +281,12 @@ def pfs_data_handler(user_data: dict, user_data_lock: threading.Lock, user_data_
295281
logger.error("Contact keys hash chain does not match our computed hash chain! Skipping this PFS message...")
296282
return
297283

298-
contact_kyber_public_key = contact_publickeys_hashchain[KEYS_HASH_CHAIN_LEN: ML_KEM_1024_PK_LEN + KEYS_HASH_CHAIN_LEN]
299-
300-
if len(contact_publickeys_hashchain) == ML_KEM_1024_PK_LEN + CLASSIC_MCELIECE_8_PK_LEN + KEYS_HASH_CHAIN_LEN:
301-
logger.info("contact (%s) has rotated their Kyber and McEliece keys", contact_id)
284+
285+
logger.info("contact (%s) has rotated their Kyber and McEliece keys", contact_id)
302286

303-
contact_mceliece_public_key = contact_publickeys_hashchain[ML_KEM_1024_PK_LEN + KEYS_HASH_CHAIN_LEN:]
304-
with user_data_lock:
305-
user_data["contacts"][contact_id]["ephemeral_keys"]["contact_public_keys"][CLASSIC_MCELIECE_8_NAME] = contact_mceliece_public_key
287+
contact_kyber_public_key = contact_publickeys_hashchain[KEYS_HASH_CHAIN_LEN: ML_KEM_1024_PK_LEN + KEYS_HASH_CHAIN_LEN]
306288

307-
elif len(contact_publickeys_hashchain) == ML_KEM_1024_PK_LEN + KEYS_HASH_CHAIN_LEN:
308-
logger.info("contact (%s) has rotated their Kyber keys", contact_id)
289+
contact_mceliece_public_key = contact_publickeys_hashchain[ML_KEM_1024_PK_LEN + KEYS_HASH_CHAIN_LEN:]
309290

310291

311292
logger.info("We are acknowledging contact's new PFS keys")
@@ -315,7 +296,8 @@ def pfs_data_handler(user_data: dict, user_data_lock: threading.Lock, user_data_
315296
with user_data_lock:
316297
user_data["contacts"][contact_id]["lt_sign_keys"]["contact_hash_chain"] = contact_hash_chain
317298
user_data["contacts"][contact_id]["ephemeral_keys"]["contact_public_keys"][ML_KEM_1024_NAME] = contact_kyber_public_key
318-
299+
user_data["contacts"][contact_id]["ephemeral_keys"]["contact_public_keys"][CLASSIC_MCELIECE_8_NAME] = contact_mceliece_public_key
300+
319301
our_kyber_private_key = user_data["contacts"][contact_id]["ephemeral_keys"]["our_keys"][ML_KEM_1024_NAME]["private_key"]
320302
our_mceliece_private_key = user_data["contacts"][contact_id]["ephemeral_keys"]["our_keys"][CLASSIC_MCELIECE_8_NAME]["private_key"]
321303

0 commit comments

Comments
 (0)