def recv_next_command(conn: socket, client_parser=None): """ waits for a command by the client, and returns the parsed args, responds to the client with 202 and data on success :param conn: socket connection :return: client command arguments, or None if invalid command """ command_json = _bytes_to_string(recv_msg(conn)) print("received req:", command_json) try: # # # client_args = { # extend defaults 'file_index': None, 'local': False, 'key': DEFAULT_KEY, 'cipher': 'none', 'filename': '', 'function': lambda x: None, 'iv': None, } client_args.update(json.loads(command_json)) # update client_args = AttrDict(client_args) # converting args (parsing strings to bytes and function names to functions) client_args.cipherfunc = getattr(CipherLib, client_args.cipher) client_args.iv = _string_to_bytes(client_args.iv) client_args.function = eval(client_args.function) # printing object: import pprint pp = pprint.PrettyPrinter(indent=4) print('client_args received') pp.pprint(vars(client_args)) # server_resp = _string_to_bytes( json.dumps({ 'readystate': 202, # code "202" meaning (accepted) })) send_msg(conn, server_resp) return client_args except Exception as e: print("ERROR executing command:", e) return None
def send_command(args, callback=lambda sock: print("Connected", sock)): """connects to the server and sends the command :param args: this object is similar to the one parsed from the commandline, contains "host" and "port" members :param callback(sock, respjson): a function to call when connected to the server. sock: Gets passed the socket object, the socket object at this point is already connected and is ready to send or recv. :return the callback result """ with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: print('connecting to server...', end='') s.connect((args.host, args.port)) # connect print('\rConnection established ') # random initialization vector setattr(args, 'iv', secrets.token_bytes(16)) if not hasattr(args, 'cipherfunc'): setattr(args, 'cipherfunc', CipherLib.none) ################ # serialize args ################ import copy s_args = copy.deepcopy(vars(args)) for k, v in s_args.items(): if isinstance(v, types.FunctionType): # functions get the name passed s_args[k] = v.__name__ elif isinstance(v, bytes): # bytes get turned into strings s_args[k] = _bytes_to_string(v) s_args['cipher'] = s_args.get('cipherfunc', 'none') del s_args['key'] # delete key (otherwise is sent in plaintext) request_json = json.dumps(s_args) print('Sending command: "{}"'.format(request_json)) # send the command/request json send_msg(s, _string_to_bytes(request_json)) # check if server acknowledged the command # (if resp is included in one of the success response codes) resp = recv_msg(s) resp_json = AttrDict(json.loads(_bytes_to_string(resp))) if resp_json.readystate in [202]: res = callback(s) send_msg(s, b'200') # send OK code print('\nTransaction complete') return res
def callback(conn: socket): ciphertext = b'' with open(filename, 'rb') as f: data = f.read() ciphertext = args.cipherfunc(data=data, key=args.key, iv=args.iv) return send_msg( conn, _string_to_bytes( json.dumps({ 'filename': filename, 'data': _bytes_to_string(ciphertext), 'iv': _bytes_to_string(args.iv), })))
def get(conn: socket, args=None): # send the file to client if args.file_index: args.filename = os.listdir('files')[int(args.filename)] iv = secrets.token_bytes(16) args_filename = args.filename filename = os.path.join('files', args_filename) with open(filename, 'rb') as f: plaintext = f.read() ciphertext = args.cipherfunc(data=plaintext, key=args.key, iv=iv) print("finished reading file \"{}\", {}B".format(filename, len(ciphertext))) return send_msg( conn, _string_to_bytes( json.dumps({ 'filename': filename, 'data': _bytes_to_string(ciphertext), 'iv': _bytes_to_string(iv), })))
def main(): """ Step 1: Alice generates an RSA key pair PK=(n,e) and SK=(d) and generates two random values, r_0 and r_1, and sends them to Bob along with her PK Step 2: Bob picks a bit b to be either 0 or 1, and selects r_b Step 3: Bob generates a random value k and blinds r_b by computing 〖v=r〗_b+k^e mod n and send it to Alice Step 4: Alice doesn't know which of r_0 and r_1 Bob chose. She applies them both and come up with two possible values for k:k_0=(v−x_0 )^d mod n and k_1=(v−x_1 )^d mod n Eventually, one of these will be equal to k and can be correctly decrypted by Bob (but not Alice), while the other will produce a meaningless random value that does not reveal any information about k Step 5: Alice combines the two secret messages with each of the possible keys, m_0^′=m_0+k_0 and m_1^′=m_1+k_1, and sends them both to Bob Step 6: Bob knows which of the two messages can be unblinded with k, so he is able to compute exactly one of the messages m_b=m_b^′−k :return: """ parser = get_arg_parser() print(DESCRIPTION + "\n") args = parser.parse_args() with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: print('connecting to server...', end='') s.connect((args.host, args.port)) # connect print('\rConnection established ') # recv public key resp = recv_msg(s) resp = json.loads(_bytes_to_string(resp)) alice_pubkey = rsa.PublicKey(resp['n'], resp['e']) r_b_choices = list(map(_string_to_bytes, resp['r_b_choices'])) print('alice_pubkey', alice_pubkey) print('r_b_choices', r_b_choices) # Step 2: Bob picks a bit b to be either 0 or 1, and selects r_bs r_b = int.from_bytes(r_b_choices[args.msg_index], 'big') # Step 3: Bob generates a random value k and blinds r_b by computing 〖v=r〗_b+k^e mod n and send it to Alice k = secrets.token_bytes(4) k_int = int.from_bytes(k, 'big') print('k=', k_int) print('r_b=', r_b) v = _string_to_bytes(str(alice_pubkey.blind(r_b, k_int))) print('v=', v) send_msg(s, v) # Step 6: Bob knows which of the two messages can be unblinded with k, so he is able to compute exactly one of the messages m_b=m_b^′−k resp6 = recv_msg(s) resp6_str = _bytes_to_string(resp6) print('resp6_str=', resp6_str) combined_list = resp6_str.split(',') combined_list = list(map(_string_to_bytes, combined_list)) f = Fernet(k) # value = combined_list[args.msg_index] ^ k_int value = f.decrypt(combined_list[args.msg_index]) print('the value is:', value) if resp in [202]: send_msg(s, b'200') # send OK code print('\nTransaction complete')
def ls(conn: socket, args=None): # send list of files filelist = os.listdir('files/') filelist_json = json.dumps(filelist) send_msg(conn, _string_to_bytes(filelist_json))
# Step 1: Alice generates an RSA key pair PK=(n,e) and SK=(d) pubkey, privkey = rsa.newkeys(32, poolsize=8) print(pubkey) print(privkey) # generates n random values, r_0 and r_1, and sends them to Bob along with her PK r_b_choices = [secrets.token_bytes(4) for i in range(args.n_msgs)] json_string = json.dumps({ 'e': pubkey.e, 'n': pubkey.n, 'r_b_choices': list(map(_bytes_to_string, r_b_choices)), }) send_msg(conn, _string_to_bytes(json_string)) # Step 4: Alice doesn't know which of r_0 and r_1 Bob chose. # She applies them both and come up with two possible values for k:k_0=(v−x_0 )^d mod n and k_1=(v−x_1 )^d mod n Eventually, # one of these will be equal to k and can be correctly decrypted by Bob (but not Alice), # while the other will produce a meaningless random value that does not reveal any information about k resp4 = recv_msg(conn) v = _bytes_to_string(resp4) print('v=', v) print('r_b_choices=', r_b_choices) k_list = [privkey.unblind(v, int.from_bytes(r_b, 'big')) for r_b in r_b_choices] print('k_list=', k_list) # combining the message with the key: m' = m+k # combined_msgs = [messages[i] ^ k_list[i] for i in range(args.n_msgs)]