def exchange_keys_with_client(the_connection):
        '''
        Prompts as to whether to send keys or not
        If keys are not sent, program terminates because it is
        impossible to encrypt and decrypt messages
        '''
        try:
            
            # wait to receive client's public key
            key = the_connection.recv(8192)
            key = key.split(',')
            public_key_tuple = (key[0], key[1])
            print '[+] Secure Chat Partner\'s Public Key Received\n'

            secure_utils.display_processing_cursor("Generating And Exchanging Your Keys")
            (n, e, d) = secure_utils.generate_my_keys(MODULUS_N, EXPONENT, MULTIPLICATIVE_INVERSE)
        
            print "[+] Your TRUNCATED Public Key is (****{0},****{1})".format(str(n)[0:5], str(e)[0:5])
            print "[+] Your Private Key is hidden"
            
            public_key = str(n) + ',' + str(e)
            the_connection.send(public_key)
            print '[+] Your Public Key Has Been Sent To The Other Party'
        
            private_key_tuple = (n, d)
        
            return ((public_key_tuple), (private_key_tuple))
        except Exception, e:
                secure_utils.clear_screen()
                print "\n\033[1;41m[+] Error connecting to server or exchanging keys\033[1;m"
                raw_input("\nPress [ENTER] To Return To The Main Menu...\n")
                return
                pass
def display_client_menu():
    
    '''
    Displays a program menu for user to choose an option
    
    '''

    try:
        # Clears the screen
        secure_utils.clear_screen()
        while True:
            # Display My Logo
            secure_utils.draw_client_logo()
            print '----------------------------------\n'
            print'1.  Set Host Name/IP To Use\n2.  Set Port Number To Use\n3.  Connect To Secure Chat Session\n4.  Program Information\n99. Exit Program\n'
            print '----------------------------------\n'
            user_chosen_option = raw_input('Enter an option >> ')
            secure_utils.clear_screen()
            
            if(user_chosen_option == '1'):
                set_host_name()
            elif(user_chosen_option == '2'):
                set_port_number()
            elif(user_chosen_option == '3'):
                connect_to_server()
            elif(user_chosen_option == '4'):
                secure_utils.program_info()
            elif(user_chosen_option == '5'):
                print "Coming Soon"
            elif(user_chosen_option == '6'):
                print "Coming Soon"
            elif(user_chosen_option == '98'):
                print "Coming Soon"
            elif(user_chosen_option == '99'):
                break
            else:
                print('[--] ERROR: Invalid Option.')
                raw_input("Press [ENTER] To Return To The Main Menu...\n")
            secure_utils.clear_screen()
                
    except KeyboardInterrupt:
        print'[--] CTRL+C Pressed.'
    except Exception, e:
        print'[--] ERROR: %s' % str(e)
    def read_data(self, n, d): 
        '''
        Reads in data from client to be sent and displayed to server.
        
        '''
        try:
            my_incoming_message = secure_utils.recv_end(self.my_connection)  # receive incoming data
            my_incoming_message = secure_utils.unpack_cipherblocks_from_transmit(my_incoming_message)  # unpack the combined cipher blocks
            my_incoming_message = RSA.decrypt(my_incoming_message, n, d, len([my_incoming_message]))  # decrypt the cipher

            while my_incoming_message.strip() != self.my_exit_code and len(my_incoming_message) > 0:
                print "\r\033[1;34m<< {0}\033[1;m".format(my_incoming_message.strip())
                my_incoming_message = secure_utils.recv_end(self.my_connection)  # continue receiving more messages
                my_incoming_message = secure_utils.unpack_cipherblocks_from_transmit(my_incoming_message)  # continue unpacking the cipher blocks
                my_incoming_message = RSA.decrypt(my_incoming_message, n, d, len([my_incoming_message]))  # continue decrypting
                # client disconnected
            self.stop_write_loop() 
        except:
            pass
