async def complete_rekey(self, peer, action: DecryptedMessageActionCommitKey): peer = self.get_secret_chat(peer) if peer.rekeying[0] != 2 or self.temp_rekeyed_secret_chats.get( action.exchange_id, None): return if self.temp_rekeyed_secret_chats.get( action.exchange_id) != action.key_fingerprint: message = DecryptedMessageService( action=DecryptedMessageActionAbortKey( exchange_id=action.exchange_id, )) message = await self.encrypt_secret_message(peer, message) await self.client( SendEncryptedServiceRequest( InputEncryptedChat(peer.id, peer.access_hash), message)) raise SecurityError("Invalid Key fingerprint") self._log.debug(f'Completing rekeying secret chat {peer}') peer.rekeying = [0] peer.auth_key = self.temp_rekeyed_secret_chats[action.exchange_id] peer.ttr = 100 peer.updated = time() del self.temp_rekeyed_secret_chats[action.exchange_id] message = DecryptedMessageService(action=DecryptedMessageActionNoop()) message = await self.encrypt_secret_message(peer, message) await self.client( SendEncryptedServiceRequest( InputEncryptedChat(peer.id, peer.access_hash), message)) self._log.debug(f'Secret chat {peer} rekeyed succrsfully')
async def commit_rekey(self, peer, action: DecryptedMessageActionAcceptKey): peer = self.get_secret_chat(peer) if peer.rekeying[0] != 1 or not self._temp_rekeyed_secret_chats.get(action.exchange_id, None): peer.rekeying = [0] return self._log.debug(f'Committing rekeying secret chat {peer}') dh_config = await self.get_dh_config() g_b = int.from_bytes(action.g_b, 'big', signed=False) self.check_g_a(g_b, dh_config.p) res = pow(g_b, self._temp_rekeyed_secret_chats[action.exchange_id], dh_config.p) auth_key = res.to_bytes(256, 'big', signed=False) key_fingerprint = struct.unpack('<q', sha1(auth_key).digest()[-8:])[0] if key_fingerprint != action.key_fingerprint: message = DecryptedMessageService(action=DecryptedMessageActionAbortKey( exchange_id=action.exchange_id, )) message = await self.encrypt_secret_message(peer, message) await self.client(SendEncryptedServiceRequest(InputEncryptedChat(peer.id, peer.access_hash), message)) raise SecurityError("Invalid Key fingerprint") message = DecryptedMessageService(action=DecryptedMessageActionCommitKey( exchange_id=action.exchange_id, key_fingerprint=key_fingerprint )) message = await self.encrypt_secret_message(peer, message) await self.client(SendEncryptedServiceRequest(InputEncryptedChat(peer.id, peer.access_hash), message)) del self._temp_rekeyed_secret_chats[action.exchange_id] peer.rekeying = [0] peer.auth_key = auth_key peer.ttl = 100 peer.updated = time()
async def accept_secret_chat(self, chat: TypeEncryptedChat): if chat.id == 0: raise ValueError("Already accepted") 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(chat.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_fingerprint = struct.unpack('<q', sha1(auth_key).digest()[-8:])[0] input_peer = InputEncryptedChat(chat_id=chat.id, access_hash=chat.access_hash) secret_chat = SecretChat(chat.id, chat.access_hash, auth_key, admin=False, user_id=chat.admin_id, input_chat=input_peer) self.session.save_chat(secret_chat, False) g_b = pow(dh_config.g, b, dh_config.p) self.check_g_a(g_b, dh_config.p) result = await self.client( AcceptEncryptionRequest(input_peer, g_b=g_b.to_bytes(256, 'big', signed=False), key_fingerprint=key_fingerprint)) await self.notify_layer(chat) return result
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_fingerprint = struct.unpack('<q', sha1(auth_key).digest()[-8:])[0] self.temp_rekeyed_secret_chats[action.exchange_id] = auth_key peer.rekeying = [2, action.exchange_id] g_b = pow(dh_config.g, b, dh_config.p) self.check_g_a(g_b, dh_config.p) message = DecryptedMessageService( action=DecryptedMessageActionAcceptKey( g_b=g_b.to_bytes(256, 'big', signed=False), exchange_id=action.exchange_id, key_fingerprint=key_fingerprint)) message = await self.encrypt_secret_message(peer, message) await self.client( SendEncryptedServiceRequest( InputEncryptedChat(peer.id, peer.access_hash), message))
async def notify_layer(self, peer: [int, SecretChat, InputEncryptedChat, EncryptedChat]): peer = self.get_secret_chat(peer) if peer.layer == 8: return message = DecryptedMessageService8(action=DecryptedMessageActionNotifyLayer( layer=min(DEFAULT_LAYER, peer.layer)), random_bytes=os.urandom(15 + 4 * random.randint(0, 2))) data = await self.encrypt_secret_message(peer.id, message) return await self.client( SendEncryptedServiceRequest(peer=InputEncryptedChat(peer.id, peer.access_hash), data=data))
async def finish_secret_chat_creation(self, chat): dh_config = await self.get_dh_config() g_a_or_b = int.from_bytes(chat.g_a_or_b, "big", signed=False) self.check_g_a(g_a_or_b, dh_config.p) a = self.session.get_temp_secret_chat_by_id(chat.id).auth_key a = int.from_bytes(a, "big", signed=False) auth_key = pow(g_a_or_b, a, dh_config.p).to_bytes( 256, "big", signed=False) self.session.remove_secret_chat_by_id(chat.id, True) key_fingerprint = struct.unpack('<q', sha1(auth_key).digest()[-8:])[0] if key_fingerprint != chat.key_fingerprint: raise ValueError("Wrong fingerprint") input_peer = InputEncryptedChat(chat_id=chat.id, access_hash=chat.access_hash) SecretChat(chat.id, chat.access_hash, auth_key, True, chat.participant_id, input_peer, session=self.session).save() await self.notify_layer(chat)
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.client(SendEncryptedServiceRequest(InputEncryptedChat(peer.id, peer.access_hash), message)) return e
def get_temp_secret_chat_by_id(self, id): row = self._execute( f"select * from {TABLE_NAME} where temp=1 and id = ?", id) if row: input_chat = InputEncryptedChat(chat_id=row[0], access_hash=row[1]) return SecretChat(id=row[0], access_hash=row[1], auth_key=row[2], admin=True if row[3] else False, user_id=row[4], in_seq_no_x=row[5], out_seq_no_x=row[6], in_seq_no=row[7], out_seq_no=row[8], layer=row[9], ttl=row[10], ttr=row[11], updated=row[12], created=row[13], mtproto=row[14], input_chat=input_chat)