def notify_all_online_clients_about_new_list(client_dict, s, new_client_Details, username): clientList = [] new_client_temp = ClientDetailsInTransit(username, new_client_Details.port, new_client_Details.ip) clientList.append(new_client_temp) for client in client_dict: clientDetails = client_dict[client] if clientDetails.is_authenticated and client != username: byte_clientList = pickle.dumps(clientList) shared_key = clientDetails.key shared_nonce = clientDetails.nonce encrypted_clientList = encrypt_with_shared_key( shared_key, byte_clientList, shared_nonce) message_transit_dict = { 'message_type': 'NEW_CLIENT_NOTIFICATION', 'message': encrypted_clientList, 'hmac': 0 } data = pickle.dumps(message_transit_dict) s.sendto(data, (clientDetails.ip, clientDetails.port))
def process_client_messages(data, client_dict, address, s, s_key, nonce): # obtain the original Message Dict sent by the client message_dict = pickle.loads(data) message_type = message_dict['message_type'] # iff message type is Req to talk # iff the message is from a source which is in client dict then send back a nonce to the sender # set next message expected to SESSION_KEY_FROM_SERVER from the sender of this request if message_type == 'REQ_TO_TALK': #print "Recieved " + message_type + "\n" username = user_name_from_address(address, client_dict) if username is not None: client_details = client_dict[username] client_details.set_next_messages_expected( 'SESSION_KEY_FROM_SERVER') cookie = os.urandom(16) client_details.set_cookie(cookie) client_dict[username] = client_details send_message_to_client('NONCE', cookie, s, address, 0) else: client_details = Client_Details() client_details.set_ip(address[0]) client_details.set_port(address[1]) client_details.set_next_messages_expected( 'SESSION_KEY_FROM_SERVER') client_details.set_cookie(10) client_dict['new_client'] = client_details send_message_to_client('NONCE', 10, s, address, 0) # iff message type is NONCE # Check if the message is from a source recoginizable to the client # if the message type is an expected message from a client at the source # then send a MESSAGE_REQ to the server elif message_type == 'NONCE': #print "Recieved " + message_type + "\n" username = user_name_from_address(address, client_dict) if username is not None: client_details = client_dict[username] if is_message_type_ok(message_type, client_details): request_dict = { 'CLIENT_KEY_REQUIRED_FOR': username, 'NONCE': message_dict['message'] } send_encrypted_message_to_server('MESSAGE_REQ', request_dict, s, s_key, nonce) #send_message("MESSAGE_REQ","",username,s) #client_details.set_next_messages_expected('DH-KEY-C') client_dict[username] = client_details # iff the message type is DH-KEY-C # iff the message type is in the expected list of messages from the source then # decrypt the DH-KEY of the client from the payload if the message # compute the diffie hellman shared key # Encrypt a random number and send it back to the client elif message_type == 'DH-KEY-C': #print "Recieved " + message_type + "\n" username = user_name_from_address(address, client_dict) if username is not None: client_details = client_dict[username] if is_message_type_ok(message_type, client_details): #decrypt_message using common key encrypted_sender_dh_key = message_dict['message'] common_key = client_details.key common_nonce = client_details.nonce d1 = client_details.dh_key byte_dh_key = decrypt_with_common_key(common_key, encrypted_sender_dh_key, common_nonce) #verify the hmac for integrity check if not verify_hmac_with_common_key(common_key, byte_dh_key, message_dict['hmac']): print "Hmac verification failed" return # convert back to the format d2_pubkey = pickle.loads(byte_dh_key) shared_key_with_client = d1.gen_shared_key(d2_pubkey) shared_nonce = client_details.nonce_client #encrypt a random number and store it in the cookie random_number = os.urandom(16) client_details.set_cookie(random_number) encrypted_random_number = encrypt_with_shared_key( shared_key_with_client, random_number, shared_nonce) h_mac = get_hmac_from_shared_key(shared_key_with_client, random_number) send_message_to_client("CLIENT_CHALLENGE", encrypted_random_number, s, address, h_mac) client_details.set_next_messages_expected( 'CLIENT_RESPONSE_CHALLENGE') client_details.set_key(shared_key_with_client) client_details.set_nonce(shared_nonce) client_dict[username] = client_details # if the message type is SESSION_KEY_FROM_SERVER # iff the message type is expected from the client then # Obtain the ticket from the message and decrypt the ticket # Check if the nonce inside the ticket is the same as the nonce it sent # to the sender of this message # then encrypt the Diffie hellman public key and send it back to the client # also compute the shared diffie hellman key from the public key the sender of this # message sent elif message_type == 'SESSION_KEY_FROM_SERVER': #print "Recieved " + message_type + "\n" username = user_name_from_address(address, client_dict) if username is not None: client_details = client_dict[username] if is_message_type_ok(message_type, client_details): # decrypt the message from the message_dict response_dict = message_dict['message'] encrypted_ticket = response_dict['COMMON_KEY_TICKET'] byte_ticket = decrypt_with_shared_key(s_key, encrypted_ticket, nonce) ticket = get_original_message_from_byte(byte_ticket) common_key = ticket['common_key'] common_nonce = ticket['common_nonce'] client_name = ticket['key_for'] nonce_for_verification = ticket['NONCE_FOR_VERIFICATION'] if nonce_for_verification != client_details.cookie: print "Nonce sent to Client not same as not recieved inside ticket" return if client_name != username: return d1 = pyDH.DiffieHellman(5) d1_pubkey = d1.gen_public_key() decoded_key = pickle.dumps(d1_pubkey) # encrypt the Public key of the diffie hellman exchange with common key and nonce in the ticket encrypted_dh_key = encrypt_with_common_key( common_key, decoded_key, common_nonce) h_mac = get_hmac_from_common_key(common_key, decoded_key) send_message_to_client("DH-KEY-C", encrypted_dh_key, s, address, h_mac) #decrypt the diffie hellman key sent by the client using the common key in the ticket encrypted_sender_dh_key = response_dict['DH-KEY-C'] byte_dh_key = decrypt_with_common_key(common_key, encrypted_sender_dh_key, common_nonce) #convert back to the format d2_pubkey = pickle.loads(byte_dh_key) shared_key_with_client = d1.gen_shared_key(d2_pubkey) shared_nonce = response_dict['NONCE'] client_details.set_next_messages_expected("CLIENT_CHALLENGE") client_details.set_key(shared_key_with_client) client_details.set_nonce(shared_nonce) client_dict[username] = client_details # if the message type is CLIENT_CHALLENGE # iff it is in the list of expected messages for the sender of this message # then decrypt the challenge ,verify the hmac # encrypt the incoming challenge number and new number and send it back to the sender of this message # also store the new number so that it can be used to verify when the sends back the challenge elif message_type == 'CLIENT_CHALLENGE': #print "Recieved " + message_type + "\n" username = user_name_from_address(address, client_dict) if username is not None: client_details = client_dict[username] if is_message_type_ok(message_type, client_details): key = client_details.key nonce = client_details.nonce decrypted_challenge = decrypt_with_shared_key( key, message_dict['message'], nonce) # verify the hmac if not verify_hmac_with_shared_key(key, decrypted_challenge, message_dict['hmac']): print "Hmac verification failed while decrypting the challenge" return #generate random number random_number = os.urandom(16) client_details.set_cookie(random_number) response_dict = { 'CHALLENGE': random_number, "RESPONSE": decrypted_challenge } byte_data = pickle.dumps(response_dict) encrypted_data = encrypt_with_shared_key(key, byte_data, nonce) h_mac = get_hmac_from_shared_key(key, byte_data) send_message_to_client("CLIENT_RESPONSE_CHALLENGE", encrypted_data, s, address, h_mac) client_details.set_next_messages_expected("CLIENT_RESPONSE") client_dict[username] = client_details # if the message type is CLIENT_RESPONSE_CHALLENGE # iff it is in the list of expected messages for the sender of this message # then decrypt the message ,verify the hmac # Verify that the incoming message has the challenge which this client had sent to the sender # Create a new dictionary with the recieved challenge from the sender of this message and also the # original message stored in the temp message # encrypt this dictinary with the shared key and send it back elif message_type == 'CLIENT_RESPONSE_CHALLENGE': #print "Recieved " + message_type + "\n" username = user_name_from_address(address, client_dict) if username is not None: client_details = client_dict[username] if is_message_type_ok(message_type, client_details): key = client_details.key nonce = client_details.nonce byte_challage_response_dict = decrypt_with_shared_key( key, message_dict['message'], nonce) if not verify_hmac_with_shared_key( key, byte_challage_response_dict, message_dict['hmac']): print "Hmac vertification failed while recieving Client Response Challege" return challenge_response_dict = get_original_message_from_byte( byte_challage_response_dict) if (client_details.cookie != challenge_response_dict['RESPONSE']): print "Response not correct" return #new challenge response dict - send back the challenge and the message originally sent new_challeng_response_dict = { 'CHALLENGE_RESPONSE': challenge_response_dict['CHALLENGE'], 'CONV': client_details.temp_message } byte_new_challenge_response_dict = pickle.dumps( new_challeng_response_dict) encrypted_new_challenge_response_dict = encrypt_with_shared_key( key, byte_new_challenge_response_dict, nonce) h_mac = get_hmac_from_shared_key( key, byte_new_challenge_response_dict) send_message_to_client("CLIENT_RESPONSE", encrypted_new_challenge_response_dict, s, address, h_mac) client_details.set_next_messages_expected("CONV") client_details.set_temp_message('') client_details.set_is_authenticated(True) #print "Setting authenticated to true" client_dict[username] = client_details # if the message type is CLIENT_RESPONSE # iff it is in the expected message type for the sender of this message then # decrypt the message # verify the hmac # Check that the message contains the challenge number which this client had sent to the server # Also display the CONV message on the screen elif message_type == 'CLIENT_RESPONSE': #print "Recieved " + message_type + "\n" username = user_name_from_address(address, client_dict) if username is not None: client_details = client_dict[username] if is_message_type_ok(message_type, client_details): key = client_details.key nonce = client_details.nonce decrypted_response = decrypt_with_shared_key( key, message_dict['message'], nonce) if not verify_hmac_with_shared_key(key, decrypted_response, message_dict['hmac']): print "Hmac verification failed when recieving client resonse" return challenge_response_dict = get_original_message_from_byte( decrypted_response) if (challenge_response_dict['CHALLENGE_RESPONSE'] != client_details.cookie): print "Challenge Verification Failed" return client_details.set_next_messages_expected("CONV") client_details.set_is_authenticated(True) #print "Setting authenticated to true" print "Message From " + username + " : " + challenge_response_dict[ 'CONV'] client_dict[username] = client_details # iff the message type is CONV then # iff it is in the expected list of messages # Decrypt the message and verify the hmac # Print the message on the screen elif message_type == 'CONV': #print "Recieved " + message_type + "\n" username = user_name_from_address(address, client_dict) clientDetails = client_dict[username] if not is_message_type_ok(message_type, clientDetails): return decrypted_message = decrypt_with_shared_key(clientDetails.key, message_dict['message'], clientDetails.nonce) if not verify_hmac_with_shared_key( clientDetails.key, decrypted_message, message_dict['hmac']): print "Hmac vertification failed for the message recieved" return print "Message From : " + username + ' : ' + decrypted_message + '\n'
def send_input_msg(s, client_dict, s_key, nonce, username, kill_flag): try: while (1): if len(kill_flag) == 1: sys.exit(0) raw_answer = raw_input("\nEnter the message :") answer_list = raw_answer.split(" ") input_length = len(answer_list) command = answer_list[0] # If the command is list then # send an encrypted message to the server asking to list all the online clients if command == 'list': send_encrypted_message_to_server('LIST', command, s, s_key, nonce) # If the command is send # check if the second input in the user input is a username in the client list , else ignore # iff the username is a valid client who is online check if the client has been authenticated # authenticated here implies that a session key has been established with the client in question # if authenticated then directly send the CONV message # if not then send a REQ_TO_TALK message to the client elif command == 'send': client_name = answer_list[1] if client_name == username: continue if client_name in client_dict: clientDetails = client_dict[client_name] ts = "" for string in answer_list[2:input_length]: ts = ts + " " + string if clientDetails.is_authenticated: encrypted_message = encrypt_with_shared_key( clientDetails.key, ts, clientDetails.nonce) h_mac = get_hmac_from_shared_key(clientDetails.key, ts) send_message_to_client( "CONV", encrypted_message, s, (clientDetails.ip, clientDetails.port), h_mac) else: send_message_to_client( "REQ_TO_TALK", "", s, (clientDetails.ip, clientDetails.port), 0) clientDetails.set_next_messages_expected('NONCE') # store the input message in the temp message attribute for later use (after the session key exchange) clientDetails.set_temp_message(ts) client_dict[client_name] = clientDetails # if the command is logout then send the logout message to the server elif command == 'logout': send_encrypted_message_to_server('LOGOUT', command, s, s_key, nonce) # remove all client related details and exit for client in client_dict: client_dict[client] = Client_Details() kill_flag.append(1) print "Logging Out" sys.exit(0) except socket.error, msg: print "Error while sending input" sys.exit()
def send_encrypted_message_to_server(message_type, message, s, s_key, nonce): s_message_dict = {'message_type': message_type, 'message': message} data = pickle.dumps(s_message_dict) encrypted_data = encrypt_with_shared_key(s_key, data, nonce) s.sendto(encrypted_data, (HOST, PORT))
def respond_to_authenticated_clients(s, client_dict, address, message): username = user_name_from_address(address, client_dict) if username is not None: # decrypt message client_details = client_dict[username] key = client_details.key nonce = client_details.nonce decrypted_message = decrypt_with_shared_key(key, message, nonce) message_dict = pickle.loads(decrypted_message) msg = message_dict['message'] # If message_type is of 'LIST" prepare a list of Online Clients # Encrypt the client list and send to the sender if message_dict['message_type'] == 'LIST': clientList = getCdtListFromDict(client_dict) byte_clientList = pickle.dumps(clientList) encrypted_clientList = encrypt_with_shared_key( key, byte_clientList, nonce) message_transit_dict = { 'message_type': 'LIST_ANSWER', 'message': encrypted_clientList, 'hmac': 0 } data = pickle.dumps(message_transit_dict) #data_encrypted = encrypt_with_shared_key(key,data,nonce) s.sendto(data, address) return client_dict # If message type is MESSAGE_REQ # Compute a common shared key and common nonce for encryption between the clients # Create dictionary for the client requesting the MESSAGE_REQ with common key, The username of the client which the sending client is requesting to talk to and the # common nonce used for encryption # Encrypt the above dictionary # Create a Dictionary for the ticket to the 2nd Client with common key,common nonce for encryption and the Nonce used for verification which it had sent to Client1 # Encrypt the above dictionary # Put the above encrypted dictionaries in one more dictionary called Response Dict and treat it as message payload # Prepare a message transit dictionary with Message Type as SESSION_KEY_FROM_SERVER , Response Dict as Message and send to the Requesting Client elif message_dict['message_type'] == 'MESSAGE_REQ': common_key = os.urandom(16) common_nonce = os.urandom(16) repsonse_for_client_requesting = { 'common_key': common_key, 'key_for': msg['CLIENT_KEY_REQUIRED_FOR'], 'common_nonce': common_nonce } byte_resonse_for_requested_client_dict = pickle.dumps( repsonse_for_client_requesting) encrypted_response_for_client_requesting = encrypt_with_shared_key( key, byte_resonse_for_requested_client_dict, nonce) ticket_to_requested_client = { 'common_key': common_key, 'key_for': username, 'common_nonce': common_nonce, 'NONCE_FOR_VERIFICATION': msg['NONCE'] } if msg['CLIENT_KEY_REQUIRED_FOR'] not in client_dict: return client_dict requested_client_details = client_dict[ msg['CLIENT_KEY_REQUIRED_FOR']] if not requested_client_details.is_authenticated: return client_dict ckey = requested_client_details.key cnonce = requested_client_details.nonce byte_ticket_to_requested_client = pickle.dumps( ticket_to_requested_client) encrypted_ticket_to_requested_client = encrypt_with_shared_key( ckey, byte_ticket_to_requested_client, cnonce) response_dict = { 'COMMON_KEY_RESPONSE': encrypted_response_for_client_requesting, 'COMMON_KEY_TICKET': encrypted_ticket_to_requested_client } message_transit_dict = { 'message_type': 'SESSION_KEY_FROM_SERVER', 'message': response_dict, 'hmac': 0 } data = pickle.dumps(message_transit_dict) s.sendto(data, address) return client_dict # If message type is LOGOUT then # Re instantiate the Client Details object for the client in Client Dict # Send the information that this client has logged out to all the online clients elif message_dict['message_type'] == 'LOGOUT': # set authenticated to false and set the key to 0 # client_details = client_dict[username] # client_details.set_is_authenticated(False) # client_details.set_key(0) # client_dict[username] = client_details client_dict[username] = Client_Details() clientList = getCdtListFromDict(client_dict) #print len(clientList) for client in client_dict: clientDetails = client_dict[client] if clientDetails.is_authenticated: print "sending logout message to " + client encrypted_message = encrypt_with_shared_key( clientDetails.key, username, clientDetails.nonce) message_transit_dict = { 'message_type': 'LOGOUT_NOTIFICATION', 'message': encrypted_message, 'hmac': 0 } data = pickle.dumps(message_transit_dict) s.sendto(data, (clientDetails.ip, clientDetails.port)) return client_dict