def connect_to_server():
    '''
    Starts a connection to the server 
    '''
    try:
        
        secure_utils.clear_screen()  # clear screen for nice output
        secure_utils.draw_client_logo()  # 
        
        my_client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        my_client_socket.connect((HOST_NAME, PORT_NUMBER))

        print_welcome_message(socket.gethostname(), my_client_socket.getsockname()[0])
    
        # wait to receive server's public key . WILL RETURN NO KEYS IF SERVER HAS BANNED YOU FROM CONNECTING
        (publicKeyTuple, privateKeyTuple) = exchange_keys_with_server(my_client_socket)
         
        # checks whether server accepted or refused connection. RETURNS NONE IF BANNED
        if((publicKeyTuple, privateKeyTuple) == ((None, None), (None, None))):
            my_client_socket.close()  # close the connection or session as you cannot carry on.

        else:  # begin interaction with other party.
            
            print '\n\033[1;42m*******Type your message below and hit enter to send. Type \'EXIT\' to end conversation.*******\033[1;m\n'
        
            ReadAndDecryptThread = ThreadManager('read', my_client_socket, publicKeyTuple, privateKeyTuple)  # Thread for reading in data and decrypting
            WriteAndEncryptThread = ThreadManager('write', my_client_socket, publicKeyTuple, privateKeyTuple)  # Thread for writing data and encrypting


            ReadAndDecryptThread.start()
            WriteAndEncryptThread.start()

            ReadAndDecryptThread.join()
            print '[+] Your partner has left the conversation. Press any key to continue...\n'

            # stop the write thread
            WriteAndEncryptThread.stop_write_loop()
            WriteAndEncryptThread.join()
    

            # shut down client connection
            secure_utils.display_processing_cursor('Shutting client down...')

    except socket.error as socket_error:
        secure_utils.clear_screen()
        print socket_error[1] + "\n"
        raw_input("Press [ENTER] To Return To The Main Menu...\n")
        return
        pass
 def write_data(self, n, e):
     '''
     Reads in data from prompt and sending out to client 
     ''' 
     try:
         
         while self.my_continue_to_write:
             my_original_message = sys.stdin.readline()  # read input from user
             my_outgoing_message = RSA.encrypt(my_original_message, n, e, len([my_original_message]))  # encrypt the users input
             
             my_outgoing_message = secure_utils.combine_cipherblocks_for_transmit(my_outgoing_message) + ";;"  # add the ";;" delimeter. This indicates the end of a user's input. A fix for not knowing the buffer size. 
             self.my_connection.send(my_outgoing_message)  # send out message to the user.
         
             # check to see if my outgoing message is EXIT to quit the chat
             if (my_original_message.strip() == self.my_exit_code):
                 self.my_connection.shutdown(socket.SHUT_RDWR)
                 self.my_connection.close()
                 self.stop_write_loop()
     except:
         pass
def exchange_keys_with_server(the_connection):
        '''
        Prompts as to whether to send keys or not
        If keys are not sent, program terminates because it is
        impossible to encrypt and decrypt messages
        '''
        try:
            
            # wait to receive client's public public_key
        
            secure_utils.display_processing_cursor("Generating And Exchanging Keys")
            (n, e, d) = secure_utils.generate_my_keys(MODULUS_N, EXPONENT, MULTIPLICATIVE_INVERSE)
        
            print "[+] Your TRUNCATED Public Key is (****{0},****{1})".format(str(n)[0:5], str(e)[0:5])
            print "[+] Your Private Key is hidden"
            
            generated_public_key = str(n) + ',' + str(e)
            the_connection.send(generated_public_key)
            print "[+] Sent Your Public Key To Your Secure Chat Partner"
        
            message_received = the_connection.recv(8192)
        
            if(message_received == "Send Keys"):
            
                message_received = the_connection.recv(8192)
                servers_public_key = message_received.split(",")
                servers_public_key_tuple = (servers_public_key[0], servers_public_key[1])
                print '[+] Server\'s Public Key Received\n'
                client_private_key_tuple = (n, d)        
                return ((servers_public_key_tuple), (client_private_key_tuple))
            else:
                
                print "\n\033[1;41m[+] Message Received from server : {0}\033[1;m".format(message_received)
                secure_utils.display_processing_cursor("Returning to main menu")
                return ((None, None), (None, None))    
        except Exception, e:
                secure_utils.clear_screen()
                print "\n\033[1;41m[+] Error connecting to server or exchanging keys\033[1;m"
                pass
