Start of refactoring

A lot of work to be done
This commit is contained in:
Anton Grigoryev 2015-03-17 02:02:01 +03:00
parent 0d79c88636
commit 94ed33bb15
3 changed files with 309 additions and 303 deletions

145
TL.py Normal file
View File

@ -0,0 +1,145 @@
__author__ = 'agrigoryev'
import os
import struct
import json
import io
import numbers
class TlConstructor:
def __init__(self, json_dict):
self.id = int(json_dict['id'])
self.type = json_dict['type']
self.predicate = json_dict['predicate']
self.params = []
# case of vector
for param in json_dict['params']:
if param['type'] == "Vector<long>":
param['type'] = "Vector t"
param['subtype'] = "long"
else:
param['subtype'] = None
self.params.append(param)
class TlMethod:
def __init__(self, json_dict):
self.id = int(json_dict['id'])
self.type = json_dict['type']
self.method = json_dict['method']
self.params = json_dict['params']
class TL:
def __init__(self, filename):
with open(filename, 'r') as f:
TL_dict = json.load(f)
# Read constructors
self.constructors = TL_dict['constructors']
self.constructor_id = {}
self.constructor_type = {}
for elem in self.constructors:
z = TlConstructor(elem)
self.constructor_id[z.id] = z
self.constructor_type[z.predicate] = z
self.methods = TL_dict['methods']
self.method_id = {}
self.method_name = {}
for elem in self.methods:
z = TlMethod(elem)
self.method_id[z.id] = z
self.method_name[z.method] = z
## Loading TL_schema (should be placed in the same directory as mtproto.py
tl = TL(os.path.join(os.path.dirname(__file__), "TL_schema.JSON"))
def serialize_obj(bytes_io, type_, **kwargs):
try:
tl_constructor = tl.constructor_type[type_]
except KeyError:
raise Exception("Could not extract type: %s" % type_)
bytes_io.write(struct.pack('<i', tl_constructor.id))
for arg in tl_constructor.params:
serialize_param(bytes_io, type_=arg['type'], value=kwargs[arg['name']])
def serialize_method(bytes_io, type_, **kwargs):
try:
tl_method = tl.method_name[type_]
except KeyError:
raise Exception("Could not extract type: %s" % type_)
bytes_io.write(struct.pack('<i', tl_method.id))
for arg in tl_method.params:
serialize_param(bytes_io, type_=arg['type'], value=kwargs[arg['name']])
def serialize_param(bytes_io, type_, value):
if type_ == "int":
assert isinstance(value, int)
bytes_io.write(struct.pack('<i', value))
elif type_ == "long":
assert isinstance(value, numbers.Real)
bytes_io.write(struct.pack('<q', value))
elif type_ in ["int128", "int256"]:
assert isinstance(value, bytes)
bytes_io.write(value)
elif type_ == 'string' or 'bytes':
l = len(value)
if l < 254: # short string format
bytes_io.write(struct.pack('<b', l)) # 1 byte of string
bytes_io.write(value) # string
bytes_io.write(b'\x00'*((-l-1) % 4)) # padding bytes
else:
bytes_io.write(b'\xfe') # byte 254
bytes_io.write(struct.pack('<i', l)[:3]) # 3 bytes of string
bytes_io.write(value) # string
bytes_io.write(b'\x00'*(-l % 4)) # padding bytes
def deserialize(bytes_io, type_=None, subtype=None):
"""
:type bytes_io: io.BytesIO object
"""
assert isinstance(bytes_io, io.BytesIO)
# Built-in bare types
if type_ == 'int': x = struct.unpack('<i', bytes_io.read(4))[0]
elif type_ == '#': x = struct.unpack('<I', bytes_io.read(4))[0]
elif type_ == 'long': x = struct.unpack('<q', bytes_io.read(8))[0]
elif type_ == 'double': x = struct.unpack('<d', bytes_io.read(8))[0]
elif type_ == 'int128': x = bytes_io.read(16)
elif type_ == 'int256': x = bytes_io.read(32)
elif type_ == 'string' or type_ == 'bytes':
l = struct.unpack('<B', bytes_io.read(1))[0]
assert l <= 254 # In general, 0xFF byte is not allowed here
if l == 254:
# We have a long string
long_len = struct.unpack('<I', bytes_io.read(3)+b'\x00')[0]
x = bytes_io.read(long_len)
bytes_io.read(-long_len % 4) # skip padding bytes
else:
# We have a short string
x = bytes_io.read(l)
bytes_io.read(-(l+1) % 4) # skip padding bytes
assert isinstance(x, bytes)
elif type_ == 'vector':
assert subtype is not None
count = struct.unpack('<l', bytes_io.read(4))[0]
x = [deserialize(bytes_io, type_=subtype) for i in range(count)]
else:
# Boxed types
i = struct.unpack('<i', bytes_io.read(4))[0] # read type ID
try:
tl_elem = tl.constructor_id[i]
except KeyError:
raise Exception("Could not extract type: %s" % type_)
base_boxed_types = ["Vector t", "Int", "Long", "Double", "String", "Int128", "Int256"]
if tl_elem.type in base_boxed_types:
x = deserialize(bytes_io, type_=tl_elem.predicate, subtype=subtype)
else: # other types
x = {}
for arg in tl_elem.params:
x[arg['name']] = deserialize(bytes_io, type_=arg['type'], subtype=arg['subtype'])
return x

