mirror of
https://github.com/LonamiWebs/Telethon.git
synced 2024-11-22 09:26:37 +03:00
Reached Authenticator's step 3
This commit is contained in:
parent
75a648f438
commit
75892afb2e
|
@ -39,7 +39,9 @@ def do_authentication(transport):
|
||||||
server_nonce = reader.read(16)
|
server_nonce = reader.read(16)
|
||||||
|
|
||||||
pq_bytes = reader.tgread_bytes()
|
pq_bytes = reader.tgread_bytes()
|
||||||
pq = int.from_bytes(pq_bytes, byteorder='little')
|
# "string pq is a representation of a natural number (in binary big endian format)"
|
||||||
|
# See https://core.telegram.org/mtproto/auth_key#dh-exchange-initiation
|
||||||
|
pq = int.from_bytes(pq_bytes, byteorder='big')
|
||||||
|
|
||||||
vector_id = reader.read_int()
|
vector_id = reader.read_int()
|
||||||
if vector_id != 0x1cb5c415:
|
if vector_id != 0x1cb5c415:
|
||||||
|
@ -88,7 +90,6 @@ def do_authentication(transport):
|
||||||
|
|
||||||
# Step 2 response: DH Exchange
|
# Step 2 response: DH Exchange
|
||||||
encrypted_answer = None
|
encrypted_answer = None
|
||||||
# TODO, there is no data to read? What's going on?
|
|
||||||
with BinaryReader(sender.receive()) as reader:
|
with BinaryReader(sender.receive()) as reader:
|
||||||
response_code = reader.read_int(signed=False)
|
response_code = reader.read_int(signed=False)
|
||||||
|
|
||||||
|
@ -110,7 +111,8 @@ def do_authentication(transport):
|
||||||
|
|
||||||
# Step 3 sending: Complete DH Exchange
|
# Step 3 sending: Complete DH Exchange
|
||||||
key, iv = utils.generate_key_data_from_nonces(server_nonce, new_nonce)
|
key, iv = utils.generate_key_data_from_nonces(server_nonce, new_nonce)
|
||||||
aes = pyaes.AESModeOfOperationCFB(key, iv, 16)
|
# TODO ValueError: initialization vector must be 16 bytes
|
||||||
|
aes = pyaes.AESModeOfOperationCFB(key, iv, len(key))
|
||||||
plain_text_answer = aes.decrypt(encrypted_answer)
|
plain_text_answer = aes.decrypt(encrypted_answer)
|
||||||
|
|
||||||
g, dh_prime, ga, time_offset = None, None, None, None
|
g, dh_prime, ga, time_offset = None, None, None, None
|
||||||
|
@ -129,13 +131,15 @@ def do_authentication(transport):
|
||||||
raise AssertionError('Invalid server nonce in encrypted answer')
|
raise AssertionError('Invalid server nonce in encrypted answer')
|
||||||
|
|
||||||
g = dh_inner_data_reader.read_int()
|
g = dh_inner_data_reader.read_int()
|
||||||
dh_prime = int.from_bytes(dh_inner_data_reader.tgread_bytes(), byteorder='little', signed=True)
|
# "current value of dh_prime equals (in big-endian byte order)
|
||||||
ga = int.from_bytes(dh_inner_data_reader.tgread_bytes(), byteorder='little', signed=True)
|
# See https://core.telegram.org/mtproto/auth_key#presenting-proof-of-work-server-authentication
|
||||||
|
dh_prime = int.from_bytes(dh_inner_data_reader.tgread_bytes(), byteorder='big', signed=True)
|
||||||
|
ga = int.from_bytes(dh_inner_data_reader.tgread_bytes(), byteorder='big', signed=True)
|
||||||
|
|
||||||
server_time = dh_inner_data_reader.read_int()
|
server_time = dh_inner_data_reader.read_int()
|
||||||
time_offset = server_time - int(time.time() * 1000) # Multiply by 1000 to get milliseconds
|
time_offset = server_time - int(time.time() * 1000) # Multiply by 1000 to get milliseconds
|
||||||
|
|
||||||
b = int.from_bytes(utils.generate_random_bytes(2048), byteorder='little')
|
b = int.from_bytes(utils.generate_random_bytes(2048), byteorder='big', signed=True)
|
||||||
gb = pow(g, b, dh_prime)
|
gb = pow(g, b, dh_prime)
|
||||||
gab = pow(ga, b, dh_prime)
|
gab = pow(ga, b, dh_prime)
|
||||||
|
|
||||||
|
|
49
unit_test.py
49
unit_test.py
|
@ -8,7 +8,6 @@ from network.tcp_client import TcpClient
|
||||||
from utils.binary_reader import BinaryReader
|
from utils.binary_reader import BinaryReader
|
||||||
from utils.binary_writer import BinaryWriter
|
from utils.binary_writer import BinaryWriter
|
||||||
from utils.factorizator import Factorizator
|
from utils.factorizator import Factorizator
|
||||||
from utils.rsa import RSA
|
|
||||||
|
|
||||||
|
|
||||||
host = 'localhost'
|
host = 'localhost'
|
||||||
|
@ -110,7 +109,6 @@ class UnitTest(unittest.TestCase):
|
||||||
|
|
||||||
assert buffer == valid, "Written type should be {} but is {}".format(list(valid), list(buffer))
|
assert buffer == valid, "Written type should be {} but is {}".format(list(valid), list(buffer))
|
||||||
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def test_binary_tgwriter_tgreader():
|
def test_binary_tgwriter_tgreader():
|
||||||
string = 'Testing Telegram strings, this should work properly!'
|
string = 'Testing Telegram strings, this should work properly!'
|
||||||
|
@ -143,7 +141,6 @@ class UnitTest(unittest.TestCase):
|
||||||
assert p == 1719614201, 'Factorized pair did not yield the correct result'
|
assert p == 1719614201, 'Factorized pair did not yield the correct result'
|
||||||
assert q == 1813767169, 'Factorized pair did not yield the correct result'
|
assert q == 1813767169, 'Factorized pair did not yield the correct result'
|
||||||
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def test_to_byte_array():
|
def test_to_byte_array():
|
||||||
for value, real in zip(
|
for value, real in zip(
|
||||||
|
@ -169,36 +166,30 @@ class UnitTest(unittest.TestCase):
|
||||||
real = '0A-54-92-7C-8D-06-3A-29-99-04-8E-F8-6A-3F-C4-8E-D3-7D-6D-39'
|
real = '0A-54-92-7C-8D-06-3A-29-99-04-8E-F8-6A-3F-C4-8E-D3-7D-6D-39'
|
||||||
assert hashsum == real, 'Invalid sha1 hashsum representation (should be {}, but is {})'.format(real, data)
|
assert hashsum == real, 'Invalid sha1 hashsum representation (should be {}, but is {})'.format(real, data)
|
||||||
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def test_rsa():
|
def test_bytes_to_int():
|
||||||
fingerprint = '216BE86C022BB4C3'
|
bytez = b'\x01\x23\x45\x67\x89\xab\xcd\xef'
|
||||||
data = get_bytes('EC-5A-C9-83-08-29-86-64-72-35-B8-4B-7D-00-00-00-04-59-6B-F5-41-00-00-00-04-76-E1-1B-3D-00-00-00-CE-2A-EA-DE-D2-17-35-B8-E6-AB-3B-3A-00-0A-79-46-C6-09-3A-99-E9-C1-5B-B5-20-30-27-B7-D5-4F-2F-A3-1C-AF-F4-23-54-B2-5E-BD-00-AB-71-0A-3E-67-94-21-E3-B3-72-71-C0-29-50-00-19-8C-CD-6A-52-D4-CE-9E')
|
|
||||||
hashsum = utils.sha1(data)
|
|
||||||
real = get_bytes('6C-86-F7-6D-A2-F5-C2-A5-D0-4D-D5-45-8A-85-AE-62-8B-F7-84-A0')
|
|
||||||
|
|
||||||
assert hashsum == real, 'Invalid sha1 hashsum representation (should be {}, but is {})'\
|
reprs = get_representation(bytez)
|
||||||
.format(get_representation(real), get_representation(data))
|
real = '01-23-45-67-89-AB-CD-EF'
|
||||||
|
assert reprs == real, 'Invalid bytes representation (should be {} but is {})'.format(real, reprs)
|
||||||
|
assert bytez == get_bytes(reprs), 'Invalid representation to bytes conversion'
|
||||||
|
|
||||||
with BinaryWriter() as writer:
|
value = int.from_bytes(bytez, byteorder='big', signed=True)
|
||||||
writer.write(hashsum)
|
real = 81985529216486895
|
||||||
writer.write(data)
|
assert value == real, 'Invalid bytes to int conversion (should be {} but is {})'.format(real, value)
|
||||||
|
|
||||||
real = get_bytes('6C-86-F7-6D-A2-F5-C2-A5-D0-4D-D5-45-8A-85-AE-62-8B-F7-84-A0-EC-5A-C9-83-08-29-86-64-72-35-B8-4B-7D-00-00-00-04-59-6B-F5-41-00-00-00-04-76-E1-1B-3D-00-00-00-CE-2A-EA-DE-D2-17-35-B8-E6-AB-3B-3A-00-0A-79-46-C6-09-3A-99-E9-C1-5B-B5-20-30-27-B7-D5-4F-2F-A3-1C-AF-F4-23-54-B2-5E-BD-00-AB-71-0A-3E-67-94-21-E3-B3-72-71-C0-29-50-00-19-8C-CD-6A-52-D4-CE-9E')
|
|
||||||
assert writer.get_bytes() == real, 'Invalid written value'
|
|
||||||
|
|
||||||
# Since the random padding is random by nature, use the sample data we know the result for
|
|
||||||
data = get_bytes(
|
|
||||||
'6C-86-F7-6D-A2-F5-C2-A5-D0-4D-D5-45-8A-85-AE-62-8B-F7-84-A0-EC-5A-C9-83-08-29-86-64-72-35-B8-4B-7D-00-00-00-04-59-6B-F5-41-00-00-00-04-76-E1-1B-3D-00-00-00-CE-2A-EA-DE-D2-17-35-B8-E6-AB-3B-3A-00-0A-79-46-C6-09-3A-99-E9-C1-5B-B5-20-30-27-B7-D5-4F-2F-A3-1C-AF-F4-23-54-B2-5E-BD-00-AB-71-0A-3E-67-94-21-E3-B3-72-71-C0-29-50-00-19-8C-CD-6A-52-D4-CE-9E-10-F4-6E-C6-1F-CB-DC-8C-2A-7A-91-92-71-22-D6-08-AD-B4-6D-5F-D3-59-0F-F4-71-1A-57-FF-17-9E-AE-CD-D8-90-4B-DB-1A-1F-06-C1-22-8D-20-67-F8-F0-F2-D1-26-DF-E9-78-72-A7-DF-B6-E5-7A-55-04-73-DD-74-8B-CB-C3-B9-E1-D7-FA-EE-8E-AD-AB-3D-46-39-A8-FB-80-28-85-D8-38-B5-35-5B-30-B0-94-F6-A0-CA-02-4E-45-18-94-9B-35-36-11-FA-2C-F0-5B-CA-C6-6A-98-7D-3C-7E-D4-DB-ED-05-3C-D6-95-68-88-30-43-04-4E-C3-AB-5D-F7-2D-A5-0C-C6-49-17-8B-AC-48')
|
|
||||||
|
|
||||||
e = 65537
|
|
||||||
m = 24403446649145068056824081744112065346446136066297307473868293895086332508101251964919587745984311372853053253457835208829824428441874946556659953519213382748319518214765985662663680818277989736779506318868003755216402538945900388706898101286548187286716959100102939636333452457308619454821845196109544157601096359148241435922125602449263164512290854366930013825808102403072317738266383237191313714482187326643144603633877219028262697593882410403273959074350849923041765639673335775605842311578109726403165298875058941765362622936097839775380070572921007586266115476975819175319995527916042178582540628652481530373407
|
|
||||||
|
|
||||||
cipher_text = utils.get_byte_array(pow(int.from_bytes(data, byteorder='big'), e, m), signed=False)
|
|
||||||
real = get_bytes('13-8A-DC-F1-10-FF-59-29-2D-ED-4A-16-AA-D9-FA-15-A5-9A-A2-A6-33-D0-23-77-6F-E7-42-30-52-9E-4E-A9-CA-8F-CD-11-71-AB-C8-E2-97-2C-B9-A1-68-FA-4D-02-A9-56-30-84-5B-F6-5F-5D-1E-95-53-A4-A9-8F-1F-66-82-0C-20-8F-6D-EB-6F-B0-F5-D2-6C-45-89-14-1F-69-85-C8-6F-C7-41-A5-76-5F-F5-BA-9B-18-32-F7-02-C8-29-A7-70-BE-8E-FD-9E-86-48-6D-00-1E-AF-77-3F-7C-A4-1E-CD-03-21-18-4A-4D-57-FB-D9-6F-B0-4A-AD-24-A4-6F-01-07-CB-56-AC-37-22-9F-50-1F-EA-B9-17-51-EB-4B-A9-30-14-5A-A8-A9-5F-9D-9D-A5-AE-46-86-0D-0B-07-2D-84-C6-3B-DD-AD-4B-EA-89-07-CF-6B-DD-D4-68-38-F9-A9-62-A7-A3-3A-CB-79-F3-42-1B-28-E4-25-90-9B-B2-ED-EE-BC-65-8B-10-21-38-27-8B-66-98-51-A2-30-4B-F0-EA-BD-5D-E1-7D-D0-55-6E-A5-D1-FB-12-01-C2-44-D7-1F-B5-28-37-3B-08-8D-3B-79-59-D6-15-76-A4-4B-E6-3C-B3-16-58-88-9F-F9-77-21-C1-99-4E')
|
|
||||||
assert cipher_text == real, 'Invalid ciphered text (should be {}, but is {})'\
|
|
||||||
.format(get_representation(real), get_representation(cipher_text))
|
|
||||||
|
|
||||||
|
# Now test more cases
|
||||||
|
for repr, real in zip(
|
||||||
|
['24-9D-FE-49-20-45-DF-C3', '60-44-F3-33', '61-5F-61-31'],
|
||||||
|
[2638544546736496579, 1615131443, 1633640753]
|
||||||
|
):
|
||||||
|
bytez = get_bytes(repr)
|
||||||
|
if len(bytez) > 8:
|
||||||
|
value = int.from_bytes(bytez, byteorder='little', signed=True)
|
||||||
|
else:
|
||||||
|
value = int.from_bytes(bytez, byteorder='big', signed=True)
|
||||||
|
assert value == real, 'Invalid bytes to int conversion (should be {} but is {})'.format(real, value)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
|
@ -60,7 +60,7 @@ def generate_key_data_from_nonces(server_nonce, new_nonce):
|
||||||
|
|
||||||
iv_buffer.write(hash2[12:20])
|
iv_buffer.write(hash2[12:20])
|
||||||
iv_buffer.write(hash3)
|
iv_buffer.write(hash3)
|
||||||
iv_buffer.write_byte(new_nonce[:4])
|
iv_buffer.write(new_nonce[:4])
|
||||||
|
|
||||||
return key_buffer.get_bytes(), iv_buffer.get_bytes()
|
return key_buffer.get_bytes(), iv_buffer.get_bytes()
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user