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 ') args['auth'] = False # setup IV args['iv'] = secrets.token_bytes(16) request_json = format_args_to_json(args) # 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 = 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 h256(*args): sha256 = hashlib.sha256() for arg in args: if isinstance(arg, int): arg = int_to_bytes(arg) if isinstance(arg, str): arg = _string_to_bytes(arg) sha256.update(arg) return sha256.digest()
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 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) client_args = parse_command_json(command_json) server_resp = _string_to_bytes( json.dumps({ 'readystate': 202, # code "202" meaning (accepted) })) send_msg(conn, server_resp) return client_args
def get(conn: socket, args=None): # send the file to client if args['file_index']: args['filename'] = os.listdir('server_files')[int(args['filename'])] iv = secrets.token_bytes(16) print('iv=', iv) filename = os.path.join('server_files', path_leaf(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 parse_command_json(command_json): client_args = { # extend defaults 'auth': True, '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 # 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(client_args) return client_args
def ls(conn: socket, args=None): # send list of files filelist = os.listdir('server_files/') filelist_json = json.dumps(filelist) send_msg(conn, _string_to_bytes(filelist_json))
def none(data, decrypt=False, key=None, **kwargs) -> bytes: if isinstance(data, str): data = _string_to_bytes(data) return data
def authenticate(args, is_client=True, conn=None): ## setting up asymmetric key # n, e, d, q, p = init_asym_key(is_client) # pubkey = rsa.PublicKey(n, e) # privkey = rsa.PrivateKey(n, e, d, q, p) pubkey, privkey = rsa.newkeys(2048, poolsize=8) ## setting up Diffie Hellmen # Alice is the client, Bob is the server exp, g, m = init_DiffieHellman() # g_x_mod_m = (g ** exp) % m g_x_mod_m = exp_mod(g, exp, m) if is_client: name = "Alice" else: name = "Bob" ## Generating challenge r_challenge = int_from_bytes(secrets.token_bytes(256 // 8)) # 256-b = 8-B ## setting args attrs init_info = { 'r_challenge': r_challenge, 'name': name, 'g_x_mod_m': g_x_mod_m, # Diffie Hellman segment 'n': pubkey.n, 'e': pubkey.e, } name = _string_to_bytes(name) if is_client: with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as conn: print('connecting to server...', end='') conn.connect((args['host'], args['port'])) # connect print('\rConnection established ') if 'test' in args and args['test'] == 2: privkey.d -= 1 ############## # send msg 1 # ############## args['seq'] = 1 args['msg1'] = init_info print('auth: sending auth command and msg1...:', list(args.keys())) send_msg(conn, _string_to_bytes(format_args_to_json(args))) # OK 200 response resp = json.loads(_bytes_to_string(recv_msg(conn))) if resp['readystate'] in [200]: print( "ERROR: server did not respond with OK 200, terminating session..." ) return ############## # recv msg 2 # ############## msg2 = msg2args(recv_msg(conn)) assert msg2['seq'] == 2 print('auth: received msg 2:', list(msg2.keys())) info_b = msg2['info'] name_b = _string_to_bytes(info_b['name']) g_ab_mod_m = compute_dh_key(exp, info_b['g_x_mod_m'], m) # assemble Bob's public key pubkey_b = rsa.PublicKey(info_b['n'], info_b['e']) ## step 2 # H= h256(Alice, Bob, R A , R B , g a mod m, g b mod m, g ab mod m) H = h256(name, name_b, r_challenge, info_b['r_challenge'], g_x_mod_m, info_b['g_x_mod_m'], g_ab_mod_m) ## step 3 verificying secret S_b_signature = msg2['S'].strip(b'\x00') S_b = H + name_b rsa.verify(S_b, S_b_signature, pubkey_b) # build key K = h256(g_ab_mod_m) ## destroy a: print('destroying exponent a:', exp) del exp ############## # send msg 3 # ############## S_a = H + name S_a_signature = rsa.sign(S_a, privkey, 'SHA-256') msg3_payload = name + S_a_signature msg3_ciphertext = CipherLib.aes(msg3_payload, key=K) msg3 = { 'seq': 3, 'payload': msg3_ciphertext, } print('auth: sending msg #3', list(msg3.keys())) # sending E(Alice, S_A ,) print('sending msg3:', msg3) send_msg(conn, args2msg(msg3)) return K else: # if server (Bob) ############## # recv msg 1 # ############## # changing key for testing, auth should fail if 'test' in args and args['test'] == 1: privkey.d -= 1 # client has already sent the stuff msg1 = args['msg1'] assert args['seq'] == 1 print('auth: received msg1', list(msg1.keys())) name_a = _string_to_bytes(msg1['name']) g_ab_mod_m = compute_dh_key(exp, msg1['g_x_mod_m'], m) # assemble Alice's public key pubkey_a = rsa.PublicKey(msg1['n'], msg1['e']) ############## # send msg 2 # ############## # H = h 256 (Alice, Alice, R A , R B , g a mod m, g b mod m, g ab mod m) H = h256(name_a, name, msg1['r_challenge'], r_challenge, msg1['g_x_mod_m'], g_x_mod_m, g_ab_mod_m) S_b = H + name S_b_signature = rsa.sign(S_b, privkey, 'SHA-256') K = h256(g_ab_mod_m) # R_B , g b mod m, S B # this was prepared in the beginning of this function (after init DH) msg2 = { 'seq': 2, 'S': S_b_signature, 'info': init_info, } print('sending msg2:', msg2) send_msg(conn, args2msg(msg2)) ############## # recv msg 3 # ############## msg3_container = msg2args(recv_msg(conn)) assert msg3_container['seq'] == 3 msg3_ciphertext = msg3_container['payload'] msg3 = CipherLib.aes(msg3_ciphertext, decrypt=True, key=K) ## verifying secret S_a_signature = msg3[len(name_a):].strip(b'\x00') S_a = (H + name_a) try: rsa.verify(S_a, S_a_signature, pubkey_a) except rsa.VerificationError as e: print('AUTHENTICATION FAILED!! S_a did not match signature:\n', S_a_signature, ' is not the signature of ', S_a) return False ## destroy b: print('destroying exponent b:', exp) del exp return K