Exemplo n.º 1
0
    def reserve_slot(self):
        while True:
            # Consider who to resever from, master is default
            ust = self.ust_table[MASTER_URL]
            ust.lock.acquire()
            ust.prepare()

            slot_id = random.getrandbits(128)
            delete_nonce = (slot_id << 128) + random.getrandbits(128)
            ust_delete = UST(self.server_table[MASTER_URL])
            ust_delete.prepare(delete_nonce)

            args = {
                "nonce": ust.nonce,
                "signature": ust.signature,
                "blinded_nonce": ust.blinded_nonce,
                "slot_id": slot_id,
                "blinded_deletion_nonce": ust_delete.blinded_nonce
            }

            r = send_request(MASTER_URL, RESERVE, args)

            ust.receive(r['blinded_sign'])
            ust.lock.release()

            if r['success'] == True:
                ust_delete.receive(r['blinded_deletion_sign'])
                sig = ust_delete.signature
                return slot_id, delete_nonce, sig
Exemplo n.º 2
0
    def reserve_slot(self):
        while True:
            self.ust_lock.acquire()
            self.ust.prepare()

            slot_id = random.getrandbits(128)
            delete_nonce = (slot_id << 128) + random.getrandbits(128)
            ust_delete = UST(self.server_pk_n, self.server_pk_e)
            ust_delete.prepare(delete_nonce)

            args = {
                "nonce": self.ust.nonce,
                "signature": self.ust.signature,
                "blinded_nonce": self.ust.blinded_nonce,
                "slot_id": slot_id,
                "blinded_deletion_nonce": ust_delete.blinded_nonce
            }

            r = send_request(RESERVE, args)

            self.ust.receive(r['blinded_sign'])
            self.ust_lock.release()

            if r['success'] == True:
                ust_delete.receive(r['blinded_deletion_sign'])
                sig = ust_delete.signature
                return slot_id, delete_nonce, sig
Exemplo n.º 3
0
    def add_new_server(self, server):
        # Check if the server table does not have identifcal server under url
        if server.url in self.server_table:
            if self.server_table[server.url].equals(server):
                return

        self.server_table[server.url] = server
        slave_ust = UST(self.server_table[server.url])
        self.ust_table[server.url] = slave_ust
        slave_ust.lock.acquire()
        slave_ust.prepare()

        ust = self.ust_table[MASTER_URL]
        ust.lock.acquire()
        ust.prepare()

        args = {
            "nonce": ust.nonce,
            "signature": ust.signature,
            "blinded_nonce": ust.blinded_nonce,
            "blinded_slave_nonce": slave_ust.blinded_nonce,
            "slave_url": server.url
        }

        r = send_request(MASTER_URL, CONNECT_TO_SLAVE, args)

        ust.receive(r['blinded_sign'])
        ust.lock.release()

        slave_ust.receive(r['blinded_slave_sign'])
        slave_ust.lock.release()
Exemplo n.º 4
0
    def reserve_slot(self):
        while True:
            self.ust_lock.acquire()
            self.ust.prepare()

            slot_id = random.getrandbits(128) 
            delete_nonce = (slot_id << 128) + random.getrandbits(128)
            ust_delete = UST(self.server_pk_n,self.server_pk_e)
            ust_delete.prepare(delete_nonce)

            args = {"nonce"                     :  self.ust.nonce,
                    "signature"                 :  self.ust.signature,
                    "blinded_nonce"             :  self.ust.blinded_nonce, 
                    "slot_id"                   :  slot_id,
                    "blinded_deletion_nonce"    :  ust_delete.blinded_nonce}

            r = send_request(RESERVE, args)

            self.ust.receive(r['blinded_sign'])
            self.ust_lock.release()

            if r['success'] == True:
                ust_delete.receive(r['blinded_deletion_sign'])
                sig = ust_delete.signature
                return slot_id, delete_nonce, sig
