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

Commit 4f6aa3f

Browse files
authored
Merge pull request #3 from Freedom-Club-FC/refactor/plausible-deniability
Refactor/plausible deniability
2 parents 5ae091b + 8ec79e3 commit 4f6aa3f

File tree

11 files changed

+250
-393
lines changed

11 files changed

+250
-393
lines changed

core/constants.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
# crypto parameters
1010
AES_GCM_NONCE_LEN = 12 # bytes
1111

12-
OTP_PAD_SIZE = 10240 # bytes
12+
OTP_PAD_SIZE = 11264 # bytes
1313
OTP_PADDING_LENGTH = 2 # bytes
1414
OTP_PADDING_LIMIT = 1024 # bytes
1515

core/crypto.py

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ def generate_kem_keys(algorithm: str = "Kyber1024"):
111111
return private_key, public_key
112112

113113

114-
def decrypt_kyber_shared_secrets(ciphertext_blob: bytes, private_key: bytes, otp_pad_size: int = 10240, algorithm: str = "Kyber1024"):
114+
def decrypt_kyber_shared_secrets(ciphertext_blob: bytes, private_key: bytes, otp_pad_size: int = OTP_PAD_SIZE):
115115
"""
116116
Decapsulates shared_secrets of size otp_pad_size and returns the resulting shared_secrets.
117117
The ciphertexts_blob is expected to be a concatenated sequence of Kyber ciphertexts,
@@ -123,11 +123,12 @@ def decrypt_kyber_shared_secrets(ciphertext_blob: bytes, private_key: bytes, otp
123123
split the blob and decapsulate in order.
124124
"""
125125

126+
cipher_size = 1568 # Kyber1024 ciphertext size
127+
126128
shared_secrets = b''
127-
cipher_size = 1568 # Kyber1024 ciphertext size
128-
cursor = 0
129+
cursor = 0
129130

130-
with oqs.KeyEncapsulation(algorithm, secret_key=private_key) as kem:
131+
with oqs.KeyEncapsulation("Kyber1024", secret_key=private_key) as kem:
131132
while len(shared_secrets) < otp_pad_size:
132133
ciphertext = ciphertext_blob[cursor:cursor + cipher_size]
133134

