Skip to content

Commit b23e344

Browse files
committed
Add messages for mismatched checks
1 parent ae028ab commit b23e344

File tree

5 files changed

+59
-34
lines changed

5 files changed

+59
-34
lines changed

pyrogram/client.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -982,7 +982,10 @@ async def get_file(
982982
# https://core.telegram.org/cdn#verifying-files
983983
for i, h in enumerate(hashes):
984984
cdn_chunk = decrypted_chunk[h.limit * i: h.limit * (i + 1)]
985-
CDNFileHashMismatch.check(h.hash == sha256(cdn_chunk).digest())
985+
CDNFileHashMismatch.check(
986+
h.hash == sha256(cdn_chunk).digest(),
987+
"h.hash == sha256(cdn_chunk).digest()"
988+
)
986989

987990
yield decrypted_chunk
988991

pyrogram/crypto/mtproto.py

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -62,15 +62,15 @@ def unpack(
6262
auth_key_id: bytes,
6363
stored_msg_ids: List[int]
6464
) -> Message:
65-
SecurityCheckMismatch.check(b.read(8) == auth_key_id)
65+
SecurityCheckMismatch.check(b.read(8) == auth_key_id, "b.read(8) == auth_key_id")
6666

6767
msg_key = b.read(16)
6868
aes_key, aes_iv = kdf(auth_key, msg_key, False)
6969
data = BytesIO(aes.ige256_decrypt(b.read(), aes_key, aes_iv))
7070
data.read(8) # Salt
7171

7272
# https://core.telegram.org/mtproto/security_guidelines#checking-session-id
73-
SecurityCheckMismatch.check(data.read(8) == session_id)
73+
SecurityCheckMismatch.check(data.read(8) == session_id, "data.read(8) == session_id")
7474

7575
try:
7676
message = Message.read(data)
@@ -88,39 +88,40 @@ def unpack(
8888

8989
# https://core.telegram.org/mtproto/security_guidelines#checking-sha256-hash-value-of-msg-key
9090
# 96 = 88 + 8 (incoming message)
91-
SecurityCheckMismatch.check(msg_key == sha256(auth_key[96:96 + 32] + data.getvalue()).digest()[8:24])
91+
SecurityCheckMismatch.check(
92+
msg_key == sha256(auth_key[96:96 + 32] + data.getvalue()).digest()[8:24],
93+
"msg_key == sha256(auth_key[96:96 + 32] + data.getvalue()).digest()[8:24]"
94+
)
9295

9396
# https://core.telegram.org/mtproto/security_guidelines#checking-message-length
9497
data.seek(32) # Get to the payload, skip salt (8) + session_id (8) + msg_id (8) + seq_no (4) + length (4)
9598
payload = data.read()
9699
padding = payload[message.length:]
97-
SecurityCheckMismatch.check(12 <= len(padding) <= 1024)
98-
SecurityCheckMismatch.check(len(payload) % 4 == 0)
100+
SecurityCheckMismatch.check(12 <= len(padding) <= 1024, "12 <= len(padding) <= 1024")
101+
SecurityCheckMismatch.check(len(payload) % 4 == 0, "len(payload) % 4 == 0")
99102

100103
# https://core.telegram.org/mtproto/security_guidelines#checking-msg-id
101-
SecurityCheckMismatch.check(message.msg_id % 2 != 0)
104+
SecurityCheckMismatch.check(message.msg_id % 2 != 0, "message.msg_id % 2 != 0")
102105

103106
if len(stored_msg_ids) > STORED_MSG_IDS_MAX_SIZE:
104107
del stored_msg_ids[:STORED_MSG_IDS_MAX_SIZE // 2]
105108

106109
if stored_msg_ids:
107-
# Ignored message: msg_id is lower than all of the stored values
108110
if message.msg_id < stored_msg_ids[0]:
109-
raise SecurityCheckMismatch
111+
raise SecurityCheckMismatch("The msg_id is lower than all the stored values")
110112

111-
# Ignored message: msg_id is equal to any of the stored values
112113
if message.msg_id in stored_msg_ids:
113-
raise SecurityCheckMismatch
114+
raise SecurityCheckMismatch("The msg_id is equal to any of the stored values")
114115

115116
time_diff = (message.msg_id - MsgId()) / 2 ** 32
116117

117-
# Ignored message: msg_id belongs over 30 seconds in the future
118118
if time_diff > 30:
119-
raise SecurityCheckMismatch
119+
raise SecurityCheckMismatch("The msg_id belongs to over 30 seconds in the future. "
120+
"Most likely the client time has to be synchronized.")
120121

121-
# Ignored message: msg_id belongs over 300 seconds in the past
122122
if time_diff < -300:
123-
raise SecurityCheckMismatch
123+
raise SecurityCheckMismatch("The msg_id belongs to over 300 seconds in the past. "
124+
"Most likely the client time has to be synchronized.")
124125

125126
bisect.insort(stored_msg_ids, message.msg_id)
126127

pyrogram/errors/__init__.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -45,21 +45,21 @@ class SecurityError(Exception):
4545
"""Generic security error."""
4646

4747
@classmethod
48-
def check(cls, cond: bool):
48+
def check(cls, cond: bool, msg: str):
4949
"""Raises this exception if the condition is false"""
5050
if not cond:
51-
raise cls
51+
raise cls(f"Check failed: {msg}")
5252

5353

5454
class SecurityCheckMismatch(SecurityError):
5555
"""Raised when a security check mismatch occurs."""
5656

57-
def __init__(self):
58-
super().__init__("A security check mismatch has occurred.")
57+
def __init__(self, msg: str = None):
58+
super().__init__("A security check mismatch has occurred." if msg is None else msg)
5959

6060

6161
class CDNFileHashMismatch(SecurityError):
6262
"""Raised when a CDN file hash mismatch occurs."""
6363

64-
def __init__(self):
65-
super().__init__("A CDN file hash mismatch has occurred.")
64+
def __init__(self, msg: str = None):
65+
super().__init__("A CDN file hash mismatch has occurred." if msg is None else msg)

pyrogram/session/auth.py

Lines changed: 32 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -211,33 +211,51 @@ async def create(self):
211211
# Security checks
212212
#######################
213213

214-
SecurityCheckMismatch.check(dh_prime == prime.CURRENT_DH_PRIME)
214+
SecurityCheckMismatch.check(dh_prime == prime.CURRENT_DH_PRIME, "dh_prime == prime.CURRENT_DH_PRIME")
215215
log.debug("DH parameters check: OK")
216216

217217
# https://core.telegram.org/mtproto/security_guidelines#g-a-and-g-b-validation
218218
g_b = int.from_bytes(g_b, "big")
219-
SecurityCheckMismatch.check(1 < g < dh_prime - 1)
220-
SecurityCheckMismatch.check(1 < g_a < dh_prime - 1)
221-
SecurityCheckMismatch.check(1 < g_b < dh_prime - 1)
222-
SecurityCheckMismatch.check(2 ** (2048 - 64) < g_a < dh_prime - 2 ** (2048 - 64))
223-
SecurityCheckMismatch.check(2 ** (2048 - 64) < g_b < dh_prime - 2 ** (2048 - 64))
219+
SecurityCheckMismatch.check(1 < g < dh_prime - 1, "1 < g < dh_prime - 1")
220+
SecurityCheckMismatch.check(1 < g_a < dh_prime - 1, "1 < g_a < dh_prime - 1")
221+
SecurityCheckMismatch.check(1 < g_b < dh_prime - 1, "1 < g_b < dh_prime - 1")
222+
SecurityCheckMismatch.check(
223+
2 ** (2048 - 64) < g_a < dh_prime - 2 ** (2048 - 64),
224+
"2 ** (2048 - 64) < g_a < dh_prime - 2 ** (2048 - 64)"
225+
)
226+
SecurityCheckMismatch.check(
227+
2 ** (2048 - 64) < g_b < dh_prime - 2 ** (2048 - 64),
228+
"2 ** (2048 - 64) < g_b < dh_prime - 2 ** (2048 - 64)"
229+
)
224230
log.debug("g_a and g_b validation: OK")
225231

226232
# https://core.telegram.org/mtproto/security_guidelines#checking-sha1-hash-values
227233
answer = server_dh_inner_data.write() # Call .write() to remove padding
228-
SecurityCheckMismatch.check(answer_with_hash[:20] == sha1(answer).digest())
234+
SecurityCheckMismatch.check(
235+
answer_with_hash[:20] == sha1(answer).digest(),
236+
"answer_with_hash[:20] == sha1(answer).digest()"
237+
)
229238
log.debug("SHA1 hash values check: OK")
230239

231240
# https://core.telegram.org/mtproto/security_guidelines#checking-nonce-server-nonce-and-new-nonce-fields
232241
# 1st message
233-
SecurityCheckMismatch.check(nonce == res_pq.nonce)
242+
SecurityCheckMismatch.check(nonce == res_pq.nonce, "nonce == res_pq.nonce")
234243
# 2nd message
235244
server_nonce = int.from_bytes(server_nonce, "little", signed=True)
236-
SecurityCheckMismatch.check(nonce == server_dh_params.nonce)
237-
SecurityCheckMismatch.check(server_nonce == server_dh_params.server_nonce)
245+
SecurityCheckMismatch.check(nonce == server_dh_params.nonce, "nonce == server_dh_params.nonce")
246+
SecurityCheckMismatch.check(
247+
server_nonce == server_dh_params.server_nonce,
248+
"server_nonce == server_dh_params.server_nonce"
249+
)
238250
# 3rd message
239-
SecurityCheckMismatch.check(nonce == set_client_dh_params_answer.nonce)
240-
SecurityCheckMismatch.check(server_nonce == set_client_dh_params_answer.server_nonce)
251+
SecurityCheckMismatch.check(
252+
nonce == set_client_dh_params_answer.nonce,
253+
"nonce == set_client_dh_params_answer.nonce"
254+
)
255+
SecurityCheckMismatch.check(
256+
server_nonce == set_client_dh_params_answer.server_nonce,
257+
"server_nonce == set_client_dh_params_answer.server_nonce"
258+
)
241259
server_nonce = server_nonce.to_bytes(16, "little", signed=True)
242260
log.debug("Nonce fields check: OK")
243261

@@ -248,6 +266,8 @@ async def create(self):
248266

249267
log.info(f"Done auth key exchange: {set_client_dh_params_answer.__class__.__name__}")
250268
except Exception as e:
269+
log.info(f"Retrying due to {type(e).__name__}: {e}")
270+
251271
if retries_left:
252272
retries_left -= 1
253273
else:

pyrogram/session/session.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,8 @@ async def handle_packet(self, packet):
188188
self.auth_key_id,
189189
self.stored_msg_ids
190190
)
191-
except SecurityCheckMismatch:
191+
except SecurityCheckMismatch as e:
192+
log.info(f"Discarding packet: {e}")
192193
return
193194

194195
messages = (

0 commit comments

Comments
 (0)