Exemplo n.º 5
0
    def reserve_slot(self):
        while True:
            # Consider who to resever from, master is default
            ust = self.ust_table[MASTER_URL]
            ust.lock.acquire()
            ust.prepare()

            slot_id = random.getrandbits(128) 
            delete_nonce = (slot_id << 128) + random.getrandbits(128)
            ust_delete = UST(self.server_table[MASTER_URL])
            ust_delete.prepare(delete_nonce)

            args = {"nonce"                     :  ust.nonce,
                    "signature"                 :  ust.signature,
                    "blinded_nonce"             :  ust.blinded_nonce, 
                    "slot_id"                   :  slot_id,
                    "blinded_deletion_nonce"    :  ust_delete.blinded_nonce}

            r = send_request(MASTER_URL, RESERVE, args)

            ust.receive(r['blinded_sign'])
            ust.lock.release()

            if r['success'] == True:
                ust_delete.receive(r['blinded_deletion_sign'])
                sig = ust_delete.signature
                return slot_id, delete_nonce, sig
Exemplo n.º 6
0
    def add_new_server(self, server):
        # Check if the server table does not have identifcal server under url
        if server.url in self.server_table:
            if self.server_table[server.url].equals(server):
                return

        self.server_table[server.url] = server
        slave_ust = UST(self.server_table[server.url])
        self.ust_table[server.url] = slave_ust
        slave_ust.lock.acquire()
        slave_ust.prepare()

        ust = self.ust_table[MASTER_URL]
        ust.lock.acquire()
        ust.prepare()

        args = {"nonce"                 :  ust.nonce,
                "signature"             :  ust.signature,
                "blinded_nonce"         :  ust.blinded_nonce, 
                "blinded_slave_nonce"   :  slave_ust.blinded_nonce,
                "slave_url"             :  server.url}

        r = send_request(MASTER_URL, CONNECT_TO_SLAVE, args)

        ust.receive(r['blinded_sign'])
        ust.lock.release()

        slave_ust.receive(r['blinded_slave_sign'])
        slave_ust.lock.release()
