def AES_decrypt(message, key, **kwargs): """ Decrypt a message using AES cipher Args: message <bytes> - message to be decrypted key <bytes> - session key of size 8 or 16 Kwargs: iv <bytes> - initialization vector iv_block <int> - size of the random initialization vector for CBC mode encoding <str> - string coding Return: msg_dec <bytes> - decrypted message """ if not message: return message if key is None: fab_log('Decryption requires a cipher key!', verbose_mode=4) return cipher = AES_from_key(key, **kwargs) dec_cipher = cipher.decryptor() msg_dec = dec_cipher.update(message) + dec_cipher.finalize() msg_dec = block_unpad(msg_dec) return msg_dec
def AES_encrypt(self, message, key=None, **kwargs): """ Fast AES encryption of a message Args: message <bytes> - message to be encrypted Kwargs: key <bytes> - session key of size 8 or 16 iv <bytes> - initialization vector iv_block <int> - size of the random initialization vector for CBC mode encoding <str> - string coding Return: msg_enc <bytes> - encrypted message """ if not message: return message key = self.key128 if key is None else key if self.key128 is None: fab_log('Encryption failed! Proceeding without encryption...', verbose_mode=4) return message msg_enc = AES_encrypt(message, key, **kwargs) return msg_enc
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 AES_from_key(key, iv=None, iv_block=16, encoding=fc.DEFAULT_ENC): """ Create an AES cipher from a key Args: key <bytes> - session key of size 8 or 16 Kwargs: iv <bytes> - initialization vector iv_block <int> - size of the random initialization vector for CBC mode encoding <str> - string coding Return: cipher <cryptography..Cipher object> - AES cipher """ if isinstance(key, str): key = key.encode(encoding) if len(key) == 8: key2 = key + key[::-1] elif len(key) == 16: key2 = key elif len(key) > 16: key2 = key[:16] else: fab_log('AES requires a cipher key of length of N16!', verbose_mode=5) return iv = iv if iv is not None else key2 AES_cipher = ciphers.Cipher(algorithm=ciphers.algorithms.AES(key2), mode=ciphers.modes.CBC(iv)) return AES_cipher
def test_fab_log(self): """ # fabular.comm.fab_log """ sys_keys = ['CONN', 'USRN', 'CUSR', 'DCRY', 'FDCR', 'WRYT', 'CHAT', 'ENTR', 'EXIT', 'INIS', 'ENDS'] for sys_key in sys_keys: self.printf((sys_key, '', {'verbose_mode': 3})) self.assertLogs(fcomm.fab_log(sys_key, '', verbose_mode=3))
def handle(server, client_key): """ Client connection handler Args: server <socket object> - server socket client_key <str> - client connected as USERNAME=client_key Kwargs/Return: None """ global clients while True: if client_key not in clients: break try: data = clients[client_key].recv(1024) if data: if clients.is_encrypted[client_key]: message = clients.secret[client_key].AES_decrypt(data) else: message = data.decode(fc.DEFAULT_ENC) message = fab_msg('CHAT', message, prefix='{}{}>{} '.format( ansi_map[clients.color[client_key]], client_key, ansi_map['reset']), suffix='') broadcast(message) except Exception as ex: client = clients.pop(client_key) if client: client.close() exit_msg = fab_msg('EXIT', client_key) broadcast(exit_msg) fab_log('fabular.server.handle: {}'.format(ex), verbose_mode=1) return
def Fernet_decrypt(self, message, key=None, **kwargs): """ Fernet decryption scheme Args: message <bytes> - message to be decrypted Kwargs: key <bytes> - Fernet session key encoding <str> - string coding Return: msg_dec <bytes> - decrypted message """ if not message: return message key = self.session if key is None else key if self.session is None: fab_log('Encryption failed! Proceeding without encryption...', verbose_mode=4) return message msg_dec = Fernet_decrypt(message, key, **kwargs) return msg_dec
def broadcast(data): """ Broadcast a message to all clients Args: data <bytes/str> - the message to be broadcast Kwargs/Return: None """ if isinstance(data, str): data = data.encode(fc.DEFAULT_ENC) for username in clients: if clients[username]: if clients.is_encrypted[username]: message = clients.secret[username].AES_encrypt(data) else: message = data try: clients[username].send(message) except Exception as ex: clients.pop(username) fab_log(data, verbose_mode=fc.VERBOSE)
def AES_decrypt(self, message, key=None, **kwargs): """ Fast AES decryption of a message Args: message <bytes> - message to be decrypted Kwargs: key <bytes> - session key of size 8 or 16 iv <bytes> - initialization vector iv_block <int> - size of the random initialization vector for CBC mode encoding <str> - string coding Return: msg_dec <str> - decrypted message """ if not message: return message key = self.key128 if key is None else key if self.key128 is None: fab_log('Decryption requires a cipher key!', verbose_mode=4) return message msg_dec = AES_decrypt(message, key, **kwargs) return msg_dec
def main(host=LOCALHOST, port=PORT): """ Start a listening server and handle incoming connections Args: None Kwargs: host <str> - host IP address port <int/str> - IP port Return: None """ global clients try: # Name definitions file_id = input('Session name: ') if not file_id: file_id = 'server' pw = pw_prompt(confirm=True) # RSA keys server_secrets = Secrets.random(file_id='server') server_secrets.pw = pw if not server_secrets.check_hash(): sys.exit() # Set up server socket clients = Clients() server = init_server(host, port, max_conn=16) fab_log('INIS', verbose_mode=3) # open ngrok tunnel tunnel = ngrok.connect(fc.PORT, "tcp") public_addr = tunnel.public_url pub_host, pub_port = public_addr.split(':')[1:] pub_host = pub_host[2:] fab_log(f"Opened tunnel @ --host {pub_host} --port {pub_port}...", verbose_mode=3) # start accept thread accept_thread = threading.Thread(target=handshake, args=( server, server_secrets, )) accept_thread.daemon = True accept_thread.start() accept_thread.join() except KeyboardInterrupt: fab_log('ENDS', verbose_mode=3)
def receive(client): """ Message recipience loop; handles special keys and reacts accordingly Args: client <socket.socket object> - client socket Kwargs/Return: None """ global username, client_secrets, accepted, decode, stop_threads while True: if stop_threads: break try: message = client.recv(fc.BLOCK_SIZE) if message: if is_query(message, 'Q:USERNAME'): client.send(username.encode(fc.DEFAULT_ENC)) elif is_query(message, 'Q:CHUSERNAME'): fab_log('CUSR', verbose_mode=3) username = input('Enter another username: '******'Q:PUBKEY'): client.send(client_secrets.pubkey) elif is_query(message, 'Q:SESSION_KEY'): if fc.ENCRYPTION: client.send(f'{username}: Setting up encryption...'.encode(fc.DEFAULT_ENC)) fab_log('DCRY', verbose_mode=3) enc_msg = client.recv(2*fc.BLOCK_SIZE) server_keys = client_secrets.hybrid_decrypt(enc_msg) server_secrets = Secrets.from_keys(server_keys) if server_secrets is not None: client_secrets.sesskey = server_secrets.sesskey decode = True client.send(b'1') else: fab_log('FDCR', verbose_mode=3) client.send(b'0') else: client.send(f'{username}: Proceed without encryption'.encode( fc.DEFAULT_ENC)) client.recv(2*fc.BLOCK_SIZE) server_secrets = Secrets() client.send(b'0') elif is_query(message, 'Q:ACCEPT'): client.send(f'{username}: Starting Thread(write)...'.encode(fc.DEFAULT_ENC)) fab_log('WRYT', verbose_mode=3) fab_log('', verbose_mode=3) accepted = True elif is_query(message, 'Q:KILL'): fab_log('LERR', verbose_mode=3) accepted = False stop_threads = True else: if decode: message = client_secrets.AES_decrypt(message) fab_log(message) except Exception as ex: fab_log('fabular.client.receive: {}'.format(ex), verbose_mode=5) stop_threads = True client.close() break
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