View File

@ -6,10 +6,7 @@ Created on Tue Sep 2 19:26:15 2014
@author: Sammy Pfeiffer
"""
from binascii import crc32 as originalcrc32
MIN_SUPPORTED_PY3_VERSION = (3, 2, 0)
import numbers
def crc32(data):
return originalcrc32(data) & 0xffffffff
from datetime import datetime
from time import time
import io
@ -18,6 +15,19 @@ import json
import socket
import struct
# pycrypto module
from Crypto.Hash import SHA
from Crypto.PublicKey import RSA
from Crypto.Util.strxor import strxor
# local modules
import crypt
import prime
import TL
def crc32(data):
return originalcrc32(data) & 0xffffffff
def vis(bs):
"""
Function to visualize byte streams. Split into bytes, print to console.
@ -32,156 +42,22 @@ def vis(bs):
print(str((i+1)*symbols_in_one_line)+" | "+" ".join(["%02X" % b for b in bs[(i+1)*symbols_in_one_line:]])+"\n") # for last line
class TlConstructor:
def __init__(self, json_dict):
self.id = int(json_dict['id'])
self.type = json_dict['type']
self.predicate = json_dict['predicate']
self.params = []
# case of vector
for param in json_dict['params']:
if param['type'] == "Vector<long>":
param['type'] = "Vector t"
param['subtype'] = "long"
else:
param['subtype'] = None
self.params.append(param)
class TlMethod:
def __init__(self, json_dict):
self.id = int(json_dict['id'])
self.type = json_dict['type']
self.method = json_dict['method']
self.params = json_dict['params']
class TL:
def __init__(self, filename):
with open(filename, 'r') as f:
TL_dict = json.load(f)
# Read constructors
self.constructors = TL_dict['constructors']
self.constructor_id = {}
self.constructor_type = {}
for elem in self.constructors:
z = TlConstructor(elem)
self.constructor_id[z.id] = z
self.constructor_type[z.predicate] = z
self.methods = TL_dict['methods']
self.method_id = {}
self.method_name = {}
for elem in self.methods:
z = TlMethod(elem)
self.method_id[z.id] = z
self.method_name[z.method] = z
## Loading TL_schema (should be placed in the same directory as mtproto.py
tl = TL(os.path.join(os.path.dirname(__file__), "TL_schema.JSON"))
def serialize_obj(bytes_io, type_, **kwargs):
try:
tl_constructor = tl.constructor_type[type_]
except KeyError:
raise Exception("Could not extract type: %s" % type_)
bytes_io.write(struct.pack('<i', tl_constructor.id))
for arg in tl_constructor.params:
serialize_param(bytes_io, type_=arg['type'], value=kwargs[arg['name']])
def serialize_method(bytes_io, type_, **kwargs):
try:
tl_method = tl.method_name[type_]
except KeyError:
raise Exception("Could not extract type: %s" % type_)
bytes_io.write(struct.pack('<i', tl_method.id))
for arg in tl_method.params:
serialize_param(bytes_io, type_=arg['type'], value=kwargs[arg['name']])
def serialize_param(bytes_io, type_, value):
if type_ == "int":
assert isinstance(value, int)
bytes_io.write(struct.pack('<i', value))
elif type_ == "long":
assert isinstance(value, numbers.Real)
bytes_io.write(struct.pack('<q', value))
elif type_ in ["int128", "int256"]:
assert isinstance(value, bytes)
bytes_io.write(value)
elif type_ == 'string' or 'bytes':
l = len(value)
if l < 254: # short string format
bytes_io.write(struct.pack('<b', l)) # 1 byte of string
bytes_io.write(value) # string
bytes_io.write(b'\x00'*((-l-1) % 4)) # padding bytes
else:
bytes_io.write(b'\xfe') # byte 254
bytes_io.write(struct.pack('<i', l)[:3]) # 3 bytes of string
bytes_io.write(value) # string
bytes_io.write(b'\x00'*(-l % 4)) # padding bytes
def deserialize(bytes_io, type_=None, subtype=None):
"""
:type bytes_io: io.BytesIO object
"""
assert isinstance(bytes_io, io.BytesIO)
# Built-in bare types
if type_ == 'int': x = struct.unpack('<i', bytes_io.read(4))[0]
elif type_ == '#': x = struct.unpack('<I', bytes_io.read(4))[0]
elif type_ == 'long': x = struct.unpack('<q', bytes_io.read(8))[0]
elif type_ == 'double': x = struct.unpack('<d', bytes_io.read(8))[0]
elif type_ == 'int128': x = bytes_io.read(16)
elif type_ == 'int256': x = bytes_io.read(32)
elif type_ == 'string' or type_ == 'bytes':
l = struct.unpack('<B', bytes_io.read(1))[0]
assert l <= 254 # In general, 0xFF byte is not allowed here
if l == 254:
# We have a long string
long_len = struct.unpack('<I', bytes_io.read(3)+b'\x00')[0]
x = bytes_io.read(long_len)
bytes_io.read(-long_len % 4) # skip padding bytes
else:
# We have a short string
x = bytes_io.read(l)
bytes_io.read(-(l+1) % 4) # skip padding bytes
assert isinstance(x, bytes)
elif type_ == 'vector':
assert subtype is not None
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)]
else:
# Boxed types
i = struct.unpack('<i', bytes_io.read(4))[0] # read type ID
try:
tl_elem = tl.constructor_id[i]
except KeyError:
raise Exception("Could not extract type: %s" % type_)
base_boxed_types = ["Vector t", "Int", "Long", "Double", "String", "Int128", "Int256"]
if tl_elem.type in base_boxed_types:
x = deserialize(bytes_io, type_=tl_elem.predicate, subtype=subtype)
else: # other types
x = {}
for arg in tl_elem.params:
x[arg['name']] = deserialize(bytes_io, type_=arg['type'], subtype=arg['subtype'])
return x
class Session:
""" Manages TCP Transport. encryption and message frames """
def __init__(self, ip, port, auth_key_id=None):
def __init__(self, ip, port, auth_key=None):
# creating socket
self.sock = socket.socket()
self.sock.connect((ip, port))
self.auth_key_id = auth_key_id
self.number = 0
if auth_key is None:
self.create_auth_key()
else:
self.auth_key = auth_key
def __del__(self):
# closing socket when session object is deleted
self.sock.close()
@ -203,7 +79,7 @@ class Session:
return (b'\x00\x00\x00\x00\x00\x00\x00\x00' +
struct.pack('<Q', msg_id) +
struct.pack('<L', len(message)))
struct.pack('<I', len(message)))
# TCP Transport
@ -219,16 +95,14 @@ class Session:
Forming the message frame and sending message to server
:param message: byte string to send
"""
data = self.header_unencrypted(message) + message
step1 = struct.pack('<LL', len(data)+12, self.number) + data
step2 = step1 + struct.pack('<L', crc32(step1))
step1 = struct.pack('<II', len(data)+12, self.number) + data
step2 = step1 + struct.pack('<I', crc32(step1))
self.sock.send(step2)
self.number += 1
# Sending message visualisation to console
print('>>')
vis(step2)
# print('>>')
# vis(step2)
def recv_message(self):
"""
@ -237,27 +111,13 @@ class Session:
packet_length_data = self.sock.recv(4) # reads how many bytes to read
if len(packet_length_data) > 0: # if we have smth. in the socket
packet_length = struct.unpack("<L", packet_length_data)[0]
packet_length = struct.unpack("<I", packet_length_data)[0]
packet = self.sock.recv(packet_length - 4) # read the rest of bytes from socket
# Received message visualisation to console
print('<<')
vis(packet_length_data+packet)
(x, auth_key_id, message_id, message_length)= struct.unpack("<L8s8sI", packet[0:24])
(x, auth_key_id, message_id, message_length)= struct.unpack("<I8s8sI", packet[0:24])
data = packet[24:24+message_length]
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
if crc32(packet_length_data + packet[0:-4]) == struct.unpack('<L', crc)[0]:
if crc32(packet_length_data + packet[0:-4]) == struct.unpack('<I', crc)[0]:
return data
else:
raise Exception("CRC32 was not correct!")
@ -266,7 +126,7 @@ class Session:
def method_call(self, method, **kwargs):
z=io.BytesIO()
serialize_method(z, method, **kwargs)
TL.serialize_method(z, method, **kwargs)
# 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
@ -276,4 +136,137 @@ class Session:
# print("len of z_val: " + str(len(z_val)))
self.send_message(z_val)
server_answer = self.recv_message()
return deserialize(io.BytesIO(server_answer))
return TL.deserialize(io.BytesIO(server_answer))
def create_auth_key(self):
nonce = os.urandom(16)
print("Requesting PQ")
ResPQ = self.method_call('req_pq', nonce=nonce)
server_nonce = ResPQ['server_nonce']
# TODO: selecting RSA public key based on this fingerprint
public_key_fingerprint = ResPQ['server_public_key_fingerprints'][0]
PQ_bytes = ResPQ['pq']
# TODO: from_bytes here
PQ = struct.unpack('>q', PQ_bytes)[0]
[p, q] = prime.primefactors(PQ)
if p > q: (p, q) = (q, p)
assert p*q == PQ and p < q
print("Factorization %d = %d * %d" % (PQ, p, q))
# TODO: to_bytes here
P_bytes = struct.pack('>i', p)
Q_bytes = struct.pack('>i', q)
f = open(os.path.join(os.path.dirname(__file__), "rsa.pub"))
key = RSA.importKey(f.read())
z = io.BytesIO()
new_nonce = os.urandom(32)
TL.serialize_obj(z, 'p_q_inner_data',
pq=PQ_bytes,
p=P_bytes,
q=Q_bytes,
nonce=nonce,
server_nonce=server_nonce,
new_nonce=new_nonce)
data = z.getvalue()
sha_digest = SHA.new(data).digest()
random_bytes = os.urandom(255-len(data)-len(sha_digest))
to_encrypt = sha_digest + data + random_bytes
encrypted_data = key.encrypt(to_encrypt, 0)[0]
print("Starting Diffie Hellman key exchange")
server_DH_params = self.method_call('req_DH_params',
nonce=nonce, # 16 bytes
server_nonce=server_nonce,
p=P_bytes,
q=Q_bytes,
public_key_fingerprint=public_key_fingerprint,
encrypted_data=encrypted_data)
assert nonce == server_DH_params['nonce']
assert server_nonce == server_DH_params['server_nonce']
encrypted_answer = server_DH_params['encrypted_answer']
tmp_aes_key = SHA.new(new_nonce + server_nonce).digest() + SHA.new(server_nonce + new_nonce).digest()[0:12]
tmp_aes_iv = SHA.new(server_nonce + new_nonce).digest()[12:20] + SHA.new(new_nonce + new_nonce).digest() + new_nonce[0:4]
crypter = crypt.IGE(tmp_aes_key, tmp_aes_iv)
answer_with_hash = crypter.decrypt(encrypted_answer)
answer_hash = answer_with_hash[:20]
answer = answer_with_hash[20:]
# TODO: SHA hash assertion here
server_DH_inner_data = TL.deserialize(io.BytesIO(answer))
assert nonce == server_DH_inner_data['nonce']
assert server_nonce == server_DH_inner_data['server_nonce']
dh_prime_str = server_DH_inner_data['dh_prime']
g = server_DH_inner_data['g']
g_a_str = server_DH_inner_data['g_a']
server_time = server_DH_inner_data['server_time']
self.timedelta = server_time - time()
print("Server-client time delta = %.1f s" % self.timedelta)
dh_prime = int.from_bytes(dh_prime_str,'big')
g_a = int.from_bytes(g_a_str,'big')
assert prime.isprime(dh_prime)
retry_id = 0
while retry_id<25:
try:
b_str = os.urandom(256)
b = int.from_bytes(b_str,'big')
g_b = pow(g,b,dh_prime)
g_b_str = int.to_bytes(g_b, g_b.bit_length() // 8 + 1, 'big')
z = io.BytesIO()
TL.serialize_obj(z, 'client_DH_inner_data',
nonce=nonce,
server_nonce=server_nonce,
retry_id=retry_id,
g_b=g_b_str)
data = z.getvalue()
data_with_sha = SHA.new(data).digest()+data
data_with_sha_padded = data_with_sha + os.urandom(-len(data_with_sha) % 16)
encrypted_data = crypter.encrypt(data_with_sha_padded)
Set_client_DH_params_answer = self.method_call('set_client_DH_params',
nonce=nonce,
server_nonce=server_nonce,
encrypted_data=encrypted_data)
auth_key = pow(g_a, b, dh_prime)
auth_key_str = int.to_bytes(auth_key, auth_key.bit_length() // 8 + 1, 'big')
auth_key_sha = SHA.new(auth_key_str).digest()
auth_key_hash = auth_key_sha[-8:]
auth_key_aux_hash = auth_key_sha[:8]
new_nonce_hash1 = SHA.new(new_nonce+b'\x01'+auth_key_aux_hash).digest()[-16:]
new_nonce_hash2 = SHA.new(new_nonce+b'\x02'+auth_key_aux_hash).digest()[-16:]
new_nonce_hash3 = SHA.new(new_nonce+b'\x03'+auth_key_aux_hash).digest()[-16:]
assert Set_client_DH_params_answer['nonce'] == nonce
assert Set_client_DH_params_answer['server_nonce'] == server_nonce
assert Set_client_DH_params_answer['new_nonce_hash1'] == new_nonce_hash1
print("Diffie Hellman key exchange processed successfully")
self.server_salt = strxor(new_nonce[0:8], server_nonce[0:8])
self.auth_key = auth_key_str
print("Auth key generated")
break
except:
print("Retry DH key exchange")
retry_id += 1

View File

@ -7,14 +7,8 @@ try: # this only works in py2.7
import configparser
except ImportError:
import ConfigParser as configparser
from Crypto.Hash import SHA
from Crypto.PublicKey import RSA
from Crypto.Util.strxor import strxor
# local modules
import crypt
import mtproto
import prime
config = configparser.ConfigParser()
@ -25,130 +19,4 @@ if not config.read('credentials'):
ip = config.get('App data', 'ip_address')
port = config.getint('App data', 'port')
Session = mtproto.Session(ip, port)
client_nonce = os.urandom(16)
x = Session.method_call('req_pq', nonce=client_nonce)
server_nonce = x['server_nonce']
public_key_fingerprint = x['server_public_key_fingerprints'][0]
# TODO: selecting RSA public key based on this fingerprint
PQ_bytes = x['pq']
# 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)
if p > q: (p, q) = (q, p)
assert p*q == PQ and p < q
print("PQ = %d\np = %d, q = %d" % (PQ, p, q))
P_bytes = struct.pack('>i', p)
Q_bytes = struct.pack('>i', q)
f = open('rsa.pub', 'r')
key = RSA.importKey(f.read())
z = io.BytesIO()
new_nonce = os.urandom(32)
mtproto.serialize_obj(z, 'p_q_inner_data',
pq=PQ_bytes,
p=P_bytes,
q=Q_bytes,
nonce=client_nonce,
server_nonce=server_nonce,
new_nonce=new_nonce)
data = z.getvalue()
sha_digest = SHA.new(data).digest()
random_bytes = os.urandom(255-len(data)-len(sha_digest))
to_encrypt = sha_digest + data + random_bytes
encrypted_data = key.encrypt(to_encrypt, 0)[0]
server_DH_params = Session.method_call('req_DH_params',
nonce=client_nonce, # 16 bytes
server_nonce=server_nonce,
p=P_bytes,
q=Q_bytes,
public_key_fingerprint=public_key_fingerprint,
encrypted_data=encrypted_data)
assert client_nonce == server_DH_params['nonce']
assert server_nonce == server_DH_params['server_nonce']
encrypted_answer = server_DH_params['encrypted_answer']
tmp_aes_key = SHA.new(new_nonce + server_nonce).digest() + SHA.new(server_nonce + new_nonce).digest()[0:12]
tmp_aes_iv = SHA.new(server_nonce + new_nonce).digest()[12:20] + SHA.new(new_nonce + new_nonce).digest() + new_nonce[0:4]
crypter = crypt.IGE(tmp_aes_key, tmp_aes_iv)
answer_with_hash = crypter.decrypt(encrypted_answer)
answer_hash = answer_with_hash[:20]
answer = answer_with_hash[20:]
mtproto.vis(answer) # To start off BA0D89 ...
server_DH_inner_data = mtproto.deserialize(io.BytesIO(answer))
assert client_nonce == server_DH_inner_data['nonce']
assert server_nonce == server_DH_inner_data['server_nonce']
dh_prime_str = server_DH_inner_data['dh_prime']
g = server_DH_inner_data['g']
g_a_str = server_DH_inner_data['g_a']
server_time = server_DH_inner_data['server_time']
dh_prime = int.from_bytes(dh_prime_str,'big')
g_a = int.from_bytes(g_a_str,'big')
print(dh_prime)
print(g)
print(g_a)
print(prime.isprime(dh_prime))
b_str = os.urandom(256)
b = int.from_bytes(b_str,'big')
g_b = pow(g,b,dh_prime)
g_b_str = int.to_bytes(g_b, g_b.bit_length() // 8 + 1, 'big')
retry_id = 0
z = io.BytesIO()
mtproto.serialize_obj(z, 'client_DH_inner_data',
nonce=client_nonce,
server_nonce=server_nonce,
retry_id=retry_id,
g_b=g_b_str)
data = z.getvalue()
data_with_sha = SHA.new(data).digest()+data
data_with_sha_padded = data_with_sha + os.urandom(-len(data_with_sha) % 16)
encrypted_data = crypter.encrypt(data_with_sha_padded)
Set_client_DH_params_answer = Session.method_call('set_client_DH_params',
nonce=client_nonce,
server_nonce=server_nonce,
encrypted_data=encrypted_data)
print(encrypted_data)
print(Set_client_DH_params_answer)
auth_key = pow(g_a, b, dh_prime)
auth_key_str = int.to_bytes(auth_key, auth_key.bit_length() // 8 + 1, 'big')
print("auth_key = %d" % auth_key)
auth_key_sha = SHA.new(auth_key_str).digest()
auth_key_hash = auth_key_sha[-8:]
auth_key_aux_hash = auth_key_sha[:8]
new_nonce_hash1 = SHA.new(new_nonce+b'\x01'+auth_key_aux_hash).digest()[-16:]
new_nonce_hash2 = SHA.new(new_nonce+b'\x02'+auth_key_aux_hash).digest()[-16:]
new_nonce_hash3 = SHA.new(new_nonce+b'\x03'+auth_key_aux_hash).digest()[-16:]
assert Set_client_DH_params_answer['nonce'] == client_nonce
assert Set_client_DH_params_answer['server_nonce'] == server_nonce
assert Set_client_DH_params_answer['new_nonce_hash1'] == new_nonce_hash1
Session.__del__()
server_salt = strxor(new_nonce[0:8], server_nonce[0:8])
mtproto.vis(server_salt)
Session = mtproto.Session(ip, port)