def print_user_list(self, input_array):
        if len(
                input_array
        ) > 1:  # List followed by anything is an invalid command and will not be processed
            print("Invalid Input!")
        else:
            nonce_l = str(time.time())
            message = nonce_l
            ct, iv, tag = symmetric_encryption(self.derived_key, message)
            signature = sign_message(self.private_key, ct)
            new_message = {
                "ciphertext": str(ct),
                "user": self.username,
                "command": "list",
                "iv": iv,
                "tag": tag,
                "signature": signature
            }

            self.sock.send(pickle.dumps(new_message))
            data_1 = self.sock.recv(self.BUFFER_SIZE)
            data = pickle.loads(data_1)
            users, ni, ni1 = symmetric_decryption(
                self.derived_key, data["iv"], data["tag"],
                data["ciphertext"]).split("\n")
            temp = ast.literal_eval(users)
            user_list = []
            for x in temp:
                if x != self.username:
                    user_list.append(x)
            if len(user_list) == 0:
                print "<-- No other users online"
            else:
                print("<-- Signed In Users: {0}").format(
                    ','.join(user_list))  # Print user list
    def receive_messages(self, connection_socket, address):
        try:
            while True:
                data = connection_socket.recv(self.BUFFER_SIZE)
                # if not data:
                #     break
                parsed_data = pickle.loads(data)
                if parsed_data["command"] == "login":
                    if self.registered_users.get(
                            parsed_data["username"]) is None:
                        connection_socket.send("User not registered")
                        continue
                    if self.users.get(parsed_data["username"]):
                        connection_socket.send("Already logged in")
                        continue
                    else:
                        cha = str(time.time()) + " " + str(random.random())
                        connection_socket.send(cha)
                        challenge = cha.split()
                        h1 = create_hash(challenge[0])
                        h2 = create_hash(challenge[1])
                        answer = str(
                            int(binascii.hexlify(h1), 16)
                            & int(binascii.hexlify(h2), 16))
                        data = connection_socket.recv(self.BUFFER_SIZE)
                        ans, username, password, salt, nonce_1 = asymmetric_decryption(
                            self.server_pvt_key, data).split("\n")
                        user_derived_key = generate_key_from_password(
                            password, salt)
                        if answer == ans and password == self.registered_users[
                                username]:
                            nonce_2 = str(time.time())
                            message = nonce_1 + "\n" + nonce_2
                            enc_msg, iv, tag = symmetric_encryption(
                                user_derived_key, message)
                            payload = {
                                "message": str(enc_msg),
                                "iv": str(iv),
                                "tag": str(tag)
                            }
                            connection_socket.send(pickle.dumps(payload))
                            data_1 = connection_socket.recv(self.BUFFER_SIZE)
                            data = pickle.loads(data_1)
                            client_port = data["client_port"]
                            data = symmetric_decryption(
                                user_derived_key, data["iv"], data["tag"],
                                data["message"]).split("\n")
                            n2 = data[0]
                            n3 = data[1]
                            public_pem = '\n'.join([str(x) for x in data[2:]])
                            file = open(username + "_public.pem", "w")
                            file.write(public_pem)
                            file.close()
                            if n2 == nonce_2:
                                self.users[username] = address
                                self.client_port[username] = client_port
                                self.users_pubkeys[
                                    username] = username + "_public.pem"
                                self.users_derivedkeys[
                                    username] = user_derived_key
                                nonce_4 = str(time.time())
                                message = n3 + "\n" + nonce_4
                                enc_msg, iv, tag = symmetric_encryption(
                                    user_derived_key, message)
                                payload = {
                                    "message": str(enc_msg),
                                    "iv": str(iv),
                                    "tag": str(tag)
                                }
                                connection_socket.send(pickle.dumps(payload))
                        else:
                            connection_socket.send("Authentication failed!")

                elif parsed_data["command"] == "list":
                    signature = parsed_data["signature"]
                    user = parsed_data["user"]
                    validity = verify_signature(user + "_public.pem",
                                                signature,
                                                parsed_data["ciphertext"])
                    if validity == "VERIFIED":
                        nonce_1 = str(time.time())
                        # shared_key part is missing here, need to figure out what should be the public key
                        nonce_l = symmetric_decryption(
                            self.users_derivedkeys.get(user),
                            parsed_data["iv"], parsed_data["tag"],
                            parsed_data["ciphertext"])
                        nonce_l1 = str(time.time())
                        response = str(
                            self.users) + "\n" + nonce_l + "\n" + nonce_l1
                        enc_response, iv, tag = symmetric_encryption(
                            self.users_derivedkeys.get(user), response)
                        payload = {
                            "ciphertext": enc_response,
                            "iv": iv,
                            "tag": tag
                        }
                        connection_socket.send(pickle.dumps(payload))
                elif parsed_data["command"] == "exit":
                    signature = parsed_data["signature"]
                    user = parsed_data["user"]
                    validity = verify_signature(user + "_public.pem",
                                                signature,
                                                parsed_data["ciphertext"])
                    if validity:
                        terminate_request_nonce = symmetric_decryption(
                            self.users_derivedkeys.get(user),
                            parsed_data["iv"], parsed_data["tag"],
                            parsed_data["ciphertext"])
                        response_terminate_nonce = float(
                            terminate_request_nonce) + 1
                        encrypted_response_nonce, res_iv, res_tag = symmetric_encryption(
                            self.users_derivedkeys.get(user),
                            str(response_terminate_nonce))
                        payload = {
                            "message": "deleted_from_server",
                            "data": encrypted_response_nonce,
                            "iv": res_iv,
                            "tag": res_tag
                        }

                        connection_socket.send(pickle.dumps(payload))
                        # deleting the derived key for the user
                        del self.users_derivedkeys[user]
                        del self.users[user]
                        del self.client_port[user]
                        del self.users_pubkeys[user]
                        print "Deleted all data for : " + user

                elif parsed_data["command"] == "talk-to":
                    print self.users
                    signature = parsed_data["signature"]
                    client_user = parsed_data["chat_with"]
                    if client_user not in self.users.keys():
                        payload = {"is_valid_user": False}
                        connection_socket.send(pickle.dumps(payload))
                    else:
                        user = parsed_data["user"]
                        validity = verify_signature(user + "_public.pem",
                                                    signature,
                                                    parsed_data["ciphertext"])
                        if validity == "VERIFIED":
                            nonce_1 = str(time.time())
                            private_key, public_key = self.generate_session_key_for(
                            )
                            # shared_key part is missing here, need to figure out what should be the public key
                            client_name = parsed_data["chat_with"]
                            # this step encrypts the message ticket-to-client with the derived key of the client
                            salt = os.urandom(16)
                            shared_key_for_client = generate_key_from_password(
                                "password", salt)
                            ticket_to = pickle.dumps({
                                "shared_key":
                                shared_key_for_client,
                                "sender_name":
                                user,
                                "sender_addr":
                                self.client_port[user],
                                "nonce":
                                nonce_1
                            })
                            receiver_res, iv, tag = symmetric_encryption(
                                self.users_derivedkeys.get(client_name),
                                ticket_to)

                            message_to_receiver = pickle.dumps({
                                "shared_key":
                                shared_key_for_client,
                                "receiver":
                                self.client_port[client_name],
                                "ticket_to":
                                receiver_res,
                                "nonce":
                                3
                            })
                            enc_response, iv1, tag1 = symmetric_encryption(
                                self.users_derivedkeys.get(user),
                                message_to_receiver)
                            payload = {
                                "ciphertext": enc_response,
                                "iv1": iv1,
                                "tag1": tag1,
                                "iv": iv,
                                "tag": tag,
                                "is_valid_user": True
                            }
                            connection_socket.send(pickle.dumps(payload))
        except:
            connection_socket.close()
        finally:
            print "Connection terminated for ", address
            connection_socket.close()
    def login(self):
        count = 1
        while count <= self.MAX_RETRIES and self.logged_in == False:

            self.username = raw_input("Please enter username: "******"Please enter password: "******"command": "login",
                "username": self.username,
            }

            self.sock.send(pickle.dumps(params))
            data = self.sock.recv(self.BUFFER_SIZE)
            if data == "Already logged in":
                print "Already logged in. Terminating this session"
                os._exit(0)
            if data == "User not registered":
                print "User not registered. Please retry"
                count += 1
                continue
            challenge = data.split()
            h1 = create_hash(challenge[0])
            h2 = create_hash(challenge[1])
            answer = str(
                int(binascii.hexlify(h1), 16) & int(binascii.hexlify(h2), 16))
            nonce_1 = str(time.time())
            message = answer + "\n" + self.username + "\n" + self.password_hash + "\n" + self.salt + "\n" + nonce_1
            encrypted_message = asymmetric_encryption(self.server_pub_key,
                                                      message)
            self.sock.send(encrypted_message)
            data = self.sock.recv(self.BUFFER_SIZE)
            if data == "Authentication failed!":
                print "Authentication failed!Please retry"
                count += 1
                continue
            data = pickle.loads(data)
            n1, n2 = symmetric_decryption(self.derived_key, data["iv"],
                                          data["tag"],
                                          data["message"]).split("\n")
            if n1 == nonce_1:
                self.private_key, self.public_key = keygen()
                serialize_private_key(self.private_key, self.username)
                nonce_3 = str(time.time())
                message = n2 + "\n" + nonce_3 + "\n" + serialize_public_key(
                    self.public_key)
                enc_msg, iv, tag = symmetric_encryption(
                    self.derived_key, message)
                payload = {
                    "message": str(enc_msg),
                    "iv": str(iv),
                    "tag": str(tag),
                    "client_port": self.recv_socket.getsockname()
                }
                self.sock.send(pickle.dumps(payload))
                data_1 = self.sock.recv(self.BUFFER_SIZE)
                data = pickle.loads(data_1)
                n3, n4 = symmetric_decryption(self.derived_key, data["iv"],
                                              data["tag"],
                                              data["message"]).split("\n")
                if n3 == nonce_3:
                    print "Server authenticated and registered with server"
                    print("Client Starting...")
                    self.logged_in = True
                    self.start_send_thread()
                else:
                    print "Authentication failed!Please retry"
                    count += 1
                    continue
            else:
                print "Authentication failed!Please retry"
                count += 1
                continue
        if count > self.MAX_RETRIES and self.logged_in == False:
            print "Maximum retries exceed. Terminating now"
            os._exit(0)
    def start_listening(self):
        try:
            while True:
                data, address = self.recv_socket.recvfrom(
                    self.BUFFER_SIZE)  # buffer size is 65507 bytes
                data_dict = pickle.loads(data)
                if "message" in data_dict.keys():
                    message = data_dict["message"]
                    if message == "deleted_from_server":
                        server_del_iv = data_dict["iv"]
                        server_del_tag = data_dict["tag"]
                        server_delete_message = data_dict["data"]
                        deleted_server_decrypted_message = symmetric_decryption(
                            self.derived_key, server_del_iv, server_del_tag,
                            server_delete_message)
                        if float(self.exit_from_server_nonce) + 1 == float(
                                deleted_server_decrypted_message):
                            self.derived_key = ""
                            print "Deleted derived key for server from client: " + self.username

                    if message == "client_deleted":
                        del_iv = data_dict["iv"]
                        del_tag = data_dict["tag"]
                        deleted_user = data_dict["user"]
                        delete_confirm_nonce = symmetric_decryption(
                            self.client_shared_keys[deleted_user], del_iv,
                            del_tag, data_dict["data"])
                        if float(self.terminate_nonce
                                 ) == float(delete_confirm_nonce) - 1:
                            print "terminated"
                            del self.client_shared_keys[deleted_user]
                            del self.dh_session_keys[deleted_user]
                            continue

                    if message == "disconnect":
                        sender_user = data_dict["user"]
                        if sender_user in self.client_shared_keys.keys():
                            decrypted_msg_nonce = symmetric_decryption(
                                self.client_shared_keys[sender_user],
                                data_dict["iv"], data_dict["tag"],
                                data_dict["data"])
                            response_nonce = float(decrypted_msg_nonce) + 1
                            encrypted_res, res_iv, res_tag = symmetric_encryption(
                                self.client_shared_keys[sender_user],
                                str(response_nonce))
                            terminate_valid_payload = {
                                "message": "client_deleted",
                                "data": encrypted_res,
                                "iv": res_iv,
                                "tag": res_tag,
                                "user": self.username
                            }
                            self.send_socket.sendto(
                                pickle.dumps(terminate_valid_payload),
                                self.is_user_address_available(sender_user))
                            del self.client_shared_keys[data_dict["user"]]
                            del self.dh_session_keys[data_dict["user"]]

                    # this message is received by client(client B) for a chat request initiated bycleint B for A->B comm
                    if message == "chat_request":
                        ticket_to_receiver = data_dict["ticket_to_receiver"]
                        iv = data_dict["iv"]
                        tag = data_dict["tag"]
                        # this would get the decrypted ticket-to-receiver part, which contains the key, sender's identity, and
                        # nonce
                        # ATM I do not know where to get the iv and tag from
                        decrypted_message = symmetric_decryption(
                            self.derived_key, iv, tag, ticket_to_receiver)
                        decrypted_message_dict = pickle.loads(
                            decrypted_message)
                        shared_key = decrypted_message_dict["shared_key"]
                        sender_name = decrypted_message_dict["sender_name"]
                        sender_address = decrypted_message_dict["sender_addr"][
                            0]
                        sender_address_port = decrypted_message_dict[
                            "sender_addr"][1]
                        self.sender_addresses[sender_name] = (
                            sender_address, sender_address_port)
                        self.client_shared_keys[sender_name] = shared_key
                        self.nonce = decrypted_message_dict["nonce"]
                        # receiver here starts to reply for sender's(A) request to start communication.
                        self.nonceN2 = str(time.time())
                        self.nonceN3 = str(time.time())

                        reply_message = {
                            "N1": self.nonceN2,
                            "N2": self.nonceN3
                        }
                        encrypted_response, nonce_iv, nonce_tag = symmetric_encryption(
                            shared_key, pickle.dumps(reply_message))
                        # encrypted_response = "response"

                        payload = {
                            "encrypted_response": encrypted_response,
                            "message": "start_dh",
                            "client": self.username,
                            "iv": nonce_iv,
                            "tag": nonce_tag,
                            "user": self.username
                        }

                        self.send_socket.sendto(
                            pickle.dumps(payload),
                            (sender_address, sender_address_port))
                        # starting diffie helmann key exchange here now
                    if message == "start_dh":
                        nonce_iv = data_dict["iv"]
                        nonce_tag = data_dict["tag"]
                        nonce_user = data_dict["user"]
                        nonce_values = symmetric_decryption(
                            self.client_shared_keys[nonce_user], nonce_iv,
                            nonce_tag, data_dict["encrypted_response"])
                        nonce_values_dict = pickle.loads(nonce_values)

                        self.perform_diffie_hellman(data_dict["client"],
                                                    self.username,
                                                    nonce_values_dict["N2"])
                    # step1 is A->B with message (g^a mod p), B receives this message
                    if message == "diffie-step1":
                        # This will be received by the receiver always. In case for A->B, B will receive this message
                        params = get_diffie_hellman_params()
                        g = params["g"]
                        # The client(B) will only know 'b' of diffie hellman only
                        b = params["b"]
                        p = params["p"]
                        part = data_dict["part"]
                        sender_name = data_dict["sender-name"]
                        diffie_msg_step1_iv = data_dict["iv"]
                        diffie_msg_step1_tag = data_dict["tag"]
                        # plaintext is g^a mod p, plaintest=x in DH algorithm
                        plaintext_data = symmetric_decryption(
                            self.client_shared_keys[sender_name],
                            diffie_msg_step1_iv, diffie_msg_step1_tag, part)
                        plaintext_data_dict = pickle.loads(plaintext_data)
                        x = plaintext_data_dict["x"]
                        if plaintext_data_dict["nonceN2"] == self.nonceN2:
                            # computing the power(x, b) mod b part
                            session_key_val = math.pow(float(x), b) % p
                            # print session_key_val
                            session_key = generate_key_from_password_no_salt(
                                str(session_key_val))
                            self.dh_session_keys[sender_name] = session_key

                            # this is the creation of y = (g^b mod p) part from side B
                            gPowBModP = math.pow(g, b) % params["p"]
                            powPart = gPowBModP
                            shard_key = self.client_shared_keys[sender_name]
                            part, iv, tag = symmetric_encryption(
                                shard_key, str(powPart))
                            payload = {
                                "sender-name": self.username,
                                "message": "diffie-step2",
                                "part": part,
                                "iv": iv,
                                "tag": tag
                            }

                            self.send_socket.sendto(
                                pickle.dumps(payload),
                                self.sender_addresses[sender_name])
                        else:
                            print "invalid nonce response from client"
                            continue

                    if message == "diffie-step2":
                        # This will be received by the sender always. In case for A->B, A will receive this message
                        params = get_diffie_hellman_params()
                        a = params["a"]
                        p = params["p"]
                        sender_name = data_dict["sender-name"]
                        # plaintext is g^b mod p
                        diffie_msg_iv = data_dict["iv"]
                        diffie_msg_tag = data_dict["tag"]
                        part = data_dict["part"]
                        # the plaintext is (g^b mod p) part. This is y in diffie hellman algorithm
                        plaintext = symmetric_decryption(
                            self.client_shared_keys[sender_name],
                            diffie_msg_iv, diffie_msg_tag, part)
                        # computing the power(y, a) mod p part here.
                        session_key_val_sender = math.pow(float(plaintext),
                                                          a) % p
                        # print session_key_val_sender
                        session_key = generate_key_from_password_no_salt(
                            str(session_key_val_sender))
                        # sender_name is B in communication from A->B
                        self.dh_session_keys[sender_name] = session_key
                        # sender_name is the name of sender who sent this message
                        self.send_message_to_client(
                            self.message_for_client,
                            self.dh_session_keys[sender_name],
                            self.client_addresses[sender_name])
                    # this is message receiving part in diffie helman message exchange. B receives this message in
                    # communication  A->B
                    if message == "chat_message":
                        message_iv = data_dict["iv"]
                        message_tag = data_dict["tag"]
                        sender_name = data_dict["sender_name"]
                        res = symmetric_decryption(
                            self.dh_session_keys[sender_name][:32], message_iv,
                            message_tag, data_dict["cipher_message"])
                        print(sender_name + ":>" + res)
        except KeyboardInterrupt:
            self.perform_server_session_termination()
            os._exit(0)
    def start(self):
        try:
            print "Command list: list,send < username > < message > and exit. Have fun!"
            inp = [sys.stdin, self.sock]
            while True:

                # valid commands: list, send, terminate
                input_list, output_list, exception_list = select(inp, [], [])
                for s in input_list:
                    if s == sys.stdin:
                        input = raw_input()
                        input_array = input.split(" ")
                        command_val = input_array[0].strip()
                        # Perform different actions based on the command
                        if command_val == "list":
                            self.print_user_list(input_array)
                        elif command_val == self.exit:
                            if len(input_array) != 1:
                                print "Incorrect usage. Correct usage 'exit' to exit from server"
                            for key in self.dh_session_keys:
                                self.perform_client_session_termination(key)
                            self.perform_server_session_termination()

                        elif command_val == self.disconnect:
                            if len(input_array) != 2:
                                print "incorrect usage. Correct usage disconnect <client_name>"
                                continue
                            if (input_array[1]
                                    not in self.client_shared_keys.keys()) or (
                                        not self.is_user_address_available(
                                            input_array[1])):
                                print "connection to " + input_array[
                                    1] + " not established yet."
                            else:
                                self.perform_client_session_termination(
                                    input_array[1])
                        # user is trying to send message to the receiver
                        elif command_val == "send":
                            if len(input_array) < 3:
                                print("Invalid Input!")
                            else:
                                chat_with_user = input_array[1]
                                self.message_for_client = " ".join(
                                    input_array[2:])
                                user_address = self.is_user_address_available(
                                    chat_with_user)
                                if (chat_with_user
                                        in self.dh_session_keys.keys()
                                    ) and user_address:
                                    self.send_message_to_client(
                                        self.message_for_client,
                                        self.dh_session_keys[chat_with_user],
                                        user_address)
                                else:
                                    nonce_l = str(time.time())
                                    message = nonce_l
                                    ct, iv, tag = symmetric_encryption(
                                        self.derived_key, message)
                                    signature = sign_message(
                                        self.private_key, ct)
                                    if (chat_with_user == self.username):
                                        print(
                                            'Sender and receiver are the same.'
                                        )
                                        continue
                                    new_message = {
                                        "ciphertext": ct,
                                        "user": self.username,
                                        "chat_with": chat_with_user,
                                        "command": "talk-to",
                                        "iv": iv,
                                        "tag": tag,
                                        "nounce": nonce_l,
                                        "signature": signature
                                    }

                                    self.sock.send(pickle.dumps(new_message))
                                    # receive message from server with ticket-to-client etc
                                    data = self.sock.recv(
                                        self.BUFFER_SIZE
                                    )  # buffer size is 65507 bytes
                                    if data == "null":
                                        print("User doesn't exist!")
                                    else:
                                        temp = pickle.loads(data)
                                        if temp["is_valid_user"] == False:
                                            print "user not available to chat. Please try later. Use List command to find list of available users"
                                            continue
                                        server_response_totalk = temp[
                                            "ciphertext"]
                                        iv1 = temp["iv1"]
                                        tag1 = temp["tag1"]
                                        receiver_iv = temp["iv"]
                                        receiver_tag = temp["tag"]
                                        # decrypt response from server to get keys and ticket_to data for communicating to receiver
                                        decrypted_response = symmetric_decryption(
                                            self.derived_key, iv1, tag1,
                                            server_response_totalk)
                                        decrypted_response_dict = pickle.loads(
                                            decrypted_response)
                                        # get the ticket_to_Receiver
                                        server_generated_shared_key = decrypted_response_dict[
                                            "shared_key"]
                                        self.client_shared_keys[
                                            chat_with_user] = server_generated_shared_key
                                        receiver_address = decrypted_response_dict[
                                            "receiver"][0]
                                        receiver_address_port = decrypted_response_dict[
                                            "receiver"][1]
                                        self.client_addresses[
                                            chat_with_user] = (
                                                receiver_address,
                                                receiver_address_port)

                                        ticket_to_receiver = decrypted_response_dict[
                                            "ticket_to"]
                                        payload = {
                                            "ticket_to_receiver":
                                            ticket_to_receiver,
                                            "message": "chat_request",
                                            "iv": receiver_iv,
                                            "tag": receiver_tag
                                        }

                                        self.send_socket.sendto(
                                            pickle.dumps(payload),
                                            (receiver_address,
                                             receiver_address_port))

                        else:
                            if len(command_val) != 0:
                                print("Invalid Input!")
                                print "Command list: list,send < username > < message > and exit. Have fun!"

        except KeyboardInterrupt:
            self.perform_server_session_termination()
            os._exit(0)
        except Exception as error:
            print "Corresponding thread killed", error
            os._exit(0)