def _authenticate_and_send_msg(self, username, chat_msg): # start peer authentication nonce = util.get_good_nonce(self.request_cache) new_auth = ClientClientAuthentication(username, self.auth.crypto_service, chat_msg) new_auth.timestamp = PacketOrganiser.get_new_timestamp() # timestamp when created, for packet resend key = self.auth.dh_key msg_to_send = PacketOrganiser.prepare_packet([c.MSG_TYPE_START_NEW_CHAT, username, ""], nonce=nonce) util.add_to_request_cache( self.request_cache, nonce, c.MSG_TYPE_START_NEW_CHAT, key, msg_to_send, self.auth.server_addr, new_auth ) # add to cache return username, self.auth.server_addr, self.serv.sym_encrypt(key, msg_to_send)
def run_client(server_ip, server_port): """ Main function to start the client. server_ip: IP address of the server server_port: port number which server uses to communicate """ global server_auth, user_addr_dict, active_users g = 2 p = util.load_df_param_from_file(c.DH_CONFIG_PATH) crypto_service = CryptoService(rsa_pub_path=c.PUB_KEY_PATH, p=p, g=g) server_addr = (server_ip, server_port) sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) client_port = server_port + 1 local_ip = socket.gethostbyname(socket.gethostname()) client_addr = (local_ip, client_port) # try to find a available local port port_found = False while not port_found: try: sock.bind(client_addr) port_found = True except socket.error: client_addr = (client_addr[0], client_addr[1] + 1) continue server_auth = ClientServerAuthentication(client_addr, server_addr, crypto_service) try: server_auth.authenticate_with_server(sock) except socket.error: print Consts.FAIL_GRE_MSG return chat_service = ClientChattingService(active_users, server_auth) # start a background to handle user input t_listen = ListenThread(sock, server_addr) t_listen.start() # start a background to resend message t_resend = ResendThread(sock, request_cache) t_resend.start() sys.stdout.write(Consts.PROMPT) sys.stdout.flush() while True: try: # listening to the server and display the message recv_msg, r_addr = sock.recvfrom(20480) if r_addr == server_addr and recv_msg: dec_msg = crypto_service.sym_decrypt(server_auth.dh_key, recv_msg) n, msg_ps = PacketOrganiser.process_packet(dec_msg) # first check if it's a client/client authentication # response from server if n in request_cache: # check the type of request cache = request_cache[n] request_type = cache[c.CACHE_TYPE_IND] if request_type == c.MSG_TYPE_LOGOUT: # process logout confirmation if msg_ps[0] == c.MSG_RESPONSE_OK: request_cache.pop(n) break elif request_type == c.MSG_TYPE_START_NEW_CHAT: # process the auth response from server cur_auth = cache[c.CACHE_AUTH_IND] assert isinstance(cur_auth, ClientClientAuthentication) b_addr = cur_auth.start_authenticate(sock, msg_ps, server_auth.username) user_addr_dict[cur_auth.username] = b_addr addr_auths[b_addr] = cur_auth request_cache.pop(n) elif request_type == c.MSG_TYPE_LIST: # process the user list form server chat_service.process_message(msg_ps) request_cache.pop(n) elif request_type == c.ERR_CLIENT_DOWN: print(c.ERR_CLIENT_DOWN) request_cache.pop(n) elif r_addr in addr_auths: #Reply or chat request from client cur_auth = addr_auths[r_addr] dec_msg = crypto_service.sym_decrypt(cur_auth.dh_key, recv_msg) n, dec_msg_parts = PacketOrganiser.process_packet(dec_msg) type = dec_msg_parts[0] if cur_auth.auth_success: if type == c.MSG_RESPONSE_OK: if n in request_cache: cache = request_cache[n] request_type = cache[c.CACHE_TYPE_IND] if request_type == c.MSG_TYPE_MSG: request_cache.pop(n) continue elif type == c.MSG_TYPE_MSG: # display user message msg_hmac = dec_msg_parts[1] # check the HMAC msg, sign = PacketOrganiser.divide_signature(msg_hmac) if CryptoService.verify_hmac_sign(cur_auth.dh_key, msg, sign): util.display_user_message(msg, cur_auth.username) # send message confirmation back util.send_confirmation(sock, crypto_service, cur_auth.dh_key, n, r_addr) else: # deal with peer auth success msg if type == c.MSG_RESPONSE_OK: if n in request_cache: cache = request_cache[n] request_type = cache[c.CACHE_TYPE_IND] if request_type == c.MSG_TYPE_PUB_KEY: # verify nonce if n != cur_auth.last_nonce: continue else: cur_auth.auth_success = True request_cache.pop(n) # check the HMAC msg_hmac = dec_msg_parts[1] msg, sign = PacketOrganiser.divide_signature(msg_hmac) if CryptoService.verify_hmac_sign(cur_auth.dh_key, msg, sign): # display user message util.display_user_message(msg, cur_auth.username) # send message confirmation back util.send_confirmation(sock, crypto_service, cur_auth.dh_key, n, r_addr) elif type == c.MSG_TYPE_PUB_KEY: # finish peer authentication on Alice side b_pub_key = int(dec_msg_parts[1]) cur_auth.dh_key = crypto_service.get_dh_secret(cur_auth.pri_key, b_pub_key) cur_auth.auth_success = True cur_auth.last_nonce = n # send confirmation and first message to Bob hmac = CryptoService.generate_hmac_sign(cur_auth.dh_key, cur_auth.first_msg) first_msg_hmac = cur_auth.first_msg + hmac conf_msg_parts = [c.MSG_RESPONSE_OK, first_msg_hmac, ""] conf_msg = PacketOrganiser.prepare_packet(conf_msg_parts, n) enc_conf_msg = crypto_service.sym_encrypt(cur_auth.dh_key, conf_msg) # add to request cache # a hack here (TYPE_MSG instead of RESPONSE_OK) to make the confirmation work util.add_to_request_cache(request_cache, n, c.MSG_TYPE_MSG, cur_auth.dh_key, conf_msg, r_addr) sock.sendto(enc_conf_msg, r_addr) else: # the r_addr not in user_addr_dict, this can be a TTB # handle TTB from Alice _, msg_ps = PacketOrganiser.process_packet(recv_msg) signed_ttb, enc_inside_msg, _ = msg_ps ttb = signed_ttb[:-c.RSA_SIGN_LENGTH] sign = signed_ttb[-c.RSA_SIGN_LENGTH:] if not crypto_service.rsa_verify(ttb, sign): raise Exception(c.WARNING_TTB_INVALID) dec_ttb = crypto_service.sym_decrypt(server_auth.dh_key, ttb) _, ttb_parts = PacketOrganiser.process_packet(dec_ttb) # a_username, a_addr, k_ab a_username_ttb, a_addr, k_ab = ttb_parts a_addr = util.str_to_addr(a_addr) # decrypt inside message with k_ab dec_inside_msg = crypto_service.sym_decrypt(k_ab, enc_inside_msg) _, inside_msg_parts = PacketOrganiser.process_packet(dec_inside_msg) a_username, a_pub_key, _ = inside_msg_parts # print("username_ttb: {}, a_username: {}".format(a_username_ttb, a_username)) if a_username_ttb != a_username: raise Exception(c.WARNING_TTB_USERNAME_INVALID) new_auth = ClientClientAuthentication(a_username, crypto_service) pri_key = crypto_service.get_dh_pri_key() pub_key = crypto_service.get_dh_pub_key(pri_key) new_auth.dh_key = crypto_service.get_dh_secret(pri_key, int(a_pub_key)) nonce = util.get_good_nonce(request_cache) new_auth.last_nonce = nonce # send pub key to Alice msg_parts = [c.MSG_TYPE_PUB_KEY, pub_key, ""] plain_msg = PacketOrganiser.prepare_packet(msg_parts, nonce) enc_msg = crypto_service.sym_encrypt(k_ab, plain_msg) sock.sendto(enc_msg, a_addr) # add new auth to dict addr_auths[a_addr] = new_auth user_addr_dict[a_username] = a_addr util.add_to_request_cache(request_cache, nonce, c.MSG_TYPE_PUB_KEY, k_ab, plain_msg, a_addr) # add to request cache except socket.error: # sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # sock.bind(client_addr) continue except KeyboardInterrupt: # when seeing ctrl-c terminate the client t_listen.stop() t_listen.join() t_resend.stop() t_resend.join() print c.BYE server_auth.logout(sock) sock.close() return except: pass t_listen.stop() t_listen.join() t_resend.stop() t_resend.join() print c.BYE server_auth.logout(sock) sock.close()
def run_client(server_ip, server_port): """ Main function to start the client. server_ip: IP address of the server server_port: port number which server uses to communicate """ global server_auth, user_addr_dict, active_users g = 2 p = util.load_df_param_from_file(c.DH_CONFIG_PATH) crypto_service = CryptoService(rsa_pub_path=c.PUB_KEY_PATH, p=p, g=g) server_addr = (server_ip, server_port) sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) client_port = server_port + 1 local_ip = socket.gethostbyname(socket.gethostname()) client_addr = (local_ip, client_port) # try to find a available local port port_found = False while not port_found: try: sock.bind(client_addr) port_found = True except socket.error: client_addr = (client_addr[0], client_addr[1] + 1) continue server_auth = ClientServerAuthentication(client_addr, server_addr, crypto_service) try: server_auth.authenticate_with_server(sock) except socket.error: print Consts.FAIL_GRE_MSG return chat_service = ClientChattingService(active_users, server_auth) # start a background to handle user input t_listen = ListenThread(sock, server_addr) t_listen.start() # start a background to resend message t_resend = ResendThread(sock, request_cache) t_resend.start() sys.stdout.write(Consts.PROMPT) sys.stdout.flush() while True: try: # listening to the server and display the message recv_msg, r_addr = sock.recvfrom(20480) if r_addr == server_addr and recv_msg: dec_msg = crypto_service.sym_decrypt(server_auth.dh_key, recv_msg) n, msg_ps = PacketOrganiser.process_packet(dec_msg) # first check if it's a client/client authentication # response from server if n in request_cache: # check the type of request cache = request_cache[n] request_type = cache[c.CACHE_TYPE_IND] if request_type == c.MSG_TYPE_LOGOUT: # process logout confirmation if msg_ps[0] == c.MSG_RESPONSE_OK: request_cache.pop(n) break elif request_type == c.MSG_TYPE_START_NEW_CHAT: # process the auth response from server cur_auth = cache[c.CACHE_AUTH_IND] assert isinstance(cur_auth, ClientClientAuthentication) b_addr = cur_auth.start_authenticate( sock, msg_ps, server_auth.username) user_addr_dict[cur_auth.username] = b_addr addr_auths[b_addr] = cur_auth request_cache.pop(n) elif request_type == c.MSG_TYPE_LIST: # process the user list form server chat_service.process_message(msg_ps) request_cache.pop(n) elif request_type == c.ERR_CLIENT_DOWN: print(c.ERR_CLIENT_DOWN) request_cache.pop(n) elif r_addr in addr_auths: #Reply or chat request from client cur_auth = addr_auths[r_addr] dec_msg = crypto_service.sym_decrypt(cur_auth.dh_key, recv_msg) n, dec_msg_parts = PacketOrganiser.process_packet(dec_msg) type = dec_msg_parts[0] if cur_auth.auth_success: if type == c.MSG_RESPONSE_OK: if n in request_cache: cache = request_cache[n] request_type = cache[c.CACHE_TYPE_IND] if request_type == c.MSG_TYPE_MSG: request_cache.pop(n) continue elif type == c.MSG_TYPE_MSG: # display user message msg_hmac = dec_msg_parts[1] # check the HMAC msg, sign = PacketOrganiser.divide_signature(msg_hmac) if CryptoService.verify_hmac_sign( cur_auth.dh_key, msg, sign): util.display_user_message(msg, cur_auth.username) # send message confirmation back util.send_confirmation(sock, crypto_service, cur_auth.dh_key, n, r_addr) else: # deal with peer auth success msg if type == c.MSG_RESPONSE_OK: if n in request_cache: cache = request_cache[n] request_type = cache[c.CACHE_TYPE_IND] if request_type == c.MSG_TYPE_PUB_KEY: # verify nonce if n != cur_auth.last_nonce: continue else: cur_auth.auth_success = True request_cache.pop(n) # check the HMAC msg_hmac = dec_msg_parts[1] msg, sign = PacketOrganiser.divide_signature( msg_hmac) if CryptoService.verify_hmac_sign( cur_auth.dh_key, msg, sign): # display user message util.display_user_message( msg, cur_auth.username) # send message confirmation back util.send_confirmation( sock, crypto_service, cur_auth.dh_key, n, r_addr) elif type == c.MSG_TYPE_PUB_KEY: # finish peer authentication on Alice side b_pub_key = int(dec_msg_parts[1]) cur_auth.dh_key = crypto_service.get_dh_secret( cur_auth.pri_key, b_pub_key) cur_auth.auth_success = True cur_auth.last_nonce = n # send confirmation and first message to Bob hmac = CryptoService.generate_hmac_sign( cur_auth.dh_key, cur_auth.first_msg) first_msg_hmac = cur_auth.first_msg + hmac conf_msg_parts = [ c.MSG_RESPONSE_OK, first_msg_hmac, "" ] conf_msg = PacketOrganiser.prepare_packet( conf_msg_parts, n) enc_conf_msg = crypto_service.sym_encrypt( cur_auth.dh_key, conf_msg) # add to request cache # a hack here (TYPE_MSG instead of RESPONSE_OK) to make the confirmation work util.add_to_request_cache(request_cache, n, c.MSG_TYPE_MSG, cur_auth.dh_key, conf_msg, r_addr) sock.sendto(enc_conf_msg, r_addr) else: # the r_addr not in user_addr_dict, this can be a TTB # handle TTB from Alice _, msg_ps = PacketOrganiser.process_packet(recv_msg) signed_ttb, enc_inside_msg, _ = msg_ps ttb = signed_ttb[:-c.RSA_SIGN_LENGTH] sign = signed_ttb[-c.RSA_SIGN_LENGTH:] if not crypto_service.rsa_verify(ttb, sign): raise Exception(c.WARNING_TTB_INVALID) dec_ttb = crypto_service.sym_decrypt(server_auth.dh_key, ttb) _, ttb_parts = PacketOrganiser.process_packet( dec_ttb) # a_username, a_addr, k_ab a_username_ttb, a_addr, k_ab = ttb_parts a_addr = util.str_to_addr(a_addr) # decrypt inside message with k_ab dec_inside_msg = crypto_service.sym_decrypt( k_ab, enc_inside_msg) _, inside_msg_parts = PacketOrganiser.process_packet( dec_inside_msg) a_username, a_pub_key, _ = inside_msg_parts # print("username_ttb: {}, a_username: {}".format(a_username_ttb, a_username)) if a_username_ttb != a_username: raise Exception(c.WARNING_TTB_USERNAME_INVALID) new_auth = ClientClientAuthentication(a_username, crypto_service) pri_key = crypto_service.get_dh_pri_key() pub_key = crypto_service.get_dh_pub_key(pri_key) new_auth.dh_key = crypto_service.get_dh_secret( pri_key, int(a_pub_key)) nonce = util.get_good_nonce(request_cache) new_auth.last_nonce = nonce # send pub key to Alice msg_parts = [c.MSG_TYPE_PUB_KEY, pub_key, ""] plain_msg = PacketOrganiser.prepare_packet(msg_parts, nonce) enc_msg = crypto_service.sym_encrypt(k_ab, plain_msg) sock.sendto(enc_msg, a_addr) # add new auth to dict addr_auths[a_addr] = new_auth user_addr_dict[a_username] = a_addr util.add_to_request_cache(request_cache, nonce, c.MSG_TYPE_PUB_KEY, k_ab, plain_msg, a_addr) # add to request cache except socket.error: # sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # sock.bind(client_addr) continue except KeyboardInterrupt: # when seeing ctrl-c terminate the client t_listen.stop() t_listen.join() t_resend.stop() t_resend.join() print c.BYE server_auth.logout(sock) sock.close() return except: pass t_listen.stop() t_listen.join() t_resend.stop() t_resend.join() print c.BYE server_auth.logout(sock) sock.close()