Add auth error handling

This commit is contained in:
lds56 2015-04-04 15:18:45 +08:00
parent a07f8e56a5
commit 4d8cd202f1
5 changed files with 73 additions and 22 deletions

6
.gitignore vendored
View File

@ -59,4 +59,8 @@ target/
# testing apps # testing apps
credentials credentials
rsa.pub rsa.pub
# emacs auto-saving files
\#*#
.#*#

4
TL.py
View File

@ -152,11 +152,13 @@ def deserialize(bytes_io, type_=None, subtype=None):
except KeyError: except KeyError:
# Unknown type # Unknown type
raise Exception("Could not extract type: %s" % type_) raise Exception("Could not extract type: %s" % type_)
base_boxed_types = ["Vector t", "Int", "Long", "Double", "String", "Int128", "Int256"] base_boxed_types = ["Vector t", "Int", "Long", "Double", "String", "Int128", "Int256"]
if tl_elem.type in base_boxed_types: if tl_elem.type in base_boxed_types:
x = deserialize(bytes_io, type_=tl_elem.predicate, subtype=subtype) x = deserialize(bytes_io, type_=tl_elem.predicate, subtype=subtype)
else: # other types else: # other types
x = {} x = {}
x[u'name'] = tl_elem.predicate
for arg in tl_elem.params: for arg in tl_elem.params:
x[arg['name']] = deserialize(bytes_io, type_=arg['type'], subtype=arg['subtype']) x[arg['name']] = deserialize(bytes_io, type_=arg['type'], subtype=arg['subtype'])
return x return x

View File

@ -52,6 +52,9 @@ class Session:
self.session_id = os.urandom(8) self.session_id = os.urandom(8)
self.auth_key = auth_key self.auth_key = auth_key
self.auth_key_id = SHA.new(self.auth_key).digest()[-8:] if self.auth_key else None self.auth_key_id = SHA.new(self.auth_key).digest()[-8:] if self.auth_key else None
self.sock.settimeout(5.0)
self.MAX_RETRY = 5;
self.AUTH_MAX_RETRY = 5;
def __del__(self): def __del__(self):
# closing socket when session object is deleted # closing socket when session object is deleted
@ -129,9 +132,14 @@ class Session:
return data return data
def method_call(self, method, **kwargs): def method_call(self, method, **kwargs):
self.send_message(TL.serialize_method(method, **kwargs)) for i in range(1, self.MAX_RETRY):
server_answer = self.recv_message() try:
return TL.deserialize(io.BytesIO(server_answer)) self.send_message(TL.serialize_method(method, **kwargs))
server_answer = self.recv_message()
except socket.timeout:
print("Retry call method")
continue
return TL.deserialize(io.BytesIO(server_answer))
def create_auth_key(self): def create_auth_key(self):
@ -223,29 +231,42 @@ class Session:
data_with_sha_padded = data_with_sha + os.urandom(-len(data_with_sha) % 16) data_with_sha_padded = data_with_sha + os.urandom(-len(data_with_sha) % 16)
encrypted_data = crypt.ige_encrypt(data_with_sha_padded, tmp_aes_key, tmp_aes_iv) encrypted_data = crypt.ige_encrypt(data_with_sha_padded, tmp_aes_key, tmp_aes_iv)
Set_client_DH_params_answer = self.method_call('set_client_DH_params', for i in range(1, self.AUTH_MAX_RETRY): # retry when dh_gen_retry or dh_gen_fail
Set_client_DH_params_answer = self.method_call('set_client_DH_params',
nonce=nonce, nonce=nonce,
server_nonce=server_nonce, server_nonce=server_nonce,
encrypted_data=encrypted_data) encrypted_data=encrypted_data)
auth_key = pow(g_a, b, dh_prime) # print Set_client_DH_params_answer
auth_key_str = long_to_bytes(auth_key) auth_key = pow(g_a, b, dh_prime)
auth_key_sha = SHA.new(auth_key_str).digest() auth_key_str = long_to_bytes(auth_key)
auth_key_aux_hash = auth_key_sha[:8] auth_key_sha = SHA.new(auth_key_str).digest()
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_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_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:] 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['nonce'] == nonce
assert Set_client_DH_params_answer['server_nonce'] == server_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]) if Set_client_DH_params_answer['name'] == 'dh_gen_ok':
self.auth_key = auth_key_str assert Set_client_DH_params_answer['new_nonce_hash1'] == new_nonce_hash1
self.auth_key_id = auth_key_sha[-8:] print("Diffie Hellman key exchange processed successfully")
print("Auth key generated")
self.server_salt = strxor(new_nonce[0:8], server_nonce[0:8])
self.auth_key = auth_key_str
self.auth_key_id = auth_key_sha[-8:]
print("Auth key generated")
return "Auth Ok"
elif Set_client_DH_params_answer['name'] == 'dh_gen_retry':
assert Set_client_DH_params_answer['new_nonce_hash2'] == new_nonce_hash2
print ("Retry Auth")
elif Set_client_DH_params_answer['name'] == 'dh_gen_fail':
assert Set_client_DH_params_answer['new_nonce_hash3'] == new_nonce_hash3
print("Auth Failed")
raise Exception("Auth Failed")
else: raise Exception("Response Error")
def aes_calculate(self, msg_key, direction="to server"): def aes_calculate(self, msg_key, direction="to server"):
x = 0 if direction == "to server" else 8 x = 0 if direction == "to server" else 8

View File

@ -1,5 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import os import os
import time
import io import io
import struct import struct
# Deal with py2 and py3 differences # Deal with py2 and py3 differences
@ -20,7 +21,9 @@ ip = config.get('App data', 'ip_address')
port = config.getint('App data', 'port') port = config.getint('App data', 'port')
Session = mtproto.Session(ip, port) Session = mtproto.Session(ip, port)
# print("start create")
Session.create_auth_key() Session.create_auth_key()
future_salts = Session.method_call('get_future_salts', num=3) future_salts = Session.method_call('get_future_salts', num=3)
print(future_salts) print(future_salts)

21
tests/auth_key_test.py Normal file
View File

@ -0,0 +1,21 @@
import unittest
import os
import io
try:
import configparser
except ImportError:
import ConfigParser as configparser
import mtproto
class TestAuthKeyCase(unittest.TestCase):
def setUp(self):
def tearDown(self):
pass
def test_socket_timeout(self):
# def t