def display_server_menu():
    
    '''
    Displays a program menu for user to choose an option
    
    '''

    try:
        # Clears the screen
        secure_utils.clear_screen()
        while True:
            # Display My Logo
            secure_utils.draw_server_logo() 
            print '----------------------------------\n'
            print'1.  Change Port To Use\n2.  Run Server\n3.  View/Add Blocked IPs\n4.  Remove Blocked IPC\n5.  Program Information\n99. Exit Program\n'
            print '----------------------------------\n'
            user_chosen_option = raw_input('Enter an option>> ')
            secure_utils.clear_screen()
            
            if(user_chosen_option == '1'):
                set_port_number()
            elif(user_chosen_option == '2'):
                start_server_listener()
            elif(user_chosen_option == '3'):
                secure_utils.add_ip_to_ban_list()
            elif(user_chosen_option == '4'):
                secure_utils.remove_ip_from_ban_list()
            elif(user_chosen_option == '5'):
                secure_utils.program_info()
            elif(user_chosen_option == '99'):
                break
            else:
                print('[--] ERROR: Invalid Option.')
                raw_input("Press [ENTER] To Return To The Main Menu...\n")
            secure_utils.clear_screen()
                
    except KeyboardInterrupt:
        print'[--] CTRL+C Pressed.'
    except Exception, e:
        print'[--] ERROR: %s' % str(e)
def start_server_listener(the_host_name=HOST_NAME, the_max_clients=MAX_CLIENTS):
    '''
    Starts the Secure Server, if successfully also starts listening or a client/chat partner to connect.
    '''    
    try:
        secure_utils.clear_screen()  # clear screen for nice output
        secure_utils.draw_server_logo()  # draws logo 
        
        my_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        my_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 
        my_server_socket.bind(('', PORT_NUMBER))
        my_server_socket.listen(the_max_clients)
                                                                       
        
        print "\033[1;43m[+] The Chat Server Successfully Started\033[1;m"
        print "\033[1;43m[+] Now accepting chat clients\033[1;m\n"
        
        # Blocking call to accept connections
        
        (my_client_connection, my_client_address) = my_server_socket.accept()
        
        print "[+] User {0} at {1} is now connected to the server".format(socket.gethostname(), my_client_address[0])

        if (my_client_address[0] in secure_utils.populated_banned_list()):  # check if this user is banned from connecting, send appropriate msg
            print "[+] User at {0} is banned from this server... disconnecting".format(my_client_address[0])
            my_client_connection.send("Its unfortunate, but you are banned from connecting to this server")
            return 0
        
        else:
            my_client_connection.send("Send Keys")  # Tell other party to send their public keys.
            
            # wait to receive client's public key
            (publicKeyTuple, privateKeyTuple) = exchange_keys_with_client(my_client_connection) 
        
           
            print '\n\033[1;42m*******Type your message below and hit enter to send. Type \'EXIT\' to end conversation.*******\033[1;m\n'

            ReadAndDecryptThread = ThreadManager('read', my_client_connection, publicKeyTuple, privateKeyTuple)  # Thread for reading data and decrypting
            WriteAndEcnryptThread = ThreadManager('write', my_client_connection, publicKeyTuple, privateKeyTuple)  # Thread for writing data and decrypting

            ReadAndDecryptThread.start()  # Start the read and decrypt thread
            WriteAndEcnryptThread.start()  # Starts the writing and encrypting thread

            # wait until client dc's
            ReadAndDecryptThread.join()
            print '[+] Your partner has left the conversation. Press any key to continue...\n'

            # stop the write thread
            WriteAndEcnryptThread.stop_write_loop()
            WriteAndEcnryptThread.join()

            # shut down client connection
            try:
                my_client_connection.shutdown(socket.SHUT_RDWR)
                my_client_connection.close()
            except:
                # connection already closed
                pass

            # shut down server
            secure_utils.display_processing_cursor('Shutting server down...')
            my_server_socket.shutdown(socket.SHUT_RDWR)
            my_server_socket.close()
 
            return 0 
                
    except socket.error as socket_error:
        print socket_error[1]
        raw_input("\nPress [ENTER] To Return To The Main Menu...\n")
        # print "[-] There was problem starting the server"
        pass