def encryption_setup(client, secrets=None): """ Set up encryption keys between server and client Args: client <socket object> - client socket Kwargs: secrets <Secrets object> - secret keys to be exchanged with client Return: client_secrets <Secrets object> - necessary keys received from client client_status <bytes> - status report from client after encryption setup is_encrypted <bool> - client's encryption status """ try: client.send(query_msg('Q:PUBKEY')) client_pubkey = client.recv(fc.BLOCK_SIZE // 2) client_secrets = Secrets.from_pubkey(client_pubkey) if client_secrets is None or not client_secrets.check_hash(): pass # TODO: close client connection client_secrets.sesskey = secrets.sesskey client.send( query_msg('Q:SESSION_KEY')) # signal for encrypted server keys server_keys = client_secrets.hybrid_encrypt(secrets.keys) client_status = client.recv(1024) client.send(server_keys) encryption_status = client.recv( 8) # get confirmation of encryption setup is_encrypted = bool(int(encryption_status)) return client_secrets, client_status, is_encrypted except Exception as ex: return None, None, False
def ask_for_username(client, encoding=fc.DEFAULT_ENC): """ Ask client for a valid username Args: client <socket object> - client socket Kwargs: encoding <str> - string coding Return: username <str> - received username """ client.send(query_msg('Q:USERNAME')) while True: username = client.recv(1024).decode(encoding) knowns = known_users() if not fc.ALLOW_UNKNOWN and username in knowns: break elif fc.ALLOW_UNKNOWN and username not in clients: break else: try: client.send(query_msg('Q:CHUSERNAME')) except BrokenPipeError: fab_log('EXIT', username) return None return username
def test_query_msg(self): """ # fabular.comm.query_msg """ for query in ['Q:USERNAME', 'Q:CHUSERNAME', 'Q:PUBKEY', 'Q:SESSION_KEY', 'Q:ACCEPT', 'Q:KILL']: self.printf(query) q = fcomm.query_msg(query) self.assertTrue(q) self.assertIsInstance(q, bytes) self.printout(q) msg = 'not a query' self.printf(msg) q = fcomm.query_msg(msg) self.assertFalse(q) self.assertIsInstance(q, bytes) self.printout(q)
def test_is_query(self): """ # fabular.comm.is_query """ for query in ['Q:USERNAME', 'Q:CHUSERNAME', 'Q:PUBKEY', 'Q:SESSION_KEY', 'Q:ACCEPT', 'Q:KILL']: msg = fcomm.query_msg(query) self.printf((msg, query)) is_q = fcomm.is_query(msg, query) self.assertIsInstance(is_q, bool) self.assertTrue(is_q) self.printout(is_q) query = 'not a query' msg = fcomm.query_msg(query) self.printf((msg, query)) is_q = fcomm.is_query(msg, query) self.assertFalse(is_q) self.assertIsInstance(is_q, bool) self.printout(is_q)
def handshake(server, secrets=None): """ Server main loop: Accept and set up new incoming connections Args: server <socket object> - server socket Kwargs: secrets <Secrets object> - secret keys to be exchanged with client Return: None """ global clients v = dict(verbose_mode=fc.VERBOSE) while True: try: client, address = server.accept() fab_log('CONN', address, **v) # set up username username = ask_for_username(client) if username: fab_log('USRN', username, **v) # encryption handshake client_secrets, status, is_encrypted = \ encryption_setup(client, secrets=secrets) if status: fab_log(status, verbose_mode=3) # add username to user table and current clients status = register_user(username, client, address, is_encrypted, client_secrets) if status == 0: fab_log('LERR', username) known = known_users() try: client.send(query_msg('Q:KILL')) client.close() except BrokenPipeError: pass continue # announce entry of user client.send(query_msg('Q:ACCEPT')) try: fab_log(client.recv(256), verbose_mode=3) broadcast(fab_msg('ENTR', username)) except UnicodeDecodeError: pass handle_thread = threading.Thread(target=handle, args=( server, username, )) handle_thread.daemon = True handle_thread.start() except KeyboardInterrupt: fab_log('ENDS', verbose_mode=3) return