Exemplo n.º 7
0
class Client:
    def main(self, username):

        self.user_table = {}
        self.conversations = {}
        self.conversation_lock = threading.Lock()
        self.ust = None
        self.ust_lock = threading.Lock()

        self.rsa = None
        self.rsa_sign = None
        self.ElGkey = None

        self.username = username
        self.connect_server()
        self.subscribe()

        # Upon successfully suscribing begin updates
        self.updates()

        self.client_input()

    def connect_server(self):
        r = send_request(SERVER, {})
        self.server_pk_n = r['server_pk_n']
        self.server_pk_e = r['server_pk_e']

    def updates(self):
        try:
            thread.start_new_thread(self.client_update, ())
            thread.start_new_thread(self.conversation_update, ())
            thread.start_new_thread(self.message_update, ())
        except:
            print "ERRROR: unable to start client threads"
            print "FATAL: client unable to update"
            sys.exit(0)

    def client_input(self):
        while True:
            cmd = raw_input("[Please enter your next command]\n>> ")
            self.handle_input(cmd)

    def handle_input(self, cmd):
        parts = cmd.split(' ', 1)
        cmd_type = parts[0]

        if cmd_type == "1":
            self.print_user_table()
        elif cmd_type == "2":
            cmd_args = parts[1]
            self.init_conversation(cmd_args)
        elif cmd_type == "3":
            cmd_args = parts[1]
            split = cmd_args.split(' ', 1)
            username = split[0]
            message = split[1]
            self.send_message(username, message)
        elif cmd_type == "H":
            print "  1: 1 - Print Local User Table"
            print "  2: 2 <username> - Start Conversation with 'username'"
            print "  3: 3 <username> <message> - Send 'message' to 'username'"

    def print_user_table(self):
        print "=== Local User Table ==="
        usernames = sorted(self.user_table.keys())
        for username in usernames:
            print "  %-24s" % username
        print "\n",

    def subscribe(self):
        print "Subscribing please wait..."
        self.rsa = RSA_gen(4096)
        self.n, self.e, self.d = RSA_keys(self.rsa)
        self.ElGkey = ElGamal.generate(256, Random.new().read)

        self.rsa_sign = RSA_gen(1024)
        self.n_sign, self.e_sign, self.d_sign = RSA_keys(self.rsa_sign)

        self.ust = UST(self.server_pk_n, self.server_pk_e)
        self.ust_lock.acquire()
        self.ust.prepare()

        args = {
            "blinded_nonce": self.ust.blinded_nonce,
            "client_username": self.username,
            "client_pk_n": self.n,
            "client_pk_e": self.e,
            "client_sign_pk_n": self.n_sign,
            "client_sign_pk_e": self.e_sign
        }

        r = send_request(SUBSCRIBE, args)

        if r == ERROR:
            print "ERROR: could not subscribe"
            sys.exit(0)

        self.ust.receive(r['blinded_sign'])
        self.ust_lock.release()

        user = r['user']

        if user['client_pk_n'] == self.n and user['client_pk_e'] == self.e \
            and user['client_sign_pk_n'] == self.n_sign \
            and user['client_sign_pk_e'] == self.e_sign:
            pass
        else:
            print "Username is taken, please try again"
            sys.exit(0)

        self.user_id = user['client_user_id']
        self.user_table_ptr = 0
        self.client_new_conversations_table_ptr = 0

        return

    def client_update(self):
        while True:
            self.ust_lock.acquire()
            self.ust.prepare()

            args = {
                "nonce": self.ust.nonce,
                "signature": self.ust.signature,
                "blinded_nonce": self.ust.blinded_nonce,
                "client_user_table_ptr": self.user_table_ptr
            }

            r = send_request(UPDATE_USER_TABLE, args)

            self.ust.receive(r['blinded_sign'])
            self.ust_lock.release()

            new_users = r['new_users']

            for new_user in new_users:
                username = new_user['client_username']
                if username not in self.user_table:
                    user_id = new_user['client_user_id']
                    pk_n, pk_e, pk_sign_n, pk_sign_e = (
                        new_user['client_pk_n'], new_user['client_pk_e'],
                        new_user['client_sign_pk_n'],
                        new_user['client_sign_pk_e'])
                    user = User(username, user_id, pk_n, pk_e, pk_sign_n,
                                pk_sign_e)
                    self.user_table[username] = user

                    self.user_table_ptr = user_id

            time.sleep(NEW_CLIENT_WAIT)
        return

    def reserve_slot(self):
        while True:
            self.ust_lock.acquire()
            self.ust.prepare()

            slot_id = random.getrandbits(128)
            delete_nonce = (slot_id << 128) + random.getrandbits(128)
            ust_delete = UST(self.server_pk_n, self.server_pk_e)
            ust_delete.prepare(delete_nonce)

            args = {
                "nonce": self.ust.nonce,
                "signature": self.ust.signature,
                "blinded_nonce": self.ust.blinded_nonce,
                "slot_id": slot_id,
                "blinded_deletion_nonce": ust_delete.blinded_nonce
            }

            r = send_request(RESERVE, args)

            self.ust.receive(r['blinded_sign'])
            self.ust_lock.release()

            if r['success'] == True:
                ust_delete.receive(r['blinded_deletion_sign'])
                sig = ust_delete.signature
                return slot_id, delete_nonce, sig

    def init_conversation(self, recipient):
        if recipient == self.username:
            print "ERROR: Please enter a username that is not your own"

        # Reserve Read/Write slot
        read_slot_id, read_nonce, read_slot_sig = self.reserve_slot()
        write_slot_id, write_nonce, write_slot_sig = self.reserve_slot()

        #my_username = int(bin(int(binascii.hexlify(self.username.ljust(256)), 16)),2)

        x = bin(int(binascii.hexlify(self.username), 16))
        my_username = x.ljust(256)

        y = bin(int(binascii.hexlify(recipient), 16))
        recipient_username = y.ljust(256)
        #recipient_username = int(bin(int(binascii.hexlify(recipient.ljust(256)), 16)),2)

        # P = (write_slot_sig << 1024) + \
        #     (write_nonce << 768) + \
        #     (my_username << 512) +  \
        #     (recipient_username << 256) + \
        #     (read_slot_id << 128) + \
        #     write_slot_id

        P = (int(my_username, 2) << 512) +  \
            (int(recipient_username,2) << 256) + \
            (read_slot_id << 128) + \
            write_slot_id

        sign = PKCS1_sign(str(P), self.rsa_sign)
        rsa_recipient = RSA_gen_user(self.user_table[recipient])
        sign_enc = RSA_encrypt(sign, rsa_recipient)
        P_enc = RSA_encrypt(str(P), rsa_recipient)
        enc_M = sign_enc + "*****" + P_enc
        self.ust_lock.acquire()
        self.ust.prepare()

        args = {
            "nonce": self.ust.nonce,
            "signature": self.ust.signature,
            "blinded_nonce": self.ust.blinded_nonce,
            "message": enc_M
        }

        r = send_request(INITIATE, args)
        self.ust.receive(r['blinded_sign'])
        self.ust_lock.release()

        conversation_obj = Conversation(self.user_table[self.username],
                                        self.user_table[recipient],
                                        read_slot_id, write_slot_id)

        self.conversation_lock.acquire()
        self.conversations[recipient] = conversation_obj
        self.conversation_lock.release()

        return

    def conversation_update(self):

        while True:
            self.ust_lock.acquire()
            self.ust.prepare()

            args = {
                "nonce":
                self.ust.nonce,
                "signature":
                self.ust.signature,
                "blinded_nonce":
                self.ust.blinded_nonce,
                "client_new_conversations_table_ptr":
                self.client_new_conversations_table_ptr
            }

            r = send_request(UPDATE_NEW_CONVERSATION_TABLE, args)

            self.ust.receive(r['blinded_sign'])
            self.ust_lock.release()

            new_conversations = r['new_conversations']

            for conversation in new_conversations:
                conversation_id = conversation['conversation_id']

                enc_M = conversation['message']

                self.client_new_conversations_table_ptr = conversation_id + 1
                ciphertext = enc_M.split("*****")
                sign = RSA_decrypt(ciphertext[0], self.rsa)
                P = RSA_decrypt(ciphertext[1], self.rsa)

                try:
                    b = bin(int(P))[2:]
                    b2 = (768 - len(b)) * '0' + b
                    sender = (''.join(
                        chr(int(b2[i:i + 8], 2))
                        for i in xrange(0, 256, 8))).replace('\x00', '')
                    recipient = (''.join(
                        chr(int(b2[i:i + 8], 2))
                        for i in xrange(256, 512, 8))).replace('\x00', '')
                    write_slot_id = int(b2[512:640], 2)
                    read_slot_id = int(b2[640:], 2)

                    if recipient != self.username:
                        continue

                    rsa_sign_sender = RSA_gen_user_sign(
                        self.user_table[sender])

                    # TODO, fix verification, assume no spoofs atm
                    #if PKCS1_verify(sign, str(P), rsa_sign_sender):
                    #    print "VERIFIED!", recipient
                    conversation_obj = Conversation(
                        self.user_table[self.username],
                        self.user_table[sender], read_slot_id, write_slot_id)

                    self.conversation_lock.acquire()
                    self.conversations[sender] = conversation_obj
                    self.conversation_lock.release()
                    print "\nConversation started with: ", sender, "\n>> ",
                except:
                    continue

            time.sleep(NEW_CONVERSATION_WAIT)
        return

    def send_message(self, username,
                     text):  #, slot_id, next_block, ND, ND_signed):
        if len(text) > 256:
            print "\nERROR: message too long\n>> ",
            return

        if username not in self.user_table:
            print "\nERROR: user " + username + " does not exist\n>> ",
            return

        if username not in self.conversations:
            print "\nERROR: please start conversation with " + username + " first\n>> ",
            return

        conversation = self.conversations[username]
        write_slot_id = conversation.write_slot_id

        new_write_slot_id, new_write_nonce, new_write_slot_sig = self.reserve_slot(
        )

        conversation.update_write_slot(new_write_slot_id)

        msg = text.ljust(128)
        x = bin(int(binascii.hexlify(msg), 16))
        new_text = int(x, 2)

        #P = (new_text << 2432) + (next_block << 2304) + (ND << 2048) + (ND_signed)

        P = (new_text << 128) + new_write_slot_id

        self.ust_lock.acquire()
        self.ust.prepare()
        signature = PKCS1_sign(str(P), self.rsa_sign)
        recipient = self.user_table[username]
        rsa_recipient = RSA_gen_user(recipient)

        ciphertext = RSA_encrypt(signature, rsa_recipient) + \
                     "*****" + RSA_encrypt(str(P), rsa_recipient)

        args = {
            "nonce": self.ust.nonce,
            "signature": self.ust.signature,
            "blinded_nonce": self.ust.blinded_nonce,
            "slot_id": write_slot_id,
            "message": ciphertext
        }

        r = send_request(PUSH, args)
        self.ust.receive(r['blinded_sign'])
        self.ust_lock.release()

        conversation.add_write_text(text)
        print "\n" + conversation.get_conversation() + "\n>> ",
        return

    def message_update(self):
        while True:
            for sender, conversation in self.conversations.items():
                read_slot_id = conversation.read_slot_id

                self.ust_lock.acquire()
                self.ust.prepare()

                args = {
                    "nonce": self.ust.nonce,
                    "signature": self.ust.signature,
                    "blinded_nonce": self.ust.blinded_nonce,
                    "slot_id": read_slot_id
                }

                r = send_request(PULL, args)

                self.ust.receive(r['blinded_sign'])
                self.ust_lock.release()

                messages = r['messages']

                for message in messages:

                    try:
                        ciphertext = message.split("*****")
                        sign = RSA_decrypt(ciphertext[0], self.rsa)
                        P = RSA_decrypt(ciphertext[1], self.rsa)

                        b = bin(int(P))[2:]

                        new_read_slot_id = int(b[-128:], 2)
                        rest = '0' + str(
                            b[:-128])  # Yeah... don't worry about this...
                        text = (''.join(
                            chr(int(rest[i:i + 8], 2))
                            for i in xrange(0, len(rest), 8))).strip()
                        # Need to verify message sender
                        # Can use just username

                        conversation.update_read_slot(new_read_slot_id)
                        conversation.add_read_text(text)
                        print "\n" + conversation.get_conversation() + "\n>> ",
                    except:
                        continue

            time.sleep(NEW_MESSAGE_WAIT)
        return
