def clientthread(conn, addr): # sends a message to the client whose user object is conn global key_fragment_arr usr_ip = addr[0] while True: # Make sure that encoding will not violate the check on `message` below message = conn.recv(BUFFER_SIZE).decode(ENCODING) if message: # Parse command try: request = Request.deserialize(message) except: raise ValueError("Can't deserialize JSON data") cmd = request.cmd args = request.args print("[RECEIVED-cmd] : {0}".format(cmd)) if cmd == cmd_types.REGISTER: pubKey = args['pub_key'] register(usr_ip, conn, pubKey) # Ask the user for kfrags (after sending all PKs) elif cmd == cmd_types.MSG_TO_NODE: ''' User should expect the follow from the user: - ciphertext - capsoule Now we go through all the other users and compute cfrag for each, and send it ''' alice_capsule = pre.Capsule.from_bytes(args['sender_capsule']) alice_ciphertext = args['ciphertext'] alice_pk = args['sender_publickey'] print("<{0}> {1}".format(alice_pk[:10], alice_ciphertext)) share_cfrags(alice_pk, alice_capsule, alice_ciphertext, conn) elif cmd == cmd_types.SEND_FRG_SAMPLE: src_pubkey = args['client_pubkey'] src_id = pk_to_id[src_pubkey] dst_pubkey = args['new_pubkey'] dst_id = pk_to_id[dst_pubkey] khfrag_sample = args['khfrag_sample'] khfrag_sample = [fragments.KFrag.from_bytes(sample) for sample in khfrag_sample] key_fragment_arr.set_fragment(src_id, dst_id, khfrag_sample) elif cmd == cmd_types.USER_EXT: remove(usr_ip, conn) continue else: print("Invalid command received") else: """message may have no content if the connection is broken, in this case we remove the connection""" remove(usr_ip, conn) exit()
def main(): if len(sys.argv) != 3: print("Correct usage: script, IP address, port number") exit() ip_to_pk = {} # Indexed by ip, returns pk server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) IP_address = str(sys.argv[1]) Port = int(sys.argv[2]) server.connect((IP_address, Port)) # Generate a key pair to be used for the protocol (user_priv_key, user_pub_key) = key_gen() # Serialize the user_pub_key for future transmission. user_pub_key = user_pub_key.to_bytes() # Send a registartion request to the nodes in the network. reg_req = Request.register_request(user_pub_key) ser_reg_req = reg_req.serialize() server.send(ser_reg_req.encode(ENCODING)) while True: # maintains a list of possible input streams sockets_list = [sys.stdin, server] """ There are two possible input situations. Either the user wants to give manual input to send to other people, or the server is sending a message to be printed on the screen. Select returns from sockets_list, the stream that is reader for input. So for example, if the server wants to send a message, then the if condition will hold true below.If the user wants to send a message, the else condition will evaluate as true""" read_sockets, write_socket, error_socket = select.select( sockets_list, [], []) for socks in read_sockets: if socks == server: message = socks.recv(BUFFER_SIZE).decode(ENCODING) try: request = Request.deserialize(message) except: raise ValueError("Can't deserialize JSON command") exit() cmd = request.cmd args = request.args # Parse the recived command if cmd == cmd_types.SEND_ALL_PKS: ''' After joining the network, we recieve a list of the current active users (by their Public Keys) We parse the given list to generate fragments of the re-encryption key corresponding to each public key reciver (we assume open permission to any user in the group chat). ''' pubkey_arr = args['pks'] for new_pubkey in pubkey_arr: # We generate N shares so that it would be distributed over the 'N' nodes of the network. khfrags = pre.split_rekey( user_priv_key, keys.UmbralPublicKey.from_bytes(new_pubkey), THRESHOLD_M, THRESHOLD_N) # Create a sample to distribute the shares to each Node (To simulate a decentralized scenario) khfrags_sample = [] for i in range(0, THRESHOLD_M): khfrags_sample += [khfrags[i].to_bytes()] # Send the payload of the fragmented re-encryption keys to the nodes in the network req = Request.send_new_user_khfrag_samples_request( client_pubkey=user_pub_key, new_user_pubkey=new_pubkey, khfrag_sample=khfrags_sample) server.send(req.serialize().encode(ENCODING)) elif cmd == cmd_types.NEW_USR: ''' While on the network, if any new user joins the network, the nodes would send the new user's PublicKey to the all the users currenlty using the group chat. Then users would compute the re-encryption key for that specific user and send the fragments to the nodes in the network. ''' #Get the public key of the new user new_pubkey = args['new_pubkey'] #Compute the re-encryption keys khfrags = pre.split_rekey( user_priv_key, keys.UmbralPublicKey.from_bytes(new_pubkey), THRESHOLD_M, THRESHOLD_N) #Create a sample to distribute the shares to each Node khfrags_sample = [] for i in range(0, THRESHOLD_M): khfrags_sample += [khfrags[i].to_bytes()] # Send the payload of the fragmented re-encryption key to the nodes in the network req = Request.send_new_user_khfrag_samples_request( client_pubkey=user_pub_key, new_user_pubkey=new_pubkey, khfrag_sample=khfrags_sample) req_ser = req.serialize() server.send(req_ser.encode(ENCODING)) elif cmd == cmd_types.MSG_TO_USER: ''' While on the network, and a user sends a message to the group chat. The nodes will compute the Capsule fragments corresponding to each recieving user and send it to them. The user then would combine all the needed fragments (At least M) and then decrypt and verify the plaintext. ''' # Deserialization alice_pub_key = keys.UmbralPublicKey.from_bytes( args['sender_publickey']) A_capsule = pre.Capsule.from_bytes(args['sender_capsule']) bob_capsule = A_capsule #This is just to stick to the demo analogy. A_ciphertext = args['ciphertext'] cfrags = args['cfrag'] # Combining the fragments of the Capsule. for cfrag in cfrags: bob_capsule.attach_cfrag( fragments.CapsuleFrag.from_bytes(cfrag)) # Decrypting the ciphertext plaintext = pre.decrypt(bob_capsule, user_priv_key, A_ciphertext, alice_pub_key) print("<{0}> {1}".format(alice_pub_key.to_bytes()[:10], plaintext.decode(ENCODING))) elif cmd == cmd_types.SEND_PLAINTEXT: msg_received = args['msg'] print(msg_received) else: print(cmd) print("Invalid command received") else: # Here we do the Enryption (on the user input) user_input = sys.stdin.readline() # Generate the ciphertext and sender_capsule ciphertext, sender_capsule = pre.encrypt( keys.UmbralPublicKey.from_bytes(user_pub_key), user_input.encode(ENCODING)) sender_capsule = sender_capsule.to_bytes() # We send the ciphertext, sender_capsule and the user PublicKey to the nodes. req = Request.send_ciphertext_request( sender_capsule=sender_capsule, ciphertext=ciphertext, sender_publickey=user_pub_key) ser_req = req.serialize() server.send(ser_req.encode(ENCODING)) # We still print the `user_input` to the user's own screen (optional) sys.stdout.write("<You>") sys.stdout.write(user_input) sys.stdout.flush() server.close()