diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 00000000..4560a56a --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +telepy \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 00000000..3071daf2 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 00000000..86e90da9 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/scopes/scope_settings.xml b/.idea/scopes/scope_settings.xml new file mode 100644 index 00000000..922003b8 --- /dev/null +++ b/.idea/scopes/scope_settings.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/telepy.iml b/.idea/telepy.iml new file mode 100644 index 00000000..d0876a78 --- /dev/null +++ b/.idea/telepy.iml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 00000000..94a25f7f --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/TL_schema b/TL_schema new file mode 100644 index 00000000..ac785680 --- /dev/null +++ b/TL_schema @@ -0,0 +1,76 @@ +int ? = Int; +long ? = Long; +double ? = Double; +string ? = String; + +vector {t:Type} # [ t ] = Vector t; + +int128 4*[ int ] = Int128; +int256 8*[ int ] = Int256; + +resPQ#05162463 nonce:int128 server_nonce:int128 pq:bytes server_public_key_fingerprints:Vector = ResPQ; + +p_q_inner_data#83c95aec pq:bytes p:bytes q:bytes nonce:int128 server_nonce:int128 new_nonce:int256 = P_Q_inner_data; + + +server_DH_params_fail#79cb045d nonce:int128 server_nonce:int128 new_nonce_hash:int128 = Server_DH_Params; +server_DH_params_ok#d0e8075c nonce:int128 server_nonce:int128 encrypted_answer:bytes = Server_DH_Params; + +server_DH_inner_data#b5890dba nonce:int128 server_nonce:int128 g:int dh_prime:bytes g_a:bytes server_time:int = Server_DH_inner_data; + +client_DH_inner_data#6643b654 nonce:int128 server_nonce:int128 retry_id:long g_b:bytes = Client_DH_Inner_Data; + +dh_gen_ok#3bcbf734 nonce:int128 server_nonce:int128 new_nonce_hash1:int128 = Set_client_DH_params_answer; +dh_gen_retry#46dc1fb9 nonce:int128 server_nonce:int128 new_nonce_hash2:int128 = Set_client_DH_params_answer; +dh_gen_fail#a69dae02 nonce:int128 server_nonce:int128 new_nonce_hash3:int128 = Set_client_DH_params_answer; + +rpc_result#f35c6d01 req_msg_id:long result:Object = RpcResult; +rpc_error#2144ca19 error_code:int error_message:string = RpcError; + +rpc_answer_unknown#5e2ad36e = RpcDropAnswer; +rpc_answer_dropped_running#cd78e586 = RpcDropAnswer; +rpc_answer_dropped#a43ad8b7 msg_id:long seq_no:int bytes:int = RpcDropAnswer; + +future_salt#0949d9dc valid_since:int valid_until:int salt:long = FutureSalt; +future_salts#ae500895 req_msg_id:long now:int salts:vector = FutureSalts; + +pong#347773c5 msg_id:long ping_id:long = Pong; + +destroy_session_ok#e22045fc session_id:long = DestroySessionRes; +destroy_session_none#62d350c9 session_id:long = DestroySessionRes; + +new_session_created#9ec20908 first_msg_id:long unique_id:long server_salt:long = NewSession; + +msg_container#73f1f8dc messages:vector<%Message> = MessageContainer; +message msg_id:long seqno:int bytes:int body:Object = Message; +msg_copy#e06046b2 orig_message:Message = MessageCopy; + +gzip_packed#3072cfa1 packed_data:bytes = Object; + +msgs_ack#62d6b459 msg_ids:Vector = MsgsAck; + +bad_msg_notification#a7eff811 bad_msg_id:long bad_msg_seqno:int error_code:int = BadMsgNotification; +bad_server_salt#edab447b bad_msg_id:long bad_msg_seqno:int error_code:int new_server_salt:long = BadMsgNotification; + +msg_resend_req#7d861a08 msg_ids:Vector = MsgResendReq; +msgs_state_req#da69fb52 msg_ids:Vector = MsgsStateReq; +msgs_state_info#04deb57d req_msg_id:long info:bytes = MsgsStateInfo; +msgs_all_info#8cc0d131 msg_ids:Vector info:bytes = MsgsAllInfo; +msg_detailed_info#276d3ec6 msg_id:long answer_msg_id:long bytes:int status:int = MsgDetailedInfo; +msg_new_detailed_info#809db6df answer_msg_id:long bytes:int status:int = MsgDetailedInfo; + +---functions--- + +req_pq#60469778 nonce:int128 = ResPQ; + +req_DH_params#d712e4be nonce:int128 server_nonce:int128 p:bytes q:bytes public_key_fingerprint:long encrypted_data:bytes = Server_DH_Params; + +set_client_DH_params#f5045f1f nonce:int128 server_nonce:int128 encrypted_data:bytes = Set_client_DH_params_answer; + +rpc_drop_answer#58e4a740 req_msg_id:long = RpcDropAnswer; +get_future_salts#b921bd04 num:int = FutureSalts; +ping#7abe77ec ping_id:long = Pong; +ping_delay_disconnect#f3427b8c ping_id:long disconnect_delay:int = Pong; +destroy_session#e7512126 session_id:long = DestroySessionRes; + +http_wait#9299359f max_delay:int wait_after:int max_wait:int = HttpWait; \ No newline at end of file diff --git a/mtproto.py b/mtproto.py new file mode 100644 index 00000000..69d825cc --- /dev/null +++ b/mtproto.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- +""" +Created on Tue Sep 2 19:26:15 2014 + +@author: agrigoryev +""" +import binascii +import struct + +def sendpacket(socket, data, number): + step1 = (len(data)+12).to_bytes(4,'little') + number.to_bytes(4,'little') + data + step2 = step1 + binascii.crc32(step1).to_bytes(4,'little') + socket.send(step2) + +def recvpacket(socket): + packet_length_data = socket.recv(4) + if len(packet_length_data)>0: + packet_length = struct.unpack("=6, Returns a list of primes, 2 <= p < N """ + correction = N % 6 > 1 + N = {0:N, 1:N-1, 2:N+4, 3:N+3, 4:N+2, 5:N+1}[N%6] + sieve = [True] * (N // 3) + sieve[0] = False + for i in range(int(N ** .5) // 3 + 1): + if sieve[i]: + k = (3 * i + 1) | 1 + sieve[k*k // 3::2*k] = [False] * ((N//6 - (k*k)//6 - 1)//k + 1) + sieve[(k*k + 4*k - 2*k*(i%2)) // 3::2*k] = [False] * ((N // 6 - (k*k + 4*k - 2*k*(i%2))//6 - 1) // k + 1) + return [2, 3] + [(3 * i + 1) | 1 for i in range(1, N//3 - correction) if sieve[i]] + +smallprimeset = set(primesbelow(100000)) +_smallprimeset = 100000 +def isprime(n, precision=7): + # http://en.wikipedia.org/wiki/Miller-Rabin_primality_test#Algorithm_and_running_time + if n == 1 or n % 2 == 0: + return False + elif n < 1: + raise ValueError("Out of bounds, first argument must be > 0") + elif n < _smallprimeset: + return n in smallprimeset + + + d = n - 1 + s = 0 + while d % 2 == 0: + d //= 2 + s += 1 + + for repeat in range(precision): + a = random.randrange(2, n - 2) + x = pow(a, d, n) + + if x == 1 or x == n - 1: continue + + for r in range(s - 1): + x = pow(x, 2, n) + if x == 1: return False + if x == n - 1: break + else: return False + + return True + +# https://comeoncodeon.wordpress.com/2010/09/18/pollard-rho-brent-integer-factorization/ +def pollard_brent(n): + if n % 2 == 0: return 2 + if n % 3 == 0: return 3 + + y, c, m = random.randint(1, n-1), random.randint(1, n-1), random.randint(1, n-1) + g, r, q = 1, 1, 1 + while g == 1: + x = y + for i in range(r): + y = (pow(y, 2, n) + c) % n + + k = 0 + while k < r and g==1: + ys = y + for i in range(min(m, r-k)): + y = (pow(y, 2, n) + c) % n + q = q * abs(x-y) % n + g = gcd(q, n) + k += m + r *= 2 + if g == n: + while True: + ys = (pow(ys, 2, n) + c) % n + g = gcd(abs(x - ys), n) + if g > 1: + break + + return g + +smallprimes = primesbelow(10000) # might seem low, but 1000*1000 = 1000000, so this will fully factor every composite < 1000000 +def primefactors(n, sort=False): + factors = [] + + limit = int(n ** .5) + 1 + for checker in smallprimes: + if checker > limit: break + while n % checker == 0: + factors.append(checker) + n //= checker + limit = int(n ** .5) + 1 + if checker > limit: break + + if n < 2: return factors + + while n > 1: + if isprime(n): + factors.append(n) + break + factor = pollard_brent(n) # trial division did not fully factor, switch to pollard-brent + factors.extend(primefactors(factor)) # recurse to factor the not necessarily prime factor returned by pollard-brent + n //= factor + + if sort: factors.sort() + + return factors + +def factorization(n): + factors = {} + for p1 in primefactors(n): + try: + factors[p1] += 1 + except KeyError: + factors[p1] = 1 + return factors + +totients = {} +def totient(n): + if n == 0: return 1 + + try: return totients[n] + except KeyError: pass + + tot = 1 + for p, exp in factorization(n).items(): + tot *= (p - 1) * p ** (exp - 1) + + totients[n] = tot + return tot + +def gcd(a, b): + if a == b: return a + while b > 0: a, b = b, a % b + return a + +def lcm(a, b): + return abs(a * b) // gcd(a, b) + \ No newline at end of file