Merge pull request #4 from griganton/python27_compatible
Adapted the current testing.py to work also with python2.7
This commit is contained in:
commit
181bb275c6
49
mtproto.py
49
mtproto.py
@ -3,20 +3,26 @@
|
|||||||
Created on Tue Sep 2 19:26:15 2014
|
Created on Tue Sep 2 19:26:15 2014
|
||||||
|
|
||||||
@author: agrigoryev
|
@author: agrigoryev
|
||||||
|
@author: Sammy Pfeiffer
|
||||||
"""
|
"""
|
||||||
from binascii import crc32
|
from binascii import crc32 as originalcrc32
|
||||||
|
def crc32(data):
|
||||||
|
return originalcrc32(data) & 0xffffffff
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
from time import time
|
||||||
import io
|
import io
|
||||||
import json
|
import json
|
||||||
import socket
|
import socket
|
||||||
import struct
|
import struct
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def vis(bs):
|
def vis(bs):
|
||||||
"""
|
"""
|
||||||
Function to visualize byte streams. Split into bytes, print to console.
|
Function to visualize byte streams. Split into bytes, print to console.
|
||||||
:param bs: BYTE STRING
|
:param bs: BYTE STRING
|
||||||
"""
|
"""
|
||||||
|
bs = bytearray(bs)
|
||||||
symbols_in_one_line = 8
|
symbols_in_one_line = 8
|
||||||
n = len(bs) // symbols_in_one_line
|
n = len(bs) // symbols_in_one_line
|
||||||
for i in range(n):
|
for i in range(n):
|
||||||
@ -108,12 +114,14 @@ def serialize_param(bytes_io, type_, value):
|
|||||||
elif type_ == 'string' or 'bytes':
|
elif type_ == 'string' or 'bytes':
|
||||||
l = len(value)
|
l = len(value)
|
||||||
if l < 254: # short string format
|
if l < 254: # short string format
|
||||||
bytes_io.write(int.to_bytes(l, 1, 'little')) # 1 byte of string
|
bytes_io.write(struct.pack('<b', l)) # 1 byte of string
|
||||||
|
#bytes_io.write(int.to_bytes(l, 1, 'little')) # 1 byte of string
|
||||||
bytes_io.write(value) # string
|
bytes_io.write(value) # string
|
||||||
bytes_io.write(b'\x00'*((-l-1) % 4)) # padding bytes
|
bytes_io.write(b'\x00'*((-l-1) % 4)) # padding bytes
|
||||||
else:
|
else:
|
||||||
bytes_io.write(b'\xfe') # byte 254
|
bytes_io.write(b'\xfe') # byte 254
|
||||||
bytes_io.write(int.to_bytes(l, 3, 'little')) # 3 bytes of string
|
bytes_io.write(struct.pack('<i', l)) # 3 bytes of string
|
||||||
|
#bytes_io.write(int.to_bytes(l, 3, 'little')) # 3 bytes of string
|
||||||
bytes_io.write(value) # string
|
bytes_io.write(value) # string
|
||||||
bytes_io.write(b'\x00'*(-l % 4)) # padding bytes
|
bytes_io.write(b'\x00'*(-l % 4)) # padding bytes
|
||||||
|
|
||||||
@ -131,11 +139,11 @@ def deserialize(bytes_io, type_=None, subtype=None):
|
|||||||
elif type_ == 'int128': x = bytes_io.read(16)
|
elif type_ == 'int128': x = bytes_io.read(16)
|
||||||
elif type_ == 'int256': x = bytes_io.read(32)
|
elif type_ == 'int256': x = bytes_io.read(32)
|
||||||
elif type_ == 'string' or type_ == 'bytes':
|
elif type_ == 'string' or type_ == 'bytes':
|
||||||
l = int.from_bytes(bytes_io.read(1), 'little')
|
l = struct.unpack('<b', bytes_io.read(1))[0]
|
||||||
assert l <= 254
|
assert l <= 254
|
||||||
if l == 254:
|
if l == 254:
|
||||||
# We have a long string
|
# We have a long string
|
||||||
long_len = int.from_bytes(bytes_io.read(3), 'little')
|
long_len = struct.unpack('<l', bytes_io.read(3))[0]
|
||||||
x = bytes_io.read(long_len)
|
x = bytes_io.read(long_len)
|
||||||
bytes_io.read(-long_len % 4) # skip padding bytes
|
bytes_io.read(-long_len % 4) # skip padding bytes
|
||||||
else:
|
else:
|
||||||
@ -145,7 +153,8 @@ def deserialize(bytes_io, type_=None, subtype=None):
|
|||||||
assert isinstance(x, bytes)
|
assert isinstance(x, bytes)
|
||||||
elif type_ == 'vector':
|
elif type_ == 'vector':
|
||||||
assert subtype is not None
|
assert subtype is not None
|
||||||
count = int.from_bytes(bytes_io.read(4), 'little')
|
count = struct.unpack('<l', bytes_io.read(4))[0]
|
||||||
|
print("count is: " + str(count))
|
||||||
x = [deserialize(bytes_io, type_=subtype) for i in range(count)]
|
x = [deserialize(bytes_io, type_=subtype) for i in range(count)]
|
||||||
else:
|
else:
|
||||||
# Boxed types
|
# Boxed types
|
||||||
@ -185,7 +194,11 @@ class Session:
|
|||||||
# Basic instructions: https://core.telegram.org/mtproto/description#unencrypted-message
|
# Basic instructions: https://core.telegram.org/mtproto/description#unencrypted-message
|
||||||
|
|
||||||
# Message id: https://core.telegram.org/mtproto/description#message-identifier-msg-id
|
# Message id: https://core.telegram.org/mtproto/description#message-identifier-msg-id
|
||||||
msg_id = int(datetime.utcnow().timestamp()*2**30)*4
|
# http://stackoverflow.com/questions/8777753/converting-datetime-date-to-utc-timestamp-in-python
|
||||||
|
# to make it work in py2 and py3 (py3 has the timestamp() method but py2 doesnt)
|
||||||
|
curr_timestamp = (datetime.utcfromtimestamp(time()) - datetime(1970, 1, 1)).total_seconds()
|
||||||
|
msg_id = int(curr_timestamp*2**30)*4
|
||||||
|
#msg_id = int(datetime.utcnow().timestamp()*2**30)*4
|
||||||
|
|
||||||
return (b'\x00\x00\x00\x00\x00\x00\x00\x00' +
|
return (b'\x00\x00\x00\x00\x00\x00\x00\x00' +
|
||||||
struct.pack('<Q', msg_id) +
|
struct.pack('<Q', msg_id) +
|
||||||
@ -226,17 +239,35 @@ class Session:
|
|||||||
(self.number, auth_key_id, message_id, message_length)= struct.unpack("<L8s8sI", packet[0:24])
|
(self.number, auth_key_id, message_id, message_length)= struct.unpack("<L8s8sI", packet[0:24])
|
||||||
data = packet[24:24+message_length]
|
data = packet[24:24+message_length]
|
||||||
crc = packet[-4:]
|
crc = packet[-4:]
|
||||||
|
# print("crc is: " + str(crc))
|
||||||
|
# print("type of crc: " + str(type(crc)))
|
||||||
|
# print("crc.__repr__(): " + crc.__repr__())
|
||||||
|
# print("struct.unpack('<L', crc): (next line)")
|
||||||
|
# print(struct.unpack('<L', crc))
|
||||||
|
# print("crc32(packet_length_data + packet[0:-4]): " + str(crc32(packet_length_data + packet[0:-4])))
|
||||||
|
# print("crc32(packet_length_data + packet[0:-4]).__repr__(): " + crc32(packet_length_data + packet[0:-4]).__repr__())
|
||||||
|
|
||||||
# Checking the CRC32 correctness of received data
|
# Checking the CRC32 correctness of received data
|
||||||
if crc32(packet_length_data + packet[0:-4]).to_bytes(4, 'little') == crc:
|
if crc32(packet_length_data + packet[0:-4]) == struct.unpack('<L', crc)[0]:
|
||||||
print('<<')
|
print('<<')
|
||||||
vis(data) # Received message visualisation to console
|
vis(data) # Received message visualisation to console
|
||||||
return data
|
return data
|
||||||
|
else:
|
||||||
|
print("CRC32 was not correct!")
|
||||||
|
else:
|
||||||
|
print("Nothing in the socket!")
|
||||||
|
|
||||||
def method_call(self, method, **kwargs):
|
def method_call(self, method, **kwargs):
|
||||||
z=io.BytesIO()
|
z=io.BytesIO()
|
||||||
serialize_method(z, method, **kwargs)
|
serialize_method(z, method, **kwargs)
|
||||||
self.send_message(z.getvalue())
|
# z.getvalue() on py2.7 returns str, which means bytes
|
||||||
|
# on py3.4 returns bytes
|
||||||
|
# bytearray is closer to the same data type to be shared
|
||||||
|
z_val = bytearray(z.getvalue())
|
||||||
|
# print("z_val: " + z_val.__repr__())
|
||||||
|
# print("z_val type: " + str(type(z_val)))
|
||||||
|
# print("len of z_val: " + str(len(z_val)))
|
||||||
|
self.send_message(z_val)
|
||||||
server_answer = self.recv_message()
|
server_answer = self.recv_message()
|
||||||
if server_answer is not None:
|
if server_answer is not None:
|
||||||
return deserialize(io.BytesIO(server_answer))
|
return deserialize(io.BytesIO(server_answer))
|
||||||
|
32
testing.py
32
testing.py
@ -1,15 +1,24 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
import mtproto
|
import mtproto
|
||||||
import os, io
|
import os
|
||||||
|
import io
|
||||||
import prime
|
import prime
|
||||||
import configparser
|
import struct
|
||||||
|
# Deal with py2 and py3 differences
|
||||||
|
try:
|
||||||
|
import configparser
|
||||||
|
except ImportError:
|
||||||
|
import ConfigParser as configparser
|
||||||
from Crypto.Hash import SHA
|
from Crypto.Hash import SHA
|
||||||
from Crypto.PublicKey import RSA
|
from Crypto.PublicKey import RSA
|
||||||
|
|
||||||
config = configparser.ConfigParser()
|
config = configparser.ConfigParser()
|
||||||
config.read('credentials')
|
# Check if credentials is correctly loaded (when it doesn't read anything it returns [])
|
||||||
ip = config['App data']['ip_address']
|
if not config.read('credentials'):
|
||||||
port = config['App data'].getint('port')
|
print("File 'credentials' seems to not exist.")
|
||||||
|
exit(-1)
|
||||||
|
ip = config.get('App data', 'ip_address')
|
||||||
|
port = config.getint('App data', 'port')
|
||||||
|
|
||||||
Session = mtproto.Session(ip, port)
|
Session = mtproto.Session(ip, port)
|
||||||
client_nonce = os.urandom(16)
|
client_nonce = os.urandom(16)
|
||||||
@ -19,16 +28,21 @@ server_nonce = x['server_nonce']
|
|||||||
public_key_fingerprint = x['server_public_key_fingerprints'][0]
|
public_key_fingerprint = x['server_public_key_fingerprints'][0]
|
||||||
PQ_bytes = x['pq']
|
PQ_bytes = x['pq']
|
||||||
|
|
||||||
PQ = int.from_bytes(PQ_bytes, 'big')
|
# doing len(PQ_bytes) I saw it was 8 bytes, so we unpack with Q
|
||||||
|
# as in the docs: https://docs.python.org/2/library/struct.html
|
||||||
|
PQ = struct.unpack('>q', PQ_bytes)[0]
|
||||||
[p, q] = prime.primefactors(PQ)
|
[p, q] = prime.primefactors(PQ)
|
||||||
if p > q: (p, q) = (q, p)
|
if p > q: (p, q) = (q, p)
|
||||||
assert p*q == PQ and p < q
|
assert p*q == PQ and p < q
|
||||||
|
|
||||||
print("PQ = %d\np = %d, q = %d" % (PQ, p, q))
|
print("PQ = %d\np = %d, q = %d" % (PQ, p, q))
|
||||||
|
|
||||||
|
P_bytes = struct.pack('>i', p)
|
||||||
P_bytes = int.to_bytes(p, p.bit_length()//8+1, 'big')
|
Q_bytes = struct.pack('>i', q)
|
||||||
Q_bytes = int.to_bytes(q, q.bit_length()//8+1, 'big')
|
# print("p.bit_length()//8+1: " + str(p.bit_length()//8+1)) # 4
|
||||||
|
# print("q.bit_length()//8+1: " + str(q.bit_length()//8+1)) # 4
|
||||||
|
# P_bytes = int.to_bytes(p, p.bit_length()//8+1, 'big')
|
||||||
|
# Q_bytes = int.to_bytes(q, q.bit_length()//8+1, 'big')
|
||||||
|
|
||||||
f = open('rsa.pub', 'r')
|
f = open('rsa.pub', 'r')
|
||||||
key = RSA.importKey(f.read())
|
key = RSA.importKey(f.read())
|
||||||
|
Loading…
Reference in New Issue
Block a user