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 put(conn: socket, args=None): # recv file from client and write to file print('receiving file...') client_data = AttrDict(json.loads(_bytes_to_string(recv_msg(conn)))) args.filename = os.path.join('files', args.filename) data = client_data.data if data is None: print("Problem: data received is None") print("got the file data!: {}Bytes".format(len(data))) if not os.path.isdir('./files'): os.mkdir('./files') with open(args.filename, 'wb+') as file: plaintext = args.cipherfunc(data=data, key=args.key, decrypt=True, iv=client_data.iv) file.write(plaintext) print('recieved file:', args.filename) if os.path.isfile(args.filename): subprocess.Popen(r'explorer /select,"{}"'.format(args.filename))
def callback(conn: socket): # receive data resp = AttrDict(json.loads(_bytes_to_string(recv_msg(conn)))) if args.file_index: args.filename = resp.filename delattr(args, 'file_index') if not os.path.isdir('./files'): os.mkdir('./files') filename = args.filename \ if args.filename.startswith('files') \ else os.path.join('files', args.filename) if os.path.isdir(filename): args.filename = os.path.join(args.filename, resp.filename) # === done preparing filesystem === with open(filename, 'wb+') as f: plaintext = args.cipherfunc(data=resp.data, key=args.key, decrypt=True, iv=resp.iv) f.write(plaintext) if os.path.isfile(filename): subprocess.Popen(r'explorer /select,"{}"'.format(filename))
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 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 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')
currentdir = os.path.dirname( os.path.abspath(inspect.getfile(inspect.currentframe()))) parentdir = os.path.dirname(currentdir) sys.path.insert(0, parentdir) from utils import send_msg, recv_msg, SafeArgumentParser, AttrDict from encryption_utils import CipherLib, _string_to_bytes, _bytes_to_string os.chdir(os.path.dirname( os.path.realpath(__file__))) # move path to file dir, to access files # 256 bits = 32 bytes # b'c37ddfe20d88021bc66a06706ac9fbdd0bb2dc0b043cf4d22dbbbcda086f0f48' DEFAULT_KEY = _bytes_to_string( b'\xc3\x7d\xdf\xe2\x0d\x88\x02\x1b\xc6\x6a\x06\x70\x6a\xc9\xfb\xdd\x0b\xb2\xdc\x0b\x04\x3c\xf4\xd2\x2d\xbb\xbc\xda\x08\x6f\x0f\x48' ) def get_arg_parser(): parser = argparse.ArgumentParser("Server side app") parser.add_argument( '--port', default=65431, type=int, help='Port to listen on (non-privileged ports are > 1023)') parser.add_argument('--host', default='127.0.0.1', type=str, help='the ipv4 address to open connections')
# 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)] print('before getting msgs') combined_msgs = [Fernet(k_list[i]).encrypt(messages[i]) for i in range(args.n_msgs)] print('after msg list') combined_msgs = ','.join(list(map(_bytes_to_string, combined_msgs))) # serialized print('sending combined_msgs:', combined_msgs) send_msg(conn, combined_msgs)