Add auth error handling
This commit is contained in:
parent
a07f8e56a5
commit
4d8cd202f1
6
.gitignore
vendored
6
.gitignore
vendored
@ -59,4 +59,8 @@ target/
|
|||||||
|
|
||||||
# testing apps
|
# testing apps
|
||||||
credentials
|
credentials
|
||||||
rsa.pub
|
rsa.pub
|
||||||
|
|
||||||
|
# emacs auto-saving files
|
||||||
|
\#*#
|
||||||
|
.#*#
|
4
TL.py
4
TL.py
@ -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
|
||||||
|
59
mtproto.py
59
mtproto.py
@ -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
|
||||||
|
@ -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
21
tests/auth_key_test.py
Normal 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
|
Loading…
Reference in New Issue
Block a user