mirror of
https://github.com/LonamiWebs/Telethon.git
synced 2026-09-04 16:10:39 +00:00
First attempt at TelegramClient. Added fixes and doc
This commit is contained in:
0
crypto/__init__.py
Normal file
0
crypto/__init__.py
Normal file
65
crypto/aes.py
Normal file
65
crypto/aes.py
Normal file
@@ -0,0 +1,65 @@
|
||||
# This file is based on TLSharp
|
||||
# https://github.com/sochix/TLSharp/blob/master/TLSharp.Core/MTProto/Crypto/AES.cs
|
||||
import pyaes
|
||||
|
||||
|
||||
class AES:
|
||||
@staticmethod
|
||||
def decrypt_ige(cipher_text, key, iv):
|
||||
"""Decrypts the given text in 16-bytes blocks by using the given key and 32-bytes initialization vector"""
|
||||
iv1 = iv[:len(iv)//2]
|
||||
iv2 = iv[len(iv)//2:]
|
||||
|
||||
aes = pyaes.AES(key)
|
||||
|
||||
plain_text = [0] * len(cipher_text)
|
||||
blocks_count = len(cipher_text) // 16
|
||||
|
||||
cipher_text_block = [0] * 16
|
||||
for block_index in range(blocks_count):
|
||||
for i in range(16):
|
||||
cipher_text_block[i] = cipher_text[block_index * 16 + i] ^ iv2[i]
|
||||
|
||||
plain_text_block = aes.decrypt(cipher_text_block)
|
||||
|
||||
for i in range(16):
|
||||
plain_text_block[i] ^= iv1[i]
|
||||
|
||||
iv1 = cipher_text[block_index * 16:block_index * 16 + 16]
|
||||
iv2 = plain_text_block[0:16]
|
||||
|
||||
plain_text[block_index * 16:block_index * 16 + 16] = plain_text_block[:16]
|
||||
|
||||
return bytes(plain_text)
|
||||
|
||||
@staticmethod
|
||||
def encrypt_ige(plain_text, key, iv):
|
||||
"""Encrypts the given text in 16-bytes blocks by using the given key and 32-bytes initialization vector"""
|
||||
# TODO: Random padding
|
||||
padding = bytes(16 - len(plain_text) % 16)
|
||||
plain_text += padding
|
||||
|
||||
iv1 = iv[:len(iv)//2]
|
||||
iv2 = iv[len(iv)//2:]
|
||||
|
||||
aes = pyaes.AES(key)
|
||||
|
||||
blocks_count = len(plain_text) // 16
|
||||
cipher_text = [0] * len(plain_text)
|
||||
|
||||
for block_index in range(blocks_count):
|
||||
plain_text_block = list(plain_text[block_index * 16:block_index * 16 + 16])
|
||||
for i in range(16):
|
||||
plain_text_block[i] ^= iv1[i]
|
||||
|
||||
cipher_text_block = aes.encrypt(plain_text_block)
|
||||
|
||||
for i in range(16):
|
||||
cipher_text_block[i] ^= iv2[i]
|
||||
|
||||
iv1 = cipher_text_block[0:16]
|
||||
iv2 = plain_text[block_index * 16:block_index * 16 + 16]
|
||||
|
||||
cipher_text[block_index * 16:block_index * 16 + 16] = cipher_text_block[:16]
|
||||
|
||||
return bytes(cipher_text)
|
||||
30
crypto/auth_key.py
Executable file
30
crypto/auth_key.py
Executable file
@@ -0,0 +1,30 @@
|
||||
# This file is based on TLSharp
|
||||
# https://github.com/sochix/TLSharp/blob/master/TLSharp.Core/MTProto/Crypto/AuthKey.cs
|
||||
import utils.helpers as utils
|
||||
from utils.binary_writer import BinaryWriter
|
||||
from utils.binary_reader import BinaryReader
|
||||
|
||||
|
||||
class AuthKey:
|
||||
def __init__(self, gab=None, data=None):
|
||||
if gab:
|
||||
self.key = utils.get_byte_array(gab, signed=False)
|
||||
elif data:
|
||||
self.key = data
|
||||
else:
|
||||
raise AssertionError('Either a gab integer or data bytes array must be provided')
|
||||
|
||||
with BinaryReader(utils.sha1(self.key)) as reader:
|
||||
self.aux_hash = reader.read_long(signed=False)
|
||||
reader.read(4)
|
||||
self.key_id = reader.read_long(signed=False)
|
||||
|
||||
def calc_new_nonce_hash(self, new_nonce, number):
|
||||
"""Calculates the new nonce hash based on the current class fields' values"""
|
||||
with BinaryWriter() as writer:
|
||||
writer.write(new_nonce)
|
||||
writer.write_byte(number)
|
||||
writer.write_long(self.aux_hash, signed=False)
|
||||
|
||||
new_nonce_hash = utils.sha1(writer.get_bytes())[4:20]
|
||||
return new_nonce_hash
|
||||
64
crypto/factorizator.py
Executable file
64
crypto/factorizator.py
Executable file
@@ -0,0 +1,64 @@
|
||||
# This file is based on TLSharp
|
||||
# https://github.com/sochix/TLSharp/blob/master/TLSharp.Core/MTProto/Crypto/Factorizator.cs
|
||||
from random import randint
|
||||
|
||||
|
||||
class Factorizator:
|
||||
@staticmethod
|
||||
def find_small_multiplier_lopatin(what):
|
||||
"""Finds the small multiplier by using Lopatin's method"""
|
||||
g = 0
|
||||
for i in range(3):
|
||||
q = (randint(0, 127) & 15) + 17
|
||||
x = randint(0, 1000000000) + 1
|
||||
y = x
|
||||
lim = 1 << (i + 18)
|
||||
for j in range(1, lim):
|
||||
a, b, c = x, x, q
|
||||
while b != 0:
|
||||
if (b & 1) != 0:
|
||||
c += a
|
||||
if c >= what:
|
||||
c -= what
|
||||
a += a
|
||||
if a >= what:
|
||||
a -= what
|
||||
b >>= 1
|
||||
|
||||
x = c
|
||||
z = y - x if x < y else x - y
|
||||
g = Factorizator.gcd(z, what)
|
||||
if g != 1:
|
||||
break
|
||||
|
||||
if (j & (j - 1)) == 0:
|
||||
y = x
|
||||
|
||||
if g > 1:
|
||||
break
|
||||
|
||||
p = what // g
|
||||
return min(p, g)
|
||||
|
||||
@staticmethod
|
||||
def gcd(a, b):
|
||||
"""Calculates the greatest common divisor"""
|
||||
while a != 0 and b != 0:
|
||||
while b & 1 == 0:
|
||||
b >>= 1
|
||||
|
||||
while a & 1 == 0:
|
||||
a >>= 1
|
||||
|
||||
if a > b:
|
||||
a -= b
|
||||
else:
|
||||
b -= a
|
||||
|
||||
return a if b == 0 else b
|
||||
|
||||
@staticmethod
|
||||
def factorize(pq):
|
||||
"""Factorizes the given number and returns both the divisor and the number divided by the divisor"""
|
||||
divisor = Factorizator.find_small_multiplier_lopatin(pq)
|
||||
return divisor, pq // divisor
|
||||
62
crypto/rsa.py
Executable file
62
crypto/rsa.py
Executable file
@@ -0,0 +1,62 @@
|
||||
# This file is based on TLSharp
|
||||
# https://github.com/sochix/TLSharp/blob/master/TLSharp.Core/MTProto/Crypto/RSA.cs
|
||||
from utils.binary_writer import BinaryWriter
|
||||
import utils.helpers as utils
|
||||
|
||||
|
||||
class RSAServerKey:
|
||||
def __init__(self, fingerprint, m, e):
|
||||
self.fingerprint = fingerprint
|
||||
self.m = m
|
||||
self.e = e
|
||||
|
||||
def encrypt(self, data, offset=None, length=None):
|
||||
"""Encrypts the given data with the current key"""
|
||||
if offset is None:
|
||||
offset = 0
|
||||
if length is None:
|
||||
length = len(data)
|
||||
|
||||
with BinaryWriter() as writer:
|
||||
# Write SHA
|
||||
writer.write(utils.sha1(data[offset:offset+length]))
|
||||
# Write data
|
||||
writer.write(data[offset:offset+length])
|
||||
# Add padding if required
|
||||
if length < 235:
|
||||
writer.write(utils.generate_random_bytes(235 - length))
|
||||
|
||||
cipher_text = utils.get_byte_array(
|
||||
pow(int.from_bytes(writer.get_bytes(), byteorder='big'), self.e, self.m),
|
||||
signed=False)
|
||||
|
||||
if len(cipher_text) == 256:
|
||||
return cipher_text
|
||||
|
||||
else:
|
||||
padding = bytes(256 - len(cipher_text))
|
||||
return padding + cipher_text
|
||||
|
||||
|
||||
class RSA:
|
||||
_server_keys = {
|
||||
'216be86c022bb4c3':
|
||||
RSAServerKey('216be86c022bb4c3', int('C150023E2F70DB7985DED064759CFECF0AF328E69A41DAF4D6F01B538135A6F9'
|
||||
'1F8F8B2A0EC9BA9720CE352EFCF6C5680FFC424BD634864902DE0B4BD6D49F4E'
|
||||
'580230E3AE97D95C8B19442B3C0A10D8F5633FECEDD6926A7F6DAB0DDB7D457F'
|
||||
'9EA81B8465FCD6FFFEED114011DF91C059CAEDAF97625F6C96ECC74725556934'
|
||||
'EF781D866B34F011FCE4D835A090196E9A5F0E4449AF7EB697DDB9076494CA5F'
|
||||
'81104A305B6DD27665722C46B60E5DF680FB16B210607EF217652E60236C255F'
|
||||
'6A28315F4083A96791D7214BF64C1DF4FD0DB1944FB26A2A57031B32EEE64AD1'
|
||||
'5A8BA68885CDE74A5BFC920F6ABF59BA5C75506373E7130F9042DA922179251F',
|
||||
16), int('010001', 16))
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def encrypt(fingerprint, data, offset=None, length=None):
|
||||
"""Encrypts the given data given a fingerprint"""
|
||||
if fingerprint.lower() not in RSA._server_keys:
|
||||
return None
|
||||
|
||||
key = RSA._server_keys[fingerprint.lower()]
|
||||
return key.encrypt(data, offset, length)
|
||||
Reference in New Issue
Block a user