Skip to content

Commit 8639dd0

Browse files
committed
feat(crypto): enhance mtproto padding and rsa key validation
1 parent 8c596ce commit 8639dd0

3 files changed

Lines changed: 21 additions & 18 deletions

File tree

pyrogram/crypto/aes.py

Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,15 @@
2020

2121
log = logging.getLogger(__name__)
2222

23+
24+
def xor(a: bytes, b: bytes) -> bytes:
25+
return int.to_bytes(
26+
int.from_bytes(a, "big") ^ int.from_bytes(b, "big"),
27+
len(a),
28+
"big",
29+
)
30+
31+
2332
try:
2433
import tgcrypto
2534

@@ -41,13 +50,6 @@ def ctr256_encrypt(data: bytes, key: bytes, iv: bytearray, state: bytearray = No
4150
def ctr256_decrypt(data: bytes, key: bytes, iv: bytearray, state: bytearray = None) -> bytes:
4251
return tgcrypto.ctr256_decrypt(data, key, iv, state or bytearray(1))
4352

44-
45-
def xor(a: bytes, b: bytes) -> bytes:
46-
return int.to_bytes(
47-
int.from_bytes(a, "big") ^ int.from_bytes(b, "big"),
48-
len(a),
49-
"big",
50-
)
5153
except ImportError:
5254
import pyaes
5355

@@ -74,14 +76,6 @@ def ctr256_decrypt(data: bytes, key: bytes, iv: bytearray, state: bytearray = No
7476
return ctr(data, key, iv, state or bytearray(1))
7577

7678

77-
def xor(a: bytes, b: bytes) -> bytes:
78-
return int.to_bytes(
79-
int.from_bytes(a, "big") ^ int.from_bytes(b, "big"),
80-
len(a),
81-
"big",
82-
)
83-
84-
8579
def ige(data: bytes, key: bytes, iv: bytes, encrypt: bool) -> bytes:
8680
cipher = pyaes.AES(key)
8781

pyrogram/crypto/mtproto.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
from hashlib import sha256
2020
from io import BytesIO
2121
from os import urandom
22+
from random import randint
2223

2324
from pyrogram.errors import SecurityCheckMismatch
2425
from pyrogram.raw.core import Message, Long
@@ -40,7 +41,9 @@ def kdf(auth_key: bytes, msg_key: bytes, outgoing: bool) -> tuple:
4041

4142
def pack(message: Message, salt: int, session_id: bytes, auth_key: bytes, auth_key_id: bytes) -> bytes:
4243
data = Long(salt) + session_id + message.write()
43-
padding = urandom(-(len(data) + 12) % 16 + 12)
44+
# Spec allows 12-1024 bytes; add extra random multiples of 16 for traffic analysis resistance
45+
min_padding = -(len(data) + 12) % 16 + 12
46+
padding = urandom(min_padding + 16 * randint(0, 4))
4447

4548
# 88 = 88 + 0 (outgoing message)
4649
msg_key_large = sha256(auth_key[88: 88 + 32] + data + padding).digest()

pyrogram/crypto/rsa.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -252,8 +252,14 @@
252252

253253

254254
def encrypt(data: bytes, fingerprint: int) -> bytes:
255+
key = server_public_keys.get(fingerprint)
256+
if key is None:
257+
raise ValueError(
258+
f"Unknown server public key fingerprint: {fingerprint:#018x}. "
259+
f"Known fingerprints: {', '.join(f'{fp:#018x}' for fp in server_public_keys)}"
260+
)
255261
return pow(
256262
int.from_bytes(data, "big"),
257-
server_public_keys[fingerprint].e,
258-
server_public_keys[fingerprint].m
263+
key.e,
264+
key.m
259265
).to_bytes(256, "big")

0 commit comments

Comments
 (0)