From 762639de8aa95d8ac6b1b8fd9b0178fcd850d57b Mon Sep 17 00:00:00 2001 From: Donovan Date: Thu, 13 Mar 2025 11:08:11 -0500 Subject: [PATCH] refactor render_markdown.py --- docs/nkode_authentication_template.md | 72 +++++++++++++-------------- docs/render_markdown.py | 20 ++++---- 2 files changed, 46 insertions(+), 46 deletions(-) diff --git a/docs/nkode_authentication_template.md b/docs/nkode_authentication_template.md index cfa9cb2..52b0a27 100644 --- a/docs/nkode_authentication_template.md +++ b/docs/nkode_authentication_template.md @@ -36,7 +36,7 @@ policy = NKodePolicy( keypad_size = KeypadSize( numb_of_keys = {{ keypad_size.numb_of_keys }}, - attrs_per_key = {{ keypad_size.attrs_per_key }} # aka number of sets + props_per_key = {{ keypad_size.props_per_key }} # aka number of sets ) customer_id = api.create_new_customer(keypad_size, policy) @@ -44,9 +44,9 @@ customer = api.customers[customer_id] ``` ### Customer Attributes and Sets A customer has users and defines the attributes and set values for all its users. -Since our customer has {{ keypad_size.numb_of_keys }} keys and {{ keypad_size.attrs_per_key }} attributes per key, -this gives a customer interface of {{ keypad_size.numb_of_attrs }} distinct attributes and {{ keypad_size.attrs_per_key }} distinct attribute sets. -Each attribute belongs to one of the {{ keypad_size.attrs_per_key }} sets. Each attribute and set value is a unique 2-byte integer in this example. +Since our customer has {{ keypad_size.numb_of_keys }} keys and {{ keypad_size.props_per_key }} attributes per key, +this gives a customer interface of {{ keypad_size.numb_of_props }} distinct attributes and {{ keypad_size.props_per_key }} distinct attribute sets. +Each attribute belongs to one of the {{ keypad_size.props_per_key }} sets. Each attribute and set value is a unique 2-byte integer in this example. ``` set_vals = customer.attributes.set_vals @@ -56,7 +56,7 @@ Customer Sets: {{ customer_set_vals }} ``` attr_vals = customer.attributes.attr_vals -keypad_view(attr_vals, keypad_size.attrs_per_key) +keypad_view(attr_vals, keypad_size.props_per_key) Customer Attributes: {% for attrs in customer_attr_view -%} @@ -85,15 +85,15 @@ Now that we have a customer, we can create users. To create a new user: The user's interface must be dispersable so the server can determine the user's nkode. The server randomly drops attribute sets until the number of attributes equals the number of keys, making the interface dispersable. -In our case, the server randomly drops {{ keypad_size.attrs_per_key - keypad_size.numb_of_keys }} attribute {{ "sets" if keypad_size.attrs_per_key - keypad_size.numb_of_keys > 1 else "set" }}. -to give us a {{ keypad_size.numb_of_keys }} X {{ keypad_size.numb_of_keys }} keypad with possible index values ranging from 0-{{ keypad_size.numb_of_attrs - 1 }}. +In our case, the server randomly drops {{ keypad_size.props_per_key - keypad_size.numb_of_keys }} attribute {{ "sets" if keypad_size.props_per_key - keypad_size.numb_of_keys > 1 else "set" }}. +to give us a {{ keypad_size.numb_of_keys }} X {{ keypad_size.numb_of_keys }} keypad with possible index values ranging from 0-{{ keypad_size.numb_of_props - 1 }}. Each value in the interface is the index value of a customer attribute. The user never learns what their "real" attribute is. They do not see the index value representing their nKode or the customer server-side value. ``` session_id, signup_interface = api.generate_index_interface(customer_id) -signup_interface_keypad = list_to_matrix(signup_interface, keypad_size.attrs_per_key) +signup_interface_keypad = list_to_matrix(signup_interface, keypad_size.props_per_key) Signup Keypad: {% for key in signup_keypad -%} @@ -110,7 +110,7 @@ If users want to change anything about their interface, they must also change th ``` username = {{ username }} user_passcode = {{ user_passcode }} -selected_keys_set = select_keys_with_passcode_values(user_passcode, signup_interface, keypad_size.attrs_per_key) +selected_keys_set = select_keys_with_passcode_values(user_passcode, signup_interface, keypad_size.props_per_key) Selected Keys {{ selected_keys_set }} @@ -161,11 +161,11 @@ Steps 1-2 are straightforward. For a better idea of how they work, see pyNKode. ##### User Cipher Keys Data Structure ``` -set_key = generate_random_nonrepeating_list(keypad_size.attrs_per_key, max_numb=2**(8*numb_of_bytes)) +set_key = generate_random_nonrepeating_list(keypad_size.props_per_key, max_numb=2**(8*numb_of_bytes)) set_key = xor_lists(set_key, customer_attr.set_vals) UserCipherKeys( - prop_key=generate_random_nonrepeating_list(keypad_size.attrs_per_key * keypad_size.numb_of_keys, max_numb=2**(8*numb_of_bytes)), + prop_key=generate_random_nonrepeating_list(keypad_size.props_per_key * keypad_size.numb_of_keys, max_numb=2**(8*numb_of_bytes)), pass_key=generate_random_nonrepeating_list(max_nkode_len, max_numb=2**(8*numb_of_bytes)), mask_key=generate_random_nonrepeating_list(max_nkode_len, max_numb=2**(8*numb_of_bytes)), set_key=set_key, @@ -176,13 +176,13 @@ UserCipherKeys( ##### User Cipher Keys Values ``` -user_keys = UserCipherKeys( - prop_key = {{ user_keys.prop_key }}, - pass_key = {{ user_keys.pass_key }}, - mask_key = {{ user_keys.mask_key }}, - set_key = {{ user_keys.set_key }}, - salt = {{ user_keys.salt }}, - max_nkode_len = {{ user_keys.max_nkode_len }} +user_cipher = UserCipherKeys( + prop_key = {{ user_cipher.prop_key }}, + pass_key = {{ user_cipher.pass_key }}, + mask_key = {{ user_cipher.mask_key }}, + set_key = {{ user_cipher.set_key }}, + salt = {{ user_cipher.salt }}, + max_nkode_len = {{ user_cipher.max_nkode_len }} ) ``` @@ -219,15 +219,15 @@ Passcode Attr Vals: {{ passcode_server_set }} ``` ``` -padded_passcode_server_set = user_keys.pad_user_mask(passcode_server_set, customer.nkode_policy.max_nkode_len) +padded_passcode_server_set = user_cipher.pad_user_mask(passcode_server_set, customer.nkode_policy.max_nkode_len) set_idx = [customer.attributes.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] +mask_set_keys = [user_cipher.set_key[idx] for idx in set_idx] ciphered_mask = xor_lists(mask_set_keys, padded_passcode_server_set) -ciphered_mask = xor_lists(ciphered_mask, user_keys.mask_key) +ciphered_mask = xor_lists(ciphered_mask, user_cipher.mask_key) -mask = user_keys.encode_base64_str(ciphered_mask) +mask = user_cipher.encode_base64_str(ciphered_mask) Mask: {{ enciphered_nkode.mask }} ``` @@ -238,17 +238,17 @@ Mask: {{ enciphered_nkode.mask }} - code = hash(ciphered_passcode, salt) ``` -ciphered_customer_attrs = xor_lists(customer.attributes.attr_vals, user_keys.prop_key) +ciphered_customer_attrs = xor_lists(customer.attributes.attr_vals, user_cipher.prop_key) passcode_ciphered_attrs = [ciphered_customer_attrs[idx] for idx in 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 = xor_lists(passcode_ciphered_attrs, user_cipher.pass_key) passcode_bytes = int_array_to_bytes(ciphered_code) passcode_digest = base64.b64encode(hashlib.sha256(passcode_bytes).digest()) -hashed_data = bcrypt.hashpw(passcode_digest, user_keys.salt) +hashed_data = bcrypt.hashpw(passcode_digest, user_cipher.salt) code = hashed_data.decode("utf-8") Code: {{ enciphered_nkode.code }} @@ -264,7 +264,7 @@ To login, a user: The client requests the user's login interface. ``` login_interface = api.get_login_interface(username, customer_id) -keypad_view(login_interface, keypad_size.attrs_per_key) +keypad_view(login_interface, keypad_size.props_per_key) ``` The server returns a randomly shuffled interface. Learn more about how the [User Interface Shuffle](nkode_concepts.md/#user-interface-shuffle) works ``` @@ -301,11 +301,11 @@ Recover nKode set values: ``` user = customer.users[username] -user_keys = user.user_keys +user_cipher = user.user_cipher user_mask = user.enciphered_passcode.mask -decoded_mask = user_keys.decode_base64_str(user_mask) -deciphered_mask = xor_lists(decoded_mask, user_keys.mask_key) -set_key_rand_component = xor_lists(set_vals, user_keys.set_key) +decoded_mask = user_cipher.decode_base64_str(user_mask) +deciphered_mask = xor_lists(decoded_mask, user_cipher.mask_key) +set_key_rand_component = xor_lists(set_vals, user_cipher.set_key) passcode_sets = [] for set_cipher in deciphered_mask[:passcode_len]: set_idx = set_key_rand_component.index(set_cipher) @@ -331,7 +331,7 @@ Recall User Passcode: {{ user_passcode }} ``` ### Compare Enciphered Passcodes ``` -enciphered_nkode = user_keys.encipher_salt_hash_code(presumed_selected_attributes_idx, customer.attributes) +enciphered_nkode = user_cipher.encipher_salt_hash_code(presumed_selected_attributes_idx, customer.attributes) ``` If `enciphered_nkode == user.enciphered_passcode.code`, the user's key selection is valid, and the login is successful. @@ -388,8 +388,8 @@ attrs_xor = xor_lists(new_attrs, old_attrs) sets_xor = xor_lists(new_sets, old_sets) for user in customer.users.values(): user.renew = True - user.user_keys.set_key = xor_lists(user.user_keys.set_key, sets_xor) - user.user_keys.prop_key = xor_lists(user.user_keys.prop_key, attrs_xor) + user.user_cipher.set_key = xor_lists(user.user_cipher.set_key, sets_xor) + user.user_cipher.prop_key = xor_lists(user.user_cipher.prop_key, attrs_xor) ``` ##### User prop Key The user's prop key was a randomly generated list of length `numb_of_keys * attr_per_key`. @@ -412,11 +412,11 @@ remains the same. Once the user has a successful login, they get a new salt and cipher keys, and their `enciphered_passcode` is recomputed with the new values. ``` -user.user_keys = UserCipherKeys.new( +user.user_cipher = UserCipherKeys.new( customer.attributes.keypad_size, customer.attributes.set_vals, - user.user_keys.max_nkode_len + user.user_cipher.max_nkode_len ) -user.enciphered_passcode = user.user_keys.encipher_nkode(presumed_selected_attributes_idx, customer.attributes) +user.enciphered_passcode = user.user_cipher.encipher_nkode(presumed_selected_attributes_idx, customer.attributes) user.renew = False ``` diff --git a/docs/render_markdown.py b/docs/render_markdown.py index b6fa7f3..13c9ff9 100644 --- a/docs/render_markdown.py +++ b/docs/render_markdown.py @@ -15,8 +15,9 @@ 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 select_keys_with_passcode_values(user_passcode: list[int], keypad: np.ndarray, attrs_per_key: int) -> list[int]: + indices = [np.where(keypad == attr)[0][0] for attr in user_passcode] + return [int(index // attrs_per_key) for index in indices] def visualize_keypad(keypad_list: np.ndarray, props_per_key: int): @@ -39,7 +40,7 @@ def render_nkode_authentication(data: dict): output = template.render(data) # Print or save the output - output_file = "/Users/donov/Desktop/NKode_documentation/nkode/docs/nkode_authentication.md" + output_file = os.path.expanduser("~/Desktop/nkode_authentication.md") with open(output_file, 'w') as fp: fp.write(output) print("File written successfully") @@ -71,18 +72,17 @@ if __name__ == "__main__": 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) + signup_keypad = signup_interface.reshape(-1, keypad_size.numb_of_keys) username = random_username() passcode_len = 4 - user_passcode = signup_interface[:passcode_len] + user_passcode = signup_interface[:passcode_len].tolist() 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) + confirm_keypad = confirm_interface.reshape(-1, keypad_size.numb_of_keys) selected_keys_confirm = select_keys_with_passcode_values(user_passcode, confirm_interface, keypad_size.numb_of_keys) @@ -121,7 +121,7 @@ if __name__ == "__main__": USER LOGIN """ login_interface = api.get_login_keypad(username, customer_id) - login_keypad = list_to_matrix(login_interface, keypad_size.props_per_key) + login_keypad = login_interface.reshape(-1, 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 @@ -141,7 +141,7 @@ if __name__ == "__main__": 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]) + login_passcode_sets.append(int(set_vals[set_idx])) """ GET PRESUMED ATTRIBUTES @@ -200,7 +200,7 @@ if __name__ == "__main__": 'server_side_attr': server_side_attr, 'confirm_keypad': confirm_keypad, 'selected_keys_confirm': selected_keys_confirm, - 'cipher': user_keys, + 'user_cipher': user_keys, 'passcode_server_attr': passcode_server_attr, 'passcode_server_set': passcode_server_set, 'enciphered_nkode': enciphered_nkode,