import numpy as np from jinja2 import Environment, FileSystemLoader import os from src.nkode_api import NKodeAPI from src.models import NKodePolicy, KeypadSize, EncipheredNKode from src.user_cipher import UserCipher from secrets import choice from string import ascii_lowercase import bcrypt import hashlib import base64 def random_username() -> str: return "test_username" + "".join([choice(ascii_lowercase) for _ in range(6)]) def select_keys_with_passcode_values(user_passcode: list[int], interface: list[int], attrs_per_key: int) -> list[int]: return [interface.index(attr) // attrs_per_key for attr in user_passcode] def visualize_keypad(keypad_list: np.ndarray, props_per_key: int): print("Keypad View") keypad_mat = keypad_list.reshape(-1, props_per_key) for idx, key_vals in enumerate(keypad_mat): print(f"Key {idx}: {key_vals}") def render_nkode_authentication(data: dict): # Set up the Jinja2 environment and template loader file_loader = FileSystemLoader('') env = Environment(loader=file_loader) # Load the template template = env.get_template('nkode_authentication_template.md') print(os.getcwd()) # Render the template with the data output = template.render(data) # Print or save the output output_file = "/Users/donov/Desktop/NKode_documentation/nkode/docs/nkode_authentication.md" with open(output_file, 'w') as fp: fp.write(output) print("File written successfully") if __name__ == "__main__": api = NKodeAPI() policy = NKodePolicy( max_nkode_len=10, min_nkode_len=4, distinct_sets=0, distinct_attributes=4, byte_len=2, ) keypad_size = KeypadSize( numb_of_keys=5, props_per_key=6 # aka number of sets ) customer_id = api.create_new_customer(keypad_size, policy) customer = api.customers[customer_id] set_vals = customer.cipher.set_key attr_vals = customer.cipher.prop_key customer_attr_view = attr_vals.reshape(-1, keypad_size.props_per_key) attr_keypad_view = attr_vals.reshape(-1, keypad_size.props_per_key) attr_set_view = attr_keypad_view.T set_attribute_dict = dict(zip(set_vals, attr_set_view)) session_id, signup_interface = api.generate_signup_keypad(customer_id) #signup_keypad = list_to_matrix(signup_keypad, keypad_size.numb_of_keys) signup_keypad = signup_interface.reshape(-1, keypad_size.props_per_key) username = random_username() passcode_len = 4 user_passcode = signup_interface[:passcode_len] selected_keys_set = select_keys_with_passcode_values(user_passcode, signup_interface, keypad_size.numb_of_keys) server_side_attr = [customer.cipher.prop_key[idx] for idx in user_passcode] confirm_interface = api.set_nkode(username, customer_id, selected_keys_set, session_id) confirm_keypad = list_to_matrix(confirm_interface, keypad_size.numb_of_keys) selected_keys_confirm = select_keys_with_passcode_values(user_passcode, confirm_interface, keypad_size.numb_of_keys) success = api.confirm_nkode(username, customer_id, selected_keys_confirm, session_id) assert success passcode_server_attr = [customer.cipher.prop_key[idx] for idx in user_passcode] passcode_server_set = [customer.cipher.get_prop_set_val(attr) for attr in passcode_server_attr] user_keys = customer.users[username].cipher padded_passcode_server_set = user_keys.pad_user_mask(np.array(passcode_server_set), customer.cipher.set_key) set_idx = [customer.cipher.get_set_index(set_val) for set_val in padded_passcode_server_set] mask_set_keys = [user_keys.set_key[idx] for idx in set_idx] ciphered_mask = np.bitwise_xor(mask_set_keys, padded_passcode_server_set) ciphered_mask = np.bitwise_xor(ciphered_mask, user_keys.mask_key) mask = user_keys.encode_base64_str(ciphered_mask) #ciphered_customer_attrs = xor_lists(customer.cipher.prop_key, user_keys.prop_key) ciphered_customer_attrs = np.bitwise_xor(customer.cipher.prop_key, user_keys.prop_key) passcode_ciphered_attrs = [ciphered_customer_attrs[idx] for idx in user_passcode] pad_len = customer.nkode_policy.max_nkode_len - passcode_len passcode_ciphered_attrs.extend([0 for _ in range(pad_len)]) #ciphered_code = xor_lists(passcode_ciphered_attrs, user_keys.pass_key) ciphered_code = np.bitwise_xor(passcode_ciphered_attrs, user_keys.pass_key) #passcode_bytes = int_array_to_bytes(ciphered_code) passcode_bytes = ciphered_code.tobytes() passcode_digest = base64.b64encode(hashlib.sha256(passcode_bytes).digest()) hashed_data = bcrypt.hashpw(passcode_digest, user_keys.salt) code = hashed_data.decode("utf-8") enciphered_nkode = EncipheredNKode( mask=mask, code=code, ) """ USER LOGIN """ login_interface = api.get_login_keypad(username, customer_id) login_keypad = list_to_matrix(login_interface, keypad_size.props_per_key) selected_keys_login = select_keys_with_passcode_values(user_passcode, login_interface, keypad_size.props_per_key) success = api.login(customer_id, username, selected_keys_login) assert success """ VALIDATE LOGIN KEY ENTRY DECIPHER MASK """ user = customer.users[username] set_vals = customer.cipher.set_key user_keys = user.cipher user_mask = user.enciphered_passcode.mask decoded_mask = user_keys.decode_base64_str(user_mask) deciphered_mask = np.bitwise_xor(decoded_mask, user_keys.mask_key) set_key_rand_component = np.bitwise_xor(set_vals, user_keys.set_key) login_passcode_sets = [] for set_cipher in deciphered_mask[:passcode_len]: set_idx = np.where(set_key_rand_component == set_cipher)[0][0] login_passcode_sets.append(set_vals[set_idx]) """ GET PRESUMED ATTRIBUTES """ set_vals_idx = [customer.cipher.get_set_index(set_val) for set_val in login_passcode_sets] presumed_selected_attributes_idx = [] for idx in range(passcode_len): key_numb = selected_keys_login[idx] set_idx = set_vals_idx[idx] selected_attr_idx = customer.users[username].user_keypad.get_attr_idx_by_keynumb_setidx(key_numb, set_idx) presumed_selected_attributes_idx.append(selected_attr_idx) """ RENEW KEYS """ old_attrs = customer.cipher.prop_key.copy() old_sets = customer.cipher.set_key.copy() customer.cipher.renew() new_attrs = customer.cipher.prop_key new_sets = customer.cipher.set_key customer_new_attr_view = new_attrs.reshape(-1, keypad_size.props_per_key) """ RENEW USER """ attrs_xor = np.bitwise_xor(new_attrs, old_attrs) sets_xor = np.bitwise_xor(new_sets, old_sets) for user in customer.users.values(): user.renew = True user.cipher.set_key = np.bitwise_xor(user.cipher.set_key, sets_xor) user.cipher.prop_key = np.bitwise_xor(user.cipher.prop_key, attrs_xor) """ REFRESH USER KEYS """ user.cipher = UserCipher.create( customer.cipher.keypad_size, customer.cipher.set_key, user.cipher.max_nkode_len ) user.enciphered_passcode = user.cipher.encipher_nkode(presumed_selected_attributes_idx, customer.cipher) user.renew = False # Define some data to pass to the template data = { 'keypad_size': keypad_size, 'customer_set_vals': set_vals, 'customer_attr_view': customer_attr_view, 'set_attribute_dict': set_attribute_dict, 'signup_keypad': signup_keypad, 'username': 'test_user', 'user_passcode': user_passcode, 'selected_keys_set': selected_keys_set, 'server_side_attr': server_side_attr, 'confirm_keypad': confirm_keypad, 'selected_keys_confirm': selected_keys_confirm, 'cipher': user_keys, 'passcode_server_attr': passcode_server_attr, 'passcode_server_set': passcode_server_set, 'enciphered_nkode': enciphered_nkode, 'login_keypad': login_keypad, 'selected_login_keys': selected_keys_login, 'login_passcode_sets': login_passcode_sets, 'presumed_selected_attributes_idx': presumed_selected_attributes_idx, 'customer_new_attr_view': customer_new_attr_view, 'customer_new_set_vals': new_sets, } render_nkode_authentication(data)