diff --git a/telethon/client/secret.py b/telethon/client/secret.py index cbf5dfc2..5b7a60c0 100644 --- a/telethon/client/secret.py +++ b/telethon/client/secret.py @@ -103,16 +103,122 @@ class SecretChatMethods: def generate_secret_out_seq_no(self, chat_id): return self.secret_chats[chat_id].out_seq_no * 2 + self.secret_chats[chat_id].out_seq_no_x + async def rekey(self, peer): + peer = self.get_secret_chat(peer) + self._log.debug(f'Rekeying secret chat {peer}') + dh_config = await self.get_dh_config() + a = int.from_bytes(os.urandom(256), 'big', signed=False) + g_a = pow(dh_config.g, a, dh_config.p) + self.check_g_a(g_a, dh_config.p) + e = random.randint(10000000, 99999999) + self.temp_rekeyed_secret_chats[e] = a + peer.rekeying = [1, e] + message = DecryptedMessageService(action=DecryptedMessageActionRequestKey( + g_a=g_a.to_bytes(256, 'big', signed=False), + exchange_id=e, + )) + message = await self.encrypt_secret_message(peer, message) + await self(SendEncryptedServiceRequest(InputEncryptedChat(peer.id, peer.access_hash), message)) + + return e + + async def accept_rekey(self, peer, action: DecryptedMessageActionRequestKey): + peer = self.get_secret_chat(peer) + if peer.rekeying[0] != 0: + my_exchange_id = peer.rekeying[1] + other_exchange_id = action.exchange_id + if my_exchange_id > other_exchange_id: + return + if my_exchange_id == other_exchange_id: + peer.rekeying = [0] + return + self._log.debug(f'Accepting rekeying secret chat {peer}') + dh_config = await self.get_dh_config() + random_bytes = os.urandom(256) + b = int.from_bytes(random_bytes, byteorder="big", signed=False) + g_a = int.from_bytes(action.g_a, 'big', signed=False) + self.check_g_a(g_a, dh_config.p) + res = pow(g_a, b, dh_config.p) + auth_key = res.to_bytes(256, 'big', signed=False) + key = ChatKey(auth_key) + key.fingerprint = struct.unpack(' 7 * 24 * 60 * 60) and peer.rekeying[0] == 0: - # TODO rekeying - raise ValueError("need re_keying") + await self.rekey(peer) peer.incoming[peer.in_seq_no] = message return await self.handle_decrypted_message(decrypted_message, peer) @@ -198,8 +302,7 @@ class SecretChatMethods: peer.ttr -= 1 if peer.layer > 8: if (peer.ttr <= 0 or (time() - peer.updated) > 7 * 24 * 60 * 60) and peer.rekeying[0] == 0: - # TODO rekeying - raise ValueError("need re_keying") + await self.rekey(peer) message = DecryptedMessageLayer(layer=peer.layer, random_bytes=os.urandom(15 + 4 * random.randint(0, 2)), in_seq_no=self.generate_secret_in_seq_no(peer.id),