Merge pull request #4 from griganton/python27_compatible

Adapted the current testing.py to work also with python2.7
This commit is contained in:
Anton Grigoryev 2015-03-13 11:09:29 +03:00
commit 181bb275c6
2 changed files with 64 additions and 19 deletions

View File

@ -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))

View File

@ -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())