@@ -140,7 +141,7 @@ def decrypt_kyber_shared_secrets(ciphertext_blob: bytes, private_key: bytes, otp
140141

141142
return shared_secrets[:otp_pad_size]
142143

143-
def generate_kyber_shared_secrets(public_key: bytes, otp_pad_size: int = OTP_PAD_SIZE, algorithm: str = "Kyber1024"):
144+
def generate_kyber_shared_secrets(public_key: bytes, otp_pad_size: int = OTP_PAD_SIZE):
144145
"""
145146
Generates shared_secrets of size otp_pad_size and returns both the ciphertext list-
146147
and the generated shared_secrets.
@@ -159,7 +160,7 @@ def generate_kyber_shared_secrets(public_key: bytes, otp_pad_size: int = OTP_PAD
159160
shared_secrets = b''
160161
ciphertexts_blob = b''
161162

162-
with oqs.KeyEncapsulation(algorithm) as kem:
163+
with oqs.KeyEncapsulation("Kyber1024") as kem:
163164
while len(shared_secrets) < otp_pad_size:
164165
ciphertext, shared_secret = kem.encap_secret(public_key)
165166

@@ -169,9 +170,6 @@ def generate_kyber_shared_secrets(public_key: bytes, otp_pad_size: int = OTP_PAD
169170
return ciphertexts_blob, shared_secrets[:otp_pad_size]
170171

171172

172-
def randomize_replay_protection_number(replay_protection_number: int) -> int:
173-
return random_number_range(replay_protection_number, random_number_range(replay_protection_number + 1, replay_protection_number + random_number_range(100, 1000)))
174-
175173
def random_number_range(a: int, b: int) -> int:
176174
return secrets.randbelow(b - a + 1) + a
177175

logic/background_worker.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
from core.requests import http_request
22
from logic.storage import save_account_data
33
from logic.contacts import save_contact
4-
from logic.get_user import get_target_lt_public_key
54
from logic.smp import smp_unanswered_questions, smp_data_handler
65
from logic.pfs import pfs_data_handler
76
from logic.message import messages_data_handler

logic/contacts.py

Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -29,19 +29,24 @@ def generate_random_nickname(user_data: dict, user_data_lock, contact_id: str, n
2929
return nickname
3030

3131

32-
def save_contact(user_data: dict, user_data_lock, contact_id: str, contact_public_key: bytes) -> None:
32+
def save_contact(user_data: dict, user_data_lock, contact_id: str) -> None:
3333
with user_data_lock:
3434
if contact_id in user_data["contacts"]:
3535
raise ValueError("Contact already saved!")
3636

37-
for i, v in user_data["contacts"].items():
38-
if v["lt_sign_public_key"] == contact_public_key:
39-
raise ValueError("Contact long-term auth signing public-key is duplicated, and we have no idea why")
40-
4137

4238
user_data["contacts"][contact_id] = {
4339
"nickname": None,
44-
"lt_sign_public_key": contact_public_key,
40+
"lt_sign_keys": {
41+
"contact_public_key": None,
42+
"our_keys": {
43+
"private_key": None,
44+
"public_key": None
45+
},
46+
"our_hash_chain": None,
47+
"contact_hash_chain": None
48+
49+
},
4550
"lt_sign_key_smp": {
4651
"verified": False,
4752
"pending_verification": False,
@@ -59,23 +64,14 @@ def save_contact(user_data: dict, user_data_lock, contact_id: str, contact_publi
5964
},
6065
"rotation_counter": None,
6166
"rotate_at": None,
62-
"our_hash_chain": None,
63-
"contact_hash_chain": None
6467

6568
},
66-
"message_sign_keys": {
67-
"contact_public_key": None,
68-
"our_keys": {
69-
"private_key": None,
70-
"public_key": None
71-
}
72-
},
7369
"our_pads": {
74-
"replay_protection_number": None,
70+
"hash_chain": None,
7571
"pads": None
7672
},
7773
"contact_pads": {
78-
"replay_protection_number": None,
74+
"hash_chain": None,
7975
"pads": None
8076
},
8177
}

logic/get_user.py

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,24 @@
1-
from base64 import b64decode
21
from core.requests import http_request
32

4-
def get_target_lt_public_key(user_data: dict, target_id: str) -> bytes:
5-
url = user_data["server_url"]
3+
def check_if_contact_exists(user_data: dict, user_data_lock, contact_id: str) -> bool:
4+
with user_data_lock:
5+
url = user_data["server_url"]
66

77
try:
8-
response = http_request(f"{url}/get_user?user_id={target_id}", "GET")
8+
response = http_request(f"{url}/get_user?user_id={contact_id}", "GET")
99
except:
1010
raise ValueError("Could not connect to server, try again")
1111

1212
if not "status" in response:
13-
raise ValueError("Server gave a malformed response! This could be a malicious act, we suggest you retry and if problem persists use another server")
13+
raise ValueError("Server gave a malformed response")
1414

15-
if response["status"] == "failure" or not response.get("public_key"):
15+
if response["status"] == "failure":
1616
if not 'error' in response:
17-
raise ValueError("Server gave a malformed response! This could be a malicious act, we suggest you retry and if problem persists use another server")
17+
raise ValueError("Server gave a malformed response")
1818
else:
1919
raise ValueError(response["error"][:1024])
2020

2121
if response["status"] == "success":
22+
return True
2223

23-
# Dry run to validate server's base64. Helps prevents denial-of-service startup crashes -
24-
# when client first reads parses their account file
25-
try:
26-
return b64decode(response["public_key"], validate=True)
27-
except:
28-
raise ValueError("Server gave a malformed public_key! This could be a malicious act, we suggest you retry and if problem persists use another server")
24+
return False

0 commit comments

Comments
 (0)