def list_protocol(self, data): if len(data) != 1 : return # Parse uname and use it to find the shared key uname = data[0] shared_key = connected_clients[uname]['shared_key'] shared_iv = connected_clients[uname]['shared_iv'] # Create a nonce, encrypt it with the shared key, send it to the client nonce1 = Random.new().read( 32 ) encrypted_nonce1 = common.aes_encrypt(nonce1, shared_key, shared_iv) encrypt_msg = common.encode_msg([encrypted_nonce1]) data = common.send_and_receive(encrypt_msg, self.client_address, self.socket, 1024, 2) # Return if the nonce doesn't match user_nonce1 = base64.b64decode( data[0] ) if nonce1 != user_nonce1 : return encrypted_n2 = base64.b64decode( data[1] ) # Decrypt the client's nonce incr_shared_key = SHA256.new(str( common.increment_key(shared_key) )).digest() nonce2 = common.aes_decrypt(encrypted_n2, incr_shared_key, shared_iv) # Build the list of connected clients client_list = '' for key, value in connected_clients.iteritems(): client_list += key + ',' # Encrypt the list and send it to the client (along with the decrypted nonce) encrypted_client_list = common.aes_encrypt(client_list, shared_key, shared_iv) final_msg = common.encode_msg([nonce2, encrypted_client_list]) self.socket.sendto(final_msg, self.client_address)
def clock_sync_protocol(self): if len(data) != 1 : return # Parse uname and use it to find the shared key uname = data[0] shared_key = connected_clients[uname]['shared_key'] shared_iv = connected_clients[uname]['shared_iv'] # Create a nonce, encrypt it with the shared key, send it to the client nonce1 = Random.new().read( 32 ) encrypted_nonce1 = common.aes_encrypt(nonce1, shared_key, shared_iv) encrypt_msg = common.encode_msg([encrypted_nonce1]) data = common.send_and_receive(encrypt_msg, self.client_address, self.socket, 1024, 2) # Return if nonce doesn't match user_nonce1 = base64.b64decode( data[0] ) if nonce1 != user_nonce1 : return encrypted_n2 = base64.b64decode( data[1] ) # Decrypt the client's nonce incr_shared_key = SHA256.new(str( common.increment_key(shared_key) )).digest() nonce2 = common.aes_decrypt(encrypted_n2, incr_shared_key, shared_iv) # Get the current server timestamp and encrypt it timestamp = datetime.datetime.now().strftime(fmt) encrypted_timestamp = common.aes_encrypt(timestamp, shared_key, shared_iv) final_msg = common.encode_msg([nonce2, encrypted_timestamp]) self.socket.sendto(final_msg, self.client_address)
def send_message(self, user, msg): if self.authenticated_users.get(user) is None: self.get_ticket_from_server(user) # create hmac key for message shared_key = self.authenticated_users[user]['shared_key'] shared_iv = self.authenticated_users[user]['shared_iv'] user_addr = self.authenticated_users[user]['address'] self.authenticated_users[user]['sequence_n'] += 1 sequence_n = self.authenticated_users[user]['sequence_n'] hmac_key = hmac.new(shared_key, str(sequence_n) + ',' + msg).digest() msg = str(sequence_n) + ',' + msg encrypted_msg = common.aes_encrypt(msg, shared_key, shared_iv) send_msg = common.encode_msg([self.username, hmac_key, encrypted_msg]) self.sock.sendto('MESSAGE' + ',' + send_msg, user_addr)
def create_ticket(self, requested_user, requesting_user, shared_user_key): requesting_user_pub_key_str = self.get_user_pub_key(requesting_user).exportKey() requested_user_pub_key = self.get_user_pub_key(requested_user) requested_user_pub_key_str = requested_user_pub_key.exportKey() #requested_user_priv_key = self.get_user_priv_key(requested_user).exportKey() now = datetime.datetime.now() expiration_datetime = (now + datetime.timedelta(days=1)).strftime(fmt) # Create a signature iv = Random.new().read( 16 ) signature_msg = SHA256.new(str(iv)) signature = common.sign(signature_msg, server_priv_key) # Encrypt with public key of requested user encrypt_msg = common.encode_msg([iv, signature, shared_user_key, requesting_user, requesting_user_pub_key_str, expiration_datetime]) encrypted_keys, ciphertext = common.public_key_encrypt(encrypt_msg, requested_user_pub_key) return [encrypted_keys, ciphertext]
def ticket_protocol(self, data): if len(data) != 2 : return # Parse uname and use it to find the shared key uname = data[0] shared_key = connected_clients[uname]['shared_key'] shared_iv = connected_clients[uname]['shared_iv'] # Decrypt the requested user and timestamp msg = common.aes_decrypt(base64.b64decode(data[1]), shared_key, shared_iv).split(",",2) if len(msg) != 2 : return requested_user = msg[0] requested_user_ip = connected_clients[requested_user]['ip'] requested_user_port = str(connected_clients[requested_user]['port']) user_timestamp_str = '' user_timestamp = '' try: user_timestamp_str = msg[1] user_timestamp = datetime.datetime.strptime(msg[1], fmt) except ValueError: print "timestamp import issue" return # Verify timestamp is within acceptable range if common.verify_timestamp(user_timestamp, 5): # Lookup public key requested_user and create shared key requested_user_pub_key_str = self.get_user_pub_key(requested_user).exportKey() shared_user_key = self.create_shared_key() # Create ticket to requested_user encrypted_keys, ciphertext = self.create_ticket(requested_user, uname, shared_user_key) # Encrypt response with the shared key + 1 encrypt_msg = user_timestamp_str + ',' + requested_user + ',' + shared_user_key + ',' + encrypted_keys + ',' + \ ciphertext + ',' + requested_user_pub_key_str + ',' + requested_user_ip + ',' + requested_user_port incr_shared_key = SHA256.new(str( common.increment_key(shared_key) )).digest() encrypted_msg = common.aes_encrypt(encrypt_msg, incr_shared_key, shared_iv) # Encode the response (with ticket) and send it to the client final_msg = common.encode_msg([encrypted_msg]) self.socket.sendto(final_msg, self.client_address) else: print "Timestamp not current enough" return
def logout(self): try: self.sock.sendto("LOGOUT", self.server_address) dos_cookie = self.sock.recv(1024) # Compute current timestamp and encrypt timestamp = datetime.datetime.now().strftime(fmt) encrypted_timestamp = common.aes_encrypt(timestamp, self.shared_key, self.shared_iv) # Sign the message iv = Random.new().read( 16 ) signature_msg = SHA256.new(str(iv)) signature = common.sign(signature_msg, self.priv_key) # Send logout request send_msg_body = common.encode_msg([self.username, iv, signature, encrypted_timestamp]) send_msg = 'LOGOUT' + ',' + dos_cookie + ',' + send_msg_body data = common.send_and_receive(send_msg, self.server_address, self.sock, 2048, 3) if len(data) != 3 : return None decode_data = common.decode_msg(data) iv2 = decode_data[0] serv_signature = decode_data[1] encrypted_status = decode_data[2] # Verify server signature h = SHA256.new(str(iv2)) verifier = PKCS1_v1_5.new(server_pub_key) if verifier.verify(h, str(serv_signature)): # Decrypt status status = common.aes_decrypt(encrypted_status, self.shared_key, self.shared_iv) if status == "LOGOUTSUCCESS": print "Logout successful!" sys.exit() else: print "Logout failed" else: print "Logout failed - invalid signature" return except socket.timeout as e: print "Server is not responding" sys.exit()
def sync_clocks(self): # Send the "SYNC" server request self.sock.sendto("SYNC", self.server_address) # Receive the dos cookie dos_cookie = self.sock.recv(1024) # Send the dos cookie back, along with the username msg = "SYNC," + dos_cookie + "," + self.username self.sock.sendto(msg, (HOST, PORT)) # Receive an encrypted nonce and decrypt it encrypted_nonce = self.sock.recv(1024) decoded_encrypted_nonce = base64.b64decode(encrypted_nonce) decrypted_nonce = common.aes_decrypt(decoded_encrypted_nonce, self.shared_key, self.shared_iv) # Create a new nonce and encrypt with the shared key + 1 nonce2 = Random.new().read( 32 ) incr_shared_key = SHA256.new(str( common.increment_key(self.shared_key) )).digest() encrypted_nonce2 = common.aes_encrypt(nonce2, incr_shared_key, self.shared_iv) # Send the decrypted nonce and encrypted second nonce to the server send_msg = common.encode_msg([decrypted_nonce, encrypted_nonce2]) data = common.send_and_receive(send_msg, self.server_address, self.sock, 8192, 2) # Check the nonce serv_nonce2 = base64.b64decode( data[0] ) if serv_nonce2 != nonce2 : return encrypted_timestamp = base64.b64decode(data[1]) # Decrypt the timestamp timestamp_str = common.aes_decrypt(encrypted_timestamp, self.shared_key, self.shared_iv) timestamp = '' try: timestamp = datetime.datetime.strptime(timestamp_str, fmt) except ValueError: print "timestamp import issue" return # Not sure if this legal, please check it!!! time_offset = datetime.datetime.now() - timestamp
def get_client_list(self): # Send the "LIST" server request self.sock.sendto("LIST", self.server_address) # Receive the dos cookie dos_cookie = self.sock.recv(1024) # Send the dos cookie back, along with the username msg = "LIST," + dos_cookie + "," + self.username self.sock.sendto(msg, (HOST, PORT)) # Receive an encrypted nonce and decrypt it encrypted_nonce = self.sock.recv(1024) decoded_encrypted_nonce = base64.b64decode(encrypted_nonce) decrypted_nonce = common.aes_decrypt(decoded_encrypted_nonce, self.shared_key, self.shared_iv) # Create a new nonce and encrypt with the shared key + 1 nonce2 = Random.new().read( 32 ) incr_shared_key = SHA256.new(str( common.increment_key(self.shared_key) )).digest() encrypted_nonce2 = common.aes_encrypt(nonce2, incr_shared_key, self.shared_iv) # Send the decrypted nonce and encrypted second nonce to the server #send_msg = encoded_decrypted_nonce + "," + encrypted_nonce2 send_msg = common.encode_msg([decrypted_nonce, encrypted_nonce2]) data = common.send_and_receive(send_msg, self.server_address, self.sock, 8192, 2) # Check the nonce serv_nonce2 = base64.b64decode( data[0] ) if serv_nonce2 != nonce2 : return encrypted_unames = base64.b64decode(data[1]) # Decrypt and print names unames = common.aes_decrypt(encrypted_unames, self.shared_key, self.shared_iv) unames = unames.split(',') for name in unames: print name
def login_to_server(self, password): try: self.sock.sendto("LOGIN", self.server_address) dos_cookie = self.sock.recv(1024) # compute diffie hellman value and encrypt with password hash iv1 = Random.new().read( 16 ) dh = diffie_hellman.DiffieHellman() dh_key = str(dh.genPublicKey()) dh_val = common.aes_encrypt(dh_key, password, iv1) # Sign the message signature_msg = SHA256.new(str(self.username) + str(iv1)) signature = common.sign(signature_msg, self.priv_key) # Encrypt plaintext using server public key encrypt_msg = common.encode_msg([self.username, iv1, signature, dh_val]) encrypted_keys, ciphertext = common.public_key_encrypt(encrypt_msg, server_pub_key) send_msg = "LOGIN," + dos_cookie + "," + encrypted_keys + "," + ciphertext self.sock.settimeout(3) data = common.send_and_receive(send_msg, self.server_address, self.sock, 8192, 2) if len(data) != 2 : return None rec_msg = common.public_key_decrypt(data[0], data[1], self.priv_key) decoded_msg = common.decode_msg(rec_msg) iv2 = decoded_msg[0] signature = decoded_msg[1] encrypted_serv_dh_val = decoded_msg[2] nonce1 = decoded_msg[3] # Verify the signature h = SHA256.new(str(iv2)) verifier = PKCS1_v1_5.new(server_pub_key) if verifier.verify(h, str(signature)): # Decrypt server dh val server_dh_val = long(common.aes_decrypt(encrypted_serv_dh_val, password, iv2)) # Generate shared key dh.genKey(server_dh_val) shared_key = dh.getKey() # Encrypt nonce1 with our shared key nonce2 = Random.new().read( 32 ) iv3 = Random.new().read( 16 ) encrypted_n1 = common.aes_encrypt(nonce1, shared_key, iv3) # Encrypt mesage with pub key of the server encrypt_msg = common.encode_msg([iv3, encrypted_n1, nonce2]) encrypted_keys, ciphertext = common.public_key_encrypt(encrypt_msg, server_pub_key) # Send message send_msg = encrypted_keys + ',' + ciphertext data = common.send_and_receive(send_msg, self.server_address, self.sock, 4096, 2) if len(data) != 2 : return None rec_msg = common.public_key_decrypt(data[0], data[1], self.priv_key) decoded_msg = common.decode_msg(rec_msg) iv4 = decoded_msg[0] encrypted_serv_nonce2 = decoded_msg[1] # Verify user nonce1 value matches the value we sent serv_nonce2 = common.aes_decrypt(encrypted_serv_nonce2, shared_key, iv4) if nonce2 == serv_nonce2: self.shared_key = shared_key self.shared_iv = iv4 print "Successfully logged in!" else: self.shared_key = None print "Login unsuccessful" sys.exit() else: print "Server could not be verified" sys.exit() except socket.timeout as e: print "Server is not responding" sys.exit()
def handle_request(self, data, addr): data = data.split(',', 4) if data[0] == 'AUTH': if len(data) != 3 : return # Decrypt message with our private key and break out message msg = common.public_key_decrypt(data[1], data[2], self.priv_key) decoded_msg = common.decode_msg(msg) connected_uname = decoded_msg[0] encr_ticket_key = decoded_msg[1] encr_ticket_ciphert = decoded_msg[2] iv2 = decoded_msg[3] signature = decoded_msg[4] encrypted_nonce = decoded_msg[5] # Decrypt ticket ticket = common.public_key_decrypt(encr_ticket_key, encr_ticket_ciphert, self.priv_key) ticket = common.decode_msg(ticket) if len(ticket) != 6 : return iv = ticket[0] serv_signature = ticket[1] shared_user_key = ticket[2] requesting_user = ticket[3] requesting_user_pub_key_str = ticket[4] expiration_datetime_str = ticket[5] # Verify ticket is not expired and username from ticket matches requesting username expiration_timestamp = '' try: expiration_timestamp = datetime.datetime.strptime(expiration_datetime_str, fmt) except ValueError: return # Check offset!!! if common.is_timestamp_current(expiration_timestamp + time_offset) != True : return if requesting_user != connected_uname: return # Verify server's signature h = SHA256.new(str(iv)) verifier = PKCS1_v1_5.new(server_pub_key) if verifier.verify(h, str(serv_signature)): # Now verify signature of initiating user requesting_user_pub_key = RSA.importKey(requesting_user_pub_key_str) h = SHA256.new(str(iv2)) verifier = PKCS1_v1_5.new(requesting_user_pub_key) if verifier.verify(h, str(signature)): # Create signature iv3 = Random.new().read( 16 ) signature_msg = SHA256.new(str(iv3)) signature = common.sign(signature_msg, self.priv_key) # Add user to authenticated users self.authenticated_users[requesting_user]['shared_key'] = shared_user_key self.authenticated_users[requesting_user]['shared_iv'] = iv3 self.authenticated_users[requesting_user]['sequence_n'] = int(iv3.encode('hex'), 16) self.authenticated_users[requesting_user]['address'] = addr # Now decrypt nonce, and encrypt back with kab + 1 nonce = common.aes_decrypt(encrypted_nonce, shared_user_key, iv2) incr_shared_key = SHA256.new(str( common.increment_key(shared_user_key) )).digest() our_encrypted_nonce = common.aes_encrypt(nonce, incr_shared_key, iv3) # Send final message back to initiating user, encrypted with their pub key encrypt_msg = common.encode_msg([iv3, signature, our_encrypted_nonce]) encrypted_keys, ciphertext = common.public_key_encrypt(encrypt_msg, requesting_user_pub_key) send_msg = encrypted_keys + "," + ciphertext self.sock.sendto(send_msg, addr) else: return return if data[0] == 'MESSAGE': if len(data) != 4 : return decoded_msg = common.decode_msg(data[1:]) if len(decoded_msg) != 3 : return connected_uname = decoded_msg[0] user_hmac_key = decoded_msg[1] encrypted_msg = decoded_msg[2] # Retrieve session info for user if self.authenticated_users.get(connected_uname) == None : return shared_key = self.authenticated_users[connected_uname]['shared_key'] shared_iv = self.authenticated_users[connected_uname]['shared_iv'] user_addr = self.authenticated_users[connected_uname]['address'] self.authenticated_users[connected_uname]['sequence_n'] += 1 sequence_n = self.authenticated_users[connected_uname]['sequence_n'] # Decrypt message msg = common.aes_decrypt(encrypted_msg, shared_key, shared_iv).split(',',1) if len(msg) != 2 : return user_seq_n = msg[0] user_msg = msg[1] # Verify sequence number matches our sequence number if user_seq_n != str(sequence_n) : return # Verify hmac key hmac_key = hmac.new(shared_key, str(user_seq_n) + ',' + user_msg).digest() if user_hmac_key != hmac_key : return print connected_uname + ': ' + user_msg return else: return
def get_ticket_from_server(self, user): try: self.sock.sendto("TICKET", self.server_address) dos_cookie = self.sock.recv(1024) # Request to talk to given user, sending current timestamp # Please not sure if adding the offset here is legal, please check!!! timestamp = (datetime.datetime.now() + time_offset).strftime(fmt) msg = user + "," + timestamp encrypted_msg = common.aes_encrypt(msg, self.shared_key, self.shared_iv) encoded_encrypted_msg = common.encode_msg([encrypted_msg]) # Send request to server send_msg = "TICKET," + dos_cookie + ',' + self.username + ',' + encoded_encrypted_msg self.sock.settimeout(5) data = common.send_and_receive(send_msg, self.server_address, self.sock, 16384, 1) if len(data) != 1 : return # Decrypt the message with shared key + 1 msg = base64.b64decode( data[0] ) incr_shared_key = SHA256.new(str( common.increment_key(self.shared_key) )).digest() msg = common.aes_decrypt(msg, incr_shared_key, self.shared_iv).split(',', 8) if len(msg) != 8 : return serv_timestamp = msg[0] serv_user_to_talk_to = msg[1] shared_key_ab = msg[2] encr_ticket_key = msg[3] encr_ticket_ciphert = msg[4] user_pk = msg[5] user_ip = msg[6] user_port = msg[7] # Not sure what to do with timestamp offset here!!! if serv_timestamp == timestamp and serv_user_to_talk_to == user: nonce = Random.new().read( 32 ) iv2 = Random.new().read( 16 ) signature_msg = SHA256.new(str(iv2)) signature = common.sign(signature_msg, self.priv_key) # Encrypt nonce with our shared key encrypted_nonce = common.aes_encrypt(nonce, shared_key_ab, iv2) # Encrypt mesage with pub key of the user user_pk = RSA.importKey(user_pk) encrypt_msg = common.encode_msg([self.username, encr_ticket_key, encr_ticket_ciphert, iv2, signature, encrypted_nonce]) encrypted_keys, ciphertext = common.public_key_encrypt(encrypt_msg, user_pk) user_address = (user_ip,int(user_port)) send_msg = "AUTH" + ',' + encrypted_keys + ',' + ciphertext data = common.send_and_receive(send_msg, user_address, self.sock, 2048, 2) if len(data) != 2 : return # Decrypt message with our private key and break out message msg = common.public_key_decrypt(data[0], data[1], self.priv_key) decoded_msg = common.decode_msg(msg) iv3 = decoded_msg[0] signature = decoded_msg[1] encrypted_nonce = decoded_msg[2] # Decrypt nonce with shared key + 1 incr_shared_key = SHA256.new(str( common.increment_key(shared_key_ab) )).digest() connected_nonce = common.aes_decrypt(encrypted_nonce, incr_shared_key, iv3) # Verify nonce is correct if connected_nonce == nonce: self.authenticated_users[serv_user_to_talk_to]['shared_key'] = shared_key_ab self.authenticated_users[serv_user_to_talk_to]['shared_iv'] = iv3 self.authenticated_users[serv_user_to_talk_to]['sequence_n'] = int(iv3.encode('hex'), 16) self.authenticated_users[serv_user_to_talk_to]['address'] = user_address return except socket.timeout as e: print "Server is not responding" sys.exit()
def login_protocol(self, data): if len(data) != 2 : return # Decrypt message with our private key and break out message msg = common.public_key_decrypt(data[0], data[1], server_priv_key) decoded_msg = common.decode_msg(msg) uname = decoded_msg[0] iv1 = decoded_msg[1] signature = decoded_msg[2] encrypted_dh_val = decoded_msg[3] if connected_clients.get(uname) is not None: return # Lookup public key of the user user_pub_key = self.get_user_pub_key(uname) # Verify the user's signature h = SHA256.new(str(uname) + str(iv1)) verifier = PKCS1_v1_5.new(user_pub_key) if verifier.verify(h, str(signature)): print "Signature Verified!" pass_hash = base64.b64decode( self.get_password_hash(uname) ) # Decrypt DH val diff_hell_val = long(common.aes_decrypt(encrypted_dh_val, pass_hash, iv1)) # Create random values nonce1 = Random.new().read( 32 ) iv2 = Random.new().read( 16 ) # Compute our diffie hellman value and encrypt with password hash dh = diffie_hellman.DiffieHellman() serv_dh_key = str(dh.genPublicKey()) serv_dh = common.aes_encrypt(serv_dh_key, pass_hash, iv2) # Establish shared key dh.genKey(diff_hell_val) shared_key = dh.getKey() # Sign the message signature_msg = SHA256.new(str(iv2)) signature = common.sign(signature_msg, server_priv_key ) # Encrypt with public key of user encrypt_msg = common.encode_msg([iv2, signature, serv_dh, nonce1]) encrypted_server_keys, ciphertext = common.public_key_encrypt(encrypt_msg, user_pub_key) # Send message send_msg = encrypted_server_keys + "," + ciphertext data = common.send_and_receive(send_msg, self.client_address, self.socket, 1024, 2) if len(data) != 2 : return rec_msg = common.public_key_decrypt(data[0], data[1], server_priv_key) decoded_msg = common.decode_msg(rec_msg) iv3 = decoded_msg[0] encrypted_user_nonce1 = decoded_msg[1] nonce2 = decoded_msg[2] # Verify user encrypted nonce1 with the shared key user_nonce1 = common.aes_decrypt(encrypted_user_nonce1, shared_key, iv3) if nonce1 == user_nonce1: print "Login Sucess for user: "******"Login Failure for user: "******"The signature is not authentic" return
except ConnectionRefusedError: print('### connecting to server failed. ###') raise SystemExit thread = Thread(target=receive, args=(tcp_socket, udp_socket), daemon=True) thread.start() while True: try: msg = input() except KeyboardInterrupt: tcp_socket.close() udp_socket.close() raise SystemExit if not msg: continue if '/exit' in msg: tcp_socket.close() udp_socket.close() raise SystemExit elif '/udp ' in msg: data = common.encode_msg(uid, msg.replace('/udp ', ' ')) udp_socket.sendto(data, common.serverAddr) elif '/udp_love' in msg: data = common.encode_msg(uid, inner_love) udp_socket.sendto(data, common.serverAddr) else: data = common.encode_msg(uid, msg) tcp_socket.sendall(data)