refactor render_markdown.py

This commit is contained in:
2025-03-13 11:08:11 -05:00
parent 05226edd09
commit 762639de8a
2 changed files with 46 additions and 46 deletions

View File

@@ -36,7 +36,7 @@ policy = NKodePolicy(
keypad_size = KeypadSize( keypad_size = KeypadSize(
numb_of_keys = {{ keypad_size.numb_of_keys }}, 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) customer_id = api.create_new_customer(keypad_size, policy)
@@ -44,9 +44,9 @@ customer = api.customers[customer_id]
``` ```
### Customer Attributes and Sets ### Customer Attributes and Sets
A customer has users and defines the attributes and set values for all its users. 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, 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_attrs }} distinct attributes and {{ keypad_size.attrs_per_key }} distinct attribute sets. 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.attrs_per_key }} sets. Each attribute and set value is a unique 2-byte integer in this example. 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 set_vals = customer.attributes.set_vals
@@ -56,7 +56,7 @@ Customer Sets: {{ customer_set_vals }}
``` ```
attr_vals = customer.attributes.attr_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: Customer Attributes:
{% for attrs in customer_attr_view -%} {% 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 user's interface must be dispersable so the server can determine the user's nkode.
The server randomly drops attribute sets until The server randomly drops attribute sets until
the number of attributes equals the number of keys, making the interface dispersable. 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" }}. 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_attrs - 1 }}. 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. 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 user never learns what their "real" attribute is. They do not see the index value representing their nKode or
the customer server-side value. the customer server-side value.
``` ```
session_id, signup_interface = api.generate_index_interface(customer_id) 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: Signup Keypad:
{% for key in 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 }} username = {{ username }}
user_passcode = {{ user_passcode }} 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
{{ selected_keys_set }} {{ 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 ##### 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) set_key = xor_lists(set_key, customer_attr.set_vals)
UserCipherKeys( 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)), 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)), mask_key=generate_random_nonrepeating_list(max_nkode_len, max_numb=2**(8*numb_of_bytes)),
set_key=set_key, set_key=set_key,
@@ -176,13 +176,13 @@ UserCipherKeys(
##### User Cipher Keys Values ##### User Cipher Keys Values
``` ```
user_keys = UserCipherKeys( user_cipher = UserCipherKeys(
prop_key = {{ user_keys.prop_key }}, prop_key = {{ user_cipher.prop_key }},
pass_key = {{ user_keys.pass_key }}, pass_key = {{ user_cipher.pass_key }},
mask_key = {{ user_keys.mask_key }}, mask_key = {{ user_cipher.mask_key }},
set_key = {{ user_keys.set_key }}, set_key = {{ user_cipher.set_key }},
salt = {{ user_keys.salt }}, salt = {{ user_cipher.salt }},
max_nkode_len = {{ user_keys.max_nkode_len }} 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] 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(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 }} Mask: {{ enciphered_nkode.mask }}
``` ```
@@ -238,17 +238,17 @@ Mask: {{ enciphered_nkode.mask }}
- code = hash(ciphered_passcode, salt) - 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] passcode_ciphered_attrs = [ciphered_customer_attrs[idx] for idx in passcode]
pad_len = customer.nkode_policy.max_nkode_len - passcode_len pad_len = customer.nkode_policy.max_nkode_len - passcode_len
passcode_ciphered_attrs.extend([0 for _ in range(pad_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_bytes = int_array_to_bytes(ciphered_code)
passcode_digest = base64.b64encode(hashlib.sha256(passcode_bytes).digest()) 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 = hashed_data.decode("utf-8")
Code: {{ enciphered_nkode.code }} Code: {{ enciphered_nkode.code }}
@@ -264,7 +264,7 @@ To login, a user:
The client requests the user's login interface. The client requests the user's login interface.
``` ```
login_interface = api.get_login_interface(username, customer_id) 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 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 = customer.users[username]
user_keys = user.user_keys user_cipher = user.user_cipher
user_mask = user.enciphered_passcode.mask user_mask = user.enciphered_passcode.mask
decoded_mask = user_keys.decode_base64_str(user_mask) decoded_mask = user_cipher.decode_base64_str(user_mask)
deciphered_mask = xor_lists(decoded_mask, user_keys.mask_key) deciphered_mask = xor_lists(decoded_mask, user_cipher.mask_key)
set_key_rand_component = xor_lists(set_vals, user_keys.set_key) set_key_rand_component = xor_lists(set_vals, user_cipher.set_key)
passcode_sets = [] passcode_sets = []
for set_cipher in deciphered_mask[:passcode_len]: for set_cipher in deciphered_mask[:passcode_len]:
set_idx = set_key_rand_component.index(set_cipher) set_idx = set_key_rand_component.index(set_cipher)
@@ -331,7 +331,7 @@ Recall User Passcode: {{ user_passcode }}
``` ```
### Compare Enciphered Passcodes ### 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. 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) sets_xor = xor_lists(new_sets, old_sets)
for user in customer.users.values(): for user in customer.users.values():
user.renew = True user.renew = True
user.user_keys.set_key = xor_lists(user.user_keys.set_key, sets_xor) user.user_cipher.set_key = xor_lists(user.user_cipher.set_key, sets_xor)
user.user_keys.prop_key = xor_lists(user.user_keys.prop_key, attrs_xor) user.user_cipher.prop_key = xor_lists(user.user_cipher.prop_key, attrs_xor)
``` ```
##### User prop Key ##### User prop Key
The user's prop key was a randomly generated list of length `numb_of_keys * attr_per_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 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. with the new values.
``` ```
user.user_keys = UserCipherKeys.new( user.user_cipher = UserCipherKeys.new(
customer.attributes.keypad_size, customer.attributes.keypad_size,
customer.attributes.set_vals, 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 user.renew = False
``` ```

View File

@@ -15,8 +15,9 @@ def random_username() -> str:
return "test_username" + "".join([choice(ascii_lowercase) for _ in range(6)]) 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]: def select_keys_with_passcode_values(user_passcode: list[int], keypad: np.ndarray, attrs_per_key: int) -> list[int]:
return [interface.index(attr) // attrs_per_key for attr in user_passcode] 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): 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) output = template.render(data)
# Print or save the output # 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: with open(output_file, 'w') as fp:
fp.write(output) fp.write(output)
print("File written successfully") print("File written successfully")
@@ -71,18 +72,17 @@ if __name__ == "__main__":
set_attribute_dict = dict(zip(set_vals, attr_set_view)) set_attribute_dict = dict(zip(set_vals, attr_set_view))
session_id, signup_interface = api.generate_signup_keypad(customer_id) 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.numb_of_keys)
signup_keypad = signup_interface.reshape(-1, keypad_size.props_per_key)
username = random_username() username = random_username()
passcode_len = 4 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) 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] 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_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) 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 USER LOGIN
""" """
login_interface = api.get_login_keypad(username, customer_id) 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) 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) success = api.login(customer_id, username, selected_keys_login)
assert success assert success
@@ -141,7 +141,7 @@ if __name__ == "__main__":
login_passcode_sets = [] login_passcode_sets = []
for set_cipher in deciphered_mask[:passcode_len]: for set_cipher in deciphered_mask[:passcode_len]:
set_idx = np.where(set_key_rand_component == set_cipher)[0][0] 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 GET PRESUMED ATTRIBUTES
@@ -200,7 +200,7 @@ if __name__ == "__main__":
'server_side_attr': server_side_attr, 'server_side_attr': server_side_attr,
'confirm_keypad': confirm_keypad, 'confirm_keypad': confirm_keypad,
'selected_keys_confirm': selected_keys_confirm, 'selected_keys_confirm': selected_keys_confirm,
'cipher': user_keys, 'user_cipher': user_keys,
'passcode_server_attr': passcode_server_attr, 'passcode_server_attr': passcode_server_attr,
'passcode_server_set': passcode_server_set, 'passcode_server_set': passcode_server_set,
'enciphered_nkode': enciphered_nkode, 'enciphered_nkode': enciphered_nkode,