Exemplo n.º 8
0
class Client:

    def main(self,username):

        self.user_table = {}
        self.conversations = {}
        self.conversation_lock = threading.Lock()
        self.ust = None
        self.ust_lock = threading.Lock()

        self.rsa = None
        self.rsa_sign = None
        self.ElGkey = None

        self.username = username
        self.connect_server()
        self.subscribe()

        # Upon successfully suscribing begin updates
        self.updates()

        self.client_input()

    def connect_server(self):
        r = send_request(SERVER, {})
        self.server_pk_n = r['server_pk_n']
        self.server_pk_e = r['server_pk_e']

    def updates(self):
        try:
            thread.start_new_thread(self.client_update, ())
            thread.start_new_thread(self.conversation_update, ())
            thread.start_new_thread(self.message_update, ())
        except:
            print "ERRROR: unable to start client threads"
            print "FATAL: client unable to update"
            sys.exit(0)

    def client_input(self):
        while True:
            cmd = raw_input("[Please enter your next command]\n>> ")
            self.handle_input(cmd)

    def handle_input(self, cmd):
        parts = cmd.split(' ', 1)
        cmd_type = parts[0]

        if cmd_type == "1":
            self.print_user_table() 
        elif cmd_type == "2":
            cmd_args = parts[1]
            self.init_conversation(cmd_args)
        elif cmd_type == "3":
            cmd_args = parts[1]
            split = cmd_args.split(' ', 1)
            username = split[0]
            message = split[1] 
            self.send_message(username, message)
        elif cmd_type == "H":
            print "  1: 1 - Print Local User Table"
            print "  2: 2 <username> - Start Conversation with 'username'"
            print "  3: 3 <username> <message> - Send 'message' to 'username'"

    def print_user_table(self): 
        print "=== Local User Table ==="
        usernames = sorted(self.user_table.keys())
        for username in usernames:
            print "  %-24s" % username
        print "\n",

    def subscribe(self):
        print "Subscribing please wait..."
        self.rsa = RSA_gen(4096)
        self.n, self.e, self.d = RSA_keys(self.rsa)
        self.ElGkey = ElGamal.generate(256, Random.new().read)

        self.rsa_sign = RSA_gen(1024)
        self.n_sign, self.e_sign, self.d_sign = RSA_keys(self.rsa_sign)

        self.ust = UST(self.server_pk_n, self.server_pk_e)
        self.ust_lock.acquire()
        self.ust.prepare()

        args = {"blinded_nonce"     :  self.ust.blinded_nonce, 
                "client_username"   :  self.username,
                "client_pk_n"       :  self.n, 
                "client_pk_e"       :  self.e,
                "client_sign_pk_n"  :  self.n_sign,
                "client_sign_pk_e"  :  self.e_sign}
        
        r = send_request(SUBSCRIBE, args)

        if r == ERROR:
            print "ERROR: could not subscribe"
            sys.exit(0)

        self.ust.receive(r['blinded_sign'])
        self.ust_lock.release()

        user = r['user']

        if user['client_pk_n'] == self.n and user['client_pk_e'] == self.e \
            and user['client_sign_pk_n'] == self.n_sign \
            and user['client_sign_pk_e'] == self.e_sign:
            pass
        else:
            print "Username is taken, please try again"
            sys.exit(0)

        self.user_id = user['client_user_id']
        self.user_table_ptr = 0
        self.client_new_conversations_table_ptr = 0

        return

    def client_update(self):
        while True:
            self.ust_lock.acquire()
            self.ust.prepare()

            args = {"nonce"                 :  self.ust.nonce,
                    "signature"             :  self.ust.signature,
                    "blinded_nonce"         :  self.ust.blinded_nonce, 
                    "client_user_table_ptr" :  self.user_table_ptr}

            r = send_request(UPDATE_USER_TABLE, args)
            
            self.ust.receive(r['blinded_sign'])
            self.ust_lock.release()

            new_users = r['new_users']

            for new_user in new_users:
                username = new_user['client_username']
                if username not in self.user_table:
                    user_id = new_user['client_user_id']
                    pk_n, pk_e, pk_sign_n, pk_sign_e = (new_user['client_pk_n'],
                                                       new_user['client_pk_e'],
                                                       new_user['client_sign_pk_n'],
                                                       new_user['client_sign_pk_e'])
                    user = User(username,user_id,pk_n,pk_e,pk_sign_n,pk_sign_e)
                    self.user_table[username] = user

                    self.user_table_ptr = user_id

            time.sleep(NEW_CLIENT_WAIT)
        return

    def reserve_slot(self):
        while True:
            self.ust_lock.acquire()
            self.ust.prepare()

            slot_id = random.getrandbits(128) 
            delete_nonce = (slot_id << 128) + random.getrandbits(128)
            ust_delete = UST(self.server_pk_n,self.server_pk_e)
            ust_delete.prepare(delete_nonce)

            args = {"nonce"                     :  self.ust.nonce,
                    "signature"                 :  self.ust.signature,
                    "blinded_nonce"             :  self.ust.blinded_nonce, 
                    "slot_id"                   :  slot_id,
                    "blinded_deletion_nonce"    :  ust_delete.blinded_nonce}

            r = send_request(RESERVE, args)

            self.ust.receive(r['blinded_sign'])
            self.ust_lock.release()

            if r['success'] == True:
                ust_delete.receive(r['blinded_deletion_sign'])
                sig = ust_delete.signature
                return slot_id, delete_nonce, sig

    def init_conversation(self, recipient):
        if recipient == self.username:
            print "ERROR: Please enter a username that is not your own"

        # Reserve Read/Write slot
        read_slot_id, read_nonce, read_slot_sig = self.reserve_slot()
        write_slot_id, write_nonce, write_slot_sig = self.reserve_slot()


        #my_username = int(bin(int(binascii.hexlify(self.username.ljust(256)), 16)),2)

        x = bin(int(binascii.hexlify(self.username), 16))
        my_username = x.ljust(256)

        y = bin(int(binascii.hexlify(recipient), 16))
        recipient_username = y.ljust(256)
        #recipient_username = int(bin(int(binascii.hexlify(recipient.ljust(256)), 16)),2)

        # P = (write_slot_sig << 1024) + \
        #     (write_nonce << 768) + \
        #     (my_username << 512) +  \
        #     (recipient_username << 256) + \
        #     (read_slot_id << 128) + \
        #     write_slot_id
        
        P = (int(my_username, 2) << 512) +  \
            (int(recipient_username,2) << 256) + \
            (read_slot_id << 128) + \
            write_slot_id

        sign = PKCS1_sign(str(P), self.rsa_sign)
        rsa_recipient = RSA_gen_user(self.user_table[recipient])
        sign_enc =RSA_encrypt(sign, rsa_recipient)
        P_enc = RSA_encrypt(str(P), rsa_recipient)
        enc_M = sign_enc + "*****" + P_enc
        self.ust_lock.acquire()
        self.ust.prepare()
        
        args = {"nonce"                     :  self.ust.nonce,
                "signature"                 :  self.ust.signature,
                "blinded_nonce"             :  self.ust.blinded_nonce, 
                "message"                   :  enc_M}

        r = send_request(INITIATE, args)
        self.ust.receive(r['blinded_sign'])
        self.ust_lock.release()

        conversation_obj = Conversation(self.user_table[self.username],
                                        self.user_table[recipient],
                                        read_slot_id,
                                        write_slot_id)

        self.conversation_lock.acquire()
        self.conversations[recipient] = conversation_obj
        self.conversation_lock.release()

        return 

    def conversation_update(self):

        while True:
            self.ust_lock.acquire()
            self.ust.prepare()

            args = {"nonce"                              :  self.ust.nonce,
                    "signature"                          :  self.ust.signature,
                    "blinded_nonce"                      :  self.ust.blinded_nonce, 
                    "client_new_conversations_table_ptr" :  self.client_new_conversations_table_ptr}

            r = send_request(UPDATE_NEW_CONVERSATION_TABLE, args)
            
            self.ust.receive(r['blinded_sign'])
            self.ust_lock.release()

            new_conversations = r['new_conversations']

            for conversation in new_conversations:
                conversation_id = conversation['conversation_id']

                enc_M = conversation['message']

                self.client_new_conversations_table_ptr = conversation_id + 1
                ciphertext = enc_M.split("*****")
                sign = RSA_decrypt(ciphertext[0], self.rsa)
                P = RSA_decrypt(ciphertext[1], self.rsa)

                try:
                    b = bin(int(P))[2:] 
                    b2 = (768-len(b))*'0' + b
                    sender = (''.join(chr(int(b2[i:i+8], 2)) for i in xrange(0, 256, 8))).replace('\x00','')
                    recipient = (''.join(chr(int(b2[i:i+8], 2)) for i in xrange(256, 512, 8))).replace('\x00','')
                    write_slot_id = int(b2[512:640],2)
                    read_slot_id = int(b2[640:],2)

                    if recipient != self.username:
                        continue

                    rsa_sign_sender = RSA_gen_user_sign(self.user_table[sender])

                    # TODO, fix verification, assume no spoofs atm
                    #if PKCS1_verify(sign, str(P), rsa_sign_sender):
                    #    print "VERIFIED!", recipient
                    conversation_obj = Conversation(self.user_table[self.username],
                                                    self.user_table[sender],
                                                    read_slot_id,
                                                    write_slot_id)
       
                    self.conversation_lock.acquire()
                    self.conversations[sender] = conversation_obj
                    self.conversation_lock.release()
                    print "\nConversation started with: ", sender, "\n>> ",
                except:
                    continue

            time.sleep(NEW_CONVERSATION_WAIT)
        return

    def send_message(self, username, text): #, slot_id, next_block, ND, ND_signed):
        if len(text) > 256:
            print "\nERROR: message too long\n>> ",
            return

        if username not in self.user_table:
            print "\nERROR: user " + username + " does not exist\n>> ",
            return

        if username not in self.conversations:
            print "\nERROR: please start conversation with " + username + " first\n>> ",
            return

        conversation = self.conversations[username]
        write_slot_id = conversation.write_slot_id

        new_write_slot_id, new_write_nonce, new_write_slot_sig = self.reserve_slot()

        conversation.update_write_slot(new_write_slot_id)

        msg = text.ljust(128)
        x = bin(int(binascii.hexlify(msg), 16))
        new_text = int(x,2)
        
        #P = (new_text << 2432) + (next_block << 2304) + (ND << 2048) + (ND_signed)
        
        P = (new_text << 128) + new_write_slot_id  

        self.ust_lock.acquire()
        self.ust.prepare()
        signature = PKCS1_sign(str(P), self.rsa_sign)
        recipient = self.user_table[username]
        rsa_recipient = RSA_gen_user(recipient)

        ciphertext = RSA_encrypt(signature, rsa_recipient) + \
                     "*****" + RSA_encrypt(str(P), rsa_recipient)

        args = {"nonce"                     :  self.ust.nonce,
                "signature"                 :  self.ust.signature,
                "blinded_nonce"             :  self.ust.blinded_nonce,
                "slot_id"                   :  write_slot_id,
                "message"                   :  ciphertext}

        r = send_request(PUSH, args)
        self.ust.receive(r['blinded_sign'])
        self.ust_lock.release()

        conversation.add_write_text(text)
        print "\n" + conversation.get_conversation() + "\n>> ",
        return

    def message_update(self):
        while True:
            for sender, conversation in self.conversations.items():
                read_slot_id = conversation.read_slot_id

                self.ust_lock.acquire()
                self.ust.prepare()

                args = {"nonce"              :  self.ust.nonce,
                        "signature"          :  self.ust.signature,
                        "blinded_nonce"      :  self.ust.blinded_nonce, 
                        "slot_id"            :  read_slot_id}

                r = send_request(PULL, args)
                
                self.ust.receive(r['blinded_sign'])
                self.ust_lock.release()

                messages = r['messages']

                for message in messages:
                    
                    try:
                        ciphertext = message.split("*****")
                        sign = RSA_decrypt(ciphertext[0], self.rsa)
                        P = RSA_decrypt(ciphertext[1], self.rsa)

                        b = bin(int(P))[2:]

                        new_read_slot_id = int(b[-128:],2)
                        rest = '0' + str(b[:-128])          # Yeah... don't worry about this...
                        text = (''.join(chr(int(rest[i:i+8], 2)) for i in xrange(0, len(rest), 8))).strip()
                        # Need to verify message sender
                        # Can use just username

                        conversation.update_read_slot(new_read_slot_id)
                        conversation.add_read_text(text)
                        print "\n" + conversation.get_conversation() + "\n>> ",
                    except:
                        continue

            time.sleep(NEW_MESSAGE_WAIT)
        return