def test_calc_key(self): # TODO Upgrade test for MtProto 2.0 shared_key = b'\xbc\xd2m\xb7\xcav\xf4][\x88\x83\' \xf3\x11\x8as\xd04\x941\xae' \ b'*O\x03\x86\x9a/H#\x1a\x8c\xb5j\xe9$\xe0IvCm^\xe70\x1a5C\t\x16' \ b'\x03\xd2\x9d\xa9\x89\xd6\xce\x08P\x0fdr\xa0\xb3\xeb\xfecv\x1a' \ b'\xdfJ\x14\x96\x98\x16\xa3G\xab\x04\x14!\\\xeb\n\xbcn\xdf\xc4%' \ b'\xc6\t\xb7\x16\x14\x9c\'\x81\x15=\xb0\xaf\x0e\x0bR\xaa\x0466s' \ b'\xf0\xcf\xb7\xb8>,D\x94x\xd7\xf8\xe0\x84\xcb%\xd3\x05\xb2\xe8' \ b'\x95Mr?\xa2\xe8In\xf9\x0b[E\x9b\xaa\x0cX\x7f\x0ei\xde\xeed\x1d' \ b'x/J\xce\xea^}0;\xa83B\xbbR\xa1\xbfe\x04\xb9\x1e\xa1"f=\xa5M@' \ b'\x9e\xdd\x81\x80\xc9\xa5\xfb\xfcg\xdd\x15\x03p!\x0ffD\x16\x892' \ b'\xea\xca\xb1A\x99O\xa94P\xa9\xa2\xc6;\xb2C9\x1dC5\xd2\r\xecL' \ b'\xd9\xabw-\x03\ry\xc2v\x17]\x02\x15\x0cBa\x97\xce\xa5\xb1\xe4]' \ b'\x8e\xe0,\xcfC{o\xfa\x99f\xa4pM\x00' # Calculate key being the client msg_key = b'\xba\x1a\xcf\xda\xa8^Cbl\xfa\xb6\x0c:\x9b\xb0\xfc' key, iv = utils.calc_key(shared_key, msg_key, client=True) expected_key = b"\xaf\xe3\x84Qm\xe0!\x0c\xd91\xe4\x9a\xa0v_gc" \ b"x\xa1\xb0\xc9\xbc\x16'v\xcf,\x9dM\xae\xc6\xa5" expected_iv = b'\xb8Q\xf3\xc5\xa3]\xc6\xdf\x9e\xe0Q\xbd"\x8d' \ b'\x13\t\x0e\x9a\x9d^8\xa2\xf8\xe7\x00w\xd9\xc1' \ b'\xa7\xa0\xf7\x0f' self.assertEqual( key, expected_key, msg='Invalid key (expected ("{}"), got ("{}"))'.format( expected_key, key)) self.assertEqual(iv, expected_iv, msg='Invalid IV (expected ("{}"), got ("{}"))'.format( expected_iv, iv)) # Calculate key being the server msg_key = b'\x86m\x92i\xcf\x8b\x93\xaa\x86K\x1fi\xd04\x83]' key, iv = utils.calc_key(shared_key, msg_key, client=False) expected_key = b'\xdd0X\xb6\x93\x8e\xc9y\xef\x83\xf8\x8cj' \ b'\xa7h\x03\xe2\xc6\xb16\xc5\xbb\xfc\xe7' \ b'\xdf\xd6\xb1g\xf7u\xcfk' expected_iv = b'\xdcL\xc2\x18\x01J"X\x86lb\xb6\xb547\xfd' \ b'\xe2a4\xb6\xaf}FS\xd7[\xe0N\r\x19\xfb\xbc' self.assertEqual( key, expected_key, msg='Invalid key (expected ("{}"), got ("{}"))'.format( expected_key, key)) self.assertEqual(iv, expected_iv, msg='Invalid IV (expected ("{}"), got ("{}"))'.format( expected_iv, iv))
def test_calc_key(self): # TODO Upgrade test for MtProto 2.0 shared_key = b'\xbc\xd2m\xb7\xcav\xf4][\x88\x83\' \xf3\x11\x8as\xd04\x941\xae' \ b'*O\x03\x86\x9a/H#\x1a\x8c\xb5j\xe9$\xe0IvCm^\xe70\x1a5C\t\x16' \ b'\x03\xd2\x9d\xa9\x89\xd6\xce\x08P\x0fdr\xa0\xb3\xeb\xfecv\x1a' \ b'\xdfJ\x14\x96\x98\x16\xa3G\xab\x04\x14!\\\xeb\n\xbcn\xdf\xc4%' \ b'\xc6\t\xb7\x16\x14\x9c\'\x81\x15=\xb0\xaf\x0e\x0bR\xaa\x0466s' \ b'\xf0\xcf\xb7\xb8>,D\x94x\xd7\xf8\xe0\x84\xcb%\xd3\x05\xb2\xe8' \ b'\x95Mr?\xa2\xe8In\xf9\x0b[E\x9b\xaa\x0cX\x7f\x0ei\xde\xeed\x1d' \ b'x/J\xce\xea^}0;\xa83B\xbbR\xa1\xbfe\x04\xb9\x1e\xa1"f=\xa5M@' \ b'\x9e\xdd\x81\x80\xc9\xa5\xfb\xfcg\xdd\x15\x03p!\x0ffD\x16\x892' \ b'\xea\xca\xb1A\x99O\xa94P\xa9\xa2\xc6;\xb2C9\x1dC5\xd2\r\xecL' \ b'\xd9\xabw-\x03\ry\xc2v\x17]\x02\x15\x0cBa\x97\xce\xa5\xb1\xe4]' \ b'\x8e\xe0,\xcfC{o\xfa\x99f\xa4pM\x00' # Calculate key being the client msg_key = b'\xba\x1a\xcf\xda\xa8^Cbl\xfa\xb6\x0c:\x9b\xb0\xfc' key, iv = utils.calc_key(shared_key, msg_key, client=True) expected_key = b"\xaf\xe3\x84Qm\xe0!\x0c\xd91\xe4\x9a\xa0v_gc" \ b"x\xa1\xb0\xc9\xbc\x16'v\xcf,\x9dM\xae\xc6\xa5" expected_iv = b'\xb8Q\xf3\xc5\xa3]\xc6\xdf\x9e\xe0Q\xbd"\x8d' \ b'\x13\t\x0e\x9a\x9d^8\xa2\xf8\xe7\x00w\xd9\xc1' \ b'\xa7\xa0\xf7\x0f' self.assertEqual(key, expected_key, msg='Invalid key (expected ("{}"), got ("{}"))' .format(expected_key, key)) self.assertEqual(iv, expected_iv, msg='Invalid IV (expected ("{}"), got ("{}"))' .format(expected_iv, iv)) # Calculate key being the server msg_key = b'\x86m\x92i\xcf\x8b\x93\xaa\x86K\x1fi\xd04\x83]' key, iv = utils.calc_key(shared_key, msg_key, client=False) expected_key = b'\xdd0X\xb6\x93\x8e\xc9y\xef\x83\xf8\x8cj' \ b'\xa7h\x03\xe2\xc6\xb16\xc5\xbb\xfc\xe7' \ b'\xdf\xd6\xb1g\xf7u\xcfk' expected_iv = b'\xdcL\xc2\x18\x01J"X\x86lb\xb6\xb547\xfd' \ b'\xe2a4\xb6\xaf}FS\xd7[\xe0N\r\x19\xfb\xbc' self.assertEqual(key, expected_key, msg='Invalid key (expected ("{}"), got ("{}"))' .format(expected_key, key)) self.assertEqual(iv, expected_iv, msg='Invalid IV (expected ("{}"), got ("{}"))' .format(expected_iv, iv))
def decode_msg(self, body): """Decodes an received encrypted message body bytes""" message = None remote_msg_id = None remote_sequence = None with BinaryReader(body) as reader: if len(body) < 8: raise BufferError("Can't decode packet ({})".format(body)) # TODO Check for both auth key ID and msg_key correctness reader.read_long() # remote_auth_key_id msg_key = reader.read(16) key, iv = utils.calc_key(self.session.auth_key.key, msg_key, False) plain_text = AES.decrypt_ige( reader.read(len(body) - reader.tell_position()), key, iv) with BinaryReader(plain_text) as plain_text_reader: plain_text_reader.read_long() # remote_salt plain_text_reader.read_long() # remote_session_id remote_msg_id = plain_text_reader.read_long() remote_sequence = plain_text_reader.read_int() msg_len = plain_text_reader.read_int() message = plain_text_reader.read(msg_len) return message, remote_msg_id, remote_sequence
def send_packet(self, packet, request): """Sends the given packet bytes with the additional information of the original request. This does NOT lock the threads!""" request.msg_id = self.session.get_new_msg_id() # First calculate plain_text to encrypt it with BinaryWriter() as plain_writer: plain_writer.write_long(self.session.salt, signed=False) plain_writer.write_long(self.session.id, signed=False) plain_writer.write_long(request.msg_id) plain_writer.write_int(self.generate_sequence(request.confirmed)) plain_writer.write_int(len(packet)) plain_writer.write(packet) msg_key = utils.calc_msg_key(plain_writer.get_bytes()) key, iv = utils.calc_key(self.session.auth_key.key, msg_key, True) cipher_text = AES.encrypt_ige(plain_writer.get_bytes(), key, iv) # And then finally send the encrypted packet with BinaryWriter() as cipher_writer: cipher_writer.write_long(self.session.auth_key.key_id, signed=False) cipher_writer.write(msg_key) cipher_writer.write(cipher_text) self.transport.send(cipher_writer.get_bytes())