Skip to content

Commit d06d7c9

Browse files
committed
Stable async proxy
1 parent 8e33497 commit d06d7c9

13 files changed

Lines changed: 176 additions & 178 deletions

File tree

AESEncryptor.py

Lines changed: 0 additions & 18 deletions
This file was deleted.

Core.py

Lines changed: 0 additions & 77 deletions
This file was deleted.

MTProtoPacket.py

Lines changed: 0 additions & 75 deletions
This file was deleted.

config.py

Lines changed: 0 additions & 8 deletions
This file was deleted.

pymtproxy/config.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
telegram_ips = [ "149.154.175.50", "149.154.167.51", "149.154.175.100", "149.154.167.91", "149.154.171.5"]
2+
mtproto_footprint = b'\xef\xef\xef\xef'
3+
obf_footprint = b'\xdd\xdd\xdd\xdd'
4+
secret = '1234567890abc1234567890abcef1234'
5+

pymtproxy/dispatcher.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
from encryption.crypto import Encryptor, Decryptor
2+
from config import secret, telegram_ips, mtproto_footprint, obf_footprint
3+
from exceptions import WrongServerID
4+
from protocols.telegram import TelegramProtocol
5+
6+
7+
class Dispatcher:
8+
def __init__(self, loop, real_protocol):
9+
self.loop = loop
10+
self.real_protocol = real_protocol
11+
self.telegram_protocol = None
12+
self.telegram_transport = None
13+
self.encryptor = None
14+
self.decryptor = None
15+
16+
async def handle(self, raw_data: bytes):
17+
if not self.encryptor or not self.decryptor:
18+
self.decryptor = Decryptor(raw_data, secret)
19+
self.encryptor = Encryptor(raw_data, secret)
20+
self.decoded_data = await self.decryptor(raw_data)
21+
server_id = int.from_bytes(self.decoded_data[60:62], 'little') - 1
22+
if server_id < 0 or server_id > len(telegram_ips):
23+
raise WrongServerID(f'Got id {server_id}')
24+
self.telegram_server_ip = telegram_ips[server_id]
25+
assert self.decoded_data[56:60] == mtproto_footprint or self.decoded_data[56:60] == obf_footprint, self.decoded_data[56:60]
26+
if not self.telegram_protocol or not self.telegram_transport:
27+
self.telegram_transport, self.telegram_protocol = await self.loop.create_connection(lambda: TelegramProtocol(self.loop, self),
28+
self.telegram_server_ip, 443)
29+
self.telegram_transport.write(self.decoded_data)
30+
return
31+
self.telegram_transport.write(await self.decryptor(raw_data))
32+
33+
async def reverse_handle(self, raw_data):
34+
self.real_protocol.transport.write(await self.encryptor(raw_data))

pymtproxy/encryption/aes.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import pyaes
2+
3+
class AES_CTR:
4+
def __init__(self, key, iv):
5+
assert isinstance(key, bytes), 'Key should be instance of bytes'
6+
self._aes = pyaes.AESModeOfOperationCTR(key)
7+
assert isinstance(iv, bytes), 'IV should be instance of bytes'
8+
assert len(iv) == 16, 'IV length must be 16 bytes'
9+
self._aes._counter._counter = list(iv)
10+
11+
async def encrypt(self, data):
12+
return self._aes.encrypt(data)
13+
14+
async def decrypt(self, data):
15+
return self._aes.decrypt(data)

pymtproxy/encryption/crypto.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
from hashlib import sha256
2+
3+
from .aes import AES_CTR
4+
5+
6+
class DecryptionKey:
7+
def __init__(self, key, secret):
8+
dec_key = sha256()
9+
dec_key.update(key)
10+
dec_key.update(secret)
11+
self.key = dec_key.digest()
12+
13+
def __call__(self):
14+
return self.key
15+
16+
17+
class EncryptionKey:
18+
def __init__(self, key, secret):
19+
enc_key = sha256()
20+
enc_key.update(key)
21+
enc_key.update(secret)
22+
self.key = enc_key.digest()
23+
24+
def __call__(self):
25+
return self.key
26+
27+
28+
class Decryptor:
29+
def __init__(self, raw_bytes, secret):
30+
self.secret = bytes.fromhex(secret)
31+
self.decryption_key = DecryptionKey(raw_bytes[8:40], self.secret)
32+
self.aes = AES_CTR(self.decryption_key(), raw_bytes[40:56])
33+
34+
async def __call__(self, data):
35+
return await self.aes.decrypt(data)
36+
37+
38+
class Encryptor:
39+
def __init__(self, raw_bytes, secret):
40+
self.secret = bytes.fromhex(secret)
41+
self.encryption_key = EncryptionKey(raw_bytes[8:56][::-1][0:32], self.secret)
42+
self.aes = AES_CTR(self.encryption_key(), raw_bytes[8:56][::-1][32:48])
43+
44+
async def __call__(self, data):
45+
return await self.aes.encrypt(data)

pymtproxy/exceptions.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
2+
3+
class ProxyBaseException(Exception):
4+
pass
5+
6+
7+
class WrongServerID(ProxyBaseException):
8+
pass

pymtproxy/protocols/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
from .real import RealProtocol
2+
from .telegram import TelegramProtocol

0 commit comments

Comments
 (0)