import base64 import hashlib from pathlib import Path import bcrypt import numpy as np from secrets import choice from string import ascii_lowercase from docs.scripts.utils import render_markdown_template, emojis from src.models import NKodePolicy, KeypadSize from src.nkode_api import NKodeAPI from src.user_cipher import UserCipher from src.utils import select_keys_with_passcode_values def display_keypad(icons_array: np.ndarray, props_per_key: int) -> str: icons = "" for idx, row in enumerate(icons_array.reshape(-1, props_per_key)): icons += f"Key {idx}: " icons += str(row) icons += "\n" return icons if __name__ == "__main__": api = NKodeAPI() policy = NKodePolicy( max_nkode_len=10, min_nkode_len=4, distinct_positions=0, distinct_properties=4, ) keypad_size = KeypadSize( numb_of_keys=6, props_per_key=9 ) customer_id = api.create_new_customer(keypad_size, policy) customer = api.get_customer(customer_id) username = "test_username" + "".join([choice(ascii_lowercase) for _ in range(6)]) signup_session_id, set_signup_keypad = api.generate_signup_keypad(customer_id, username) ordered_set_icons = emojis[set_signup_keypad] passcode_len = 4 passcode_property_indices = np.random.choice(set_signup_keypad.reshape(-1), size=passcode_len, replace=False).tolist() selected_keys_set = select_keys_with_passcode_values(passcode_property_indices, set_signup_keypad, keypad_size.numb_of_keys) confirm_keypad = api.set_nkode(customer_id, selected_keys_set, signup_session_id) selected_keys_confirm = select_keys_with_passcode_values(passcode_property_indices, confirm_keypad, keypad_size.numb_of_keys) ordered_confirm_icons = emojis[confirm_keypad] success = api.confirm_nkode(customer_id, selected_keys_confirm, signup_session_id) user = api.customers[customer_id].users[username] combined_prop_key = user.cipher.property_key ^ customer.cipher.property_key user_passcode = combined_prop_key[passcode_property_indices] pad_len = customer.nkode_policy.max_nkode_len - passcode_len padded_passcode = np.concatenate((user_passcode, np.zeros(pad_len, dtype=user_passcode.dtype))) ciphered_passcode = padded_passcode ^ user.cipher.pass_key passcode_prehash = base64.b64encode(hashlib.sha256(ciphered_passcode.tobytes()).digest()) passcode_hash = bcrypt.hashpw(passcode_prehash, bcrypt.gensalt(rounds=12)).decode("utf-8") padded_passcode_position_indices = customer.cipher.get_passcode_position_indices_padded( list(passcode_property_indices), customer.nkode_policy.max_nkode_len) user_position_key = user.cipher.combined_position_key ^ customer.cipher.position_key ordered_user_position_key = user_position_key[padded_passcode_position_indices] mask = ordered_user_position_key ^ user.cipher.mask_key encoded_mask = user.cipher.encode_base64_str(mask) login_keypad = api.get_login_keypad(username, customer_id) selected_keys_login = select_keys_with_passcode_values(passcode_property_indices, login_keypad, keypad_size.props_per_key) old_props = customer.cipher.property_key.copy() old_pos = customer.cipher.position_key.copy() customer.cipher.property_key = np.random.choice(2 ** 16, size=keypad_size.total_props, replace=False) customer.cipher.position_key = np.random.choice(2 ** 16, size=keypad_size.props_per_key, replace=False) new_props = customer.cipher.property_key new_pos = customer.cipher.position_key props_xor = new_props ^ old_props pos_xor = new_pos ^ old_pos user = customer.users[username] new_user_cipher = UserCipher.create(keypad_size, customer.cipher.position_key, policy.max_nkode_len) context = { "max_nkode_len": policy.max_nkode_len, "numb_of_keys": keypad_size.numb_of_keys, "props_per_key": keypad_size.props_per_key, "customer_property_key": customer.cipher.property_key, "customer_position_key": customer.cipher.position_key, "user_property_key": user.cipher.property_key, "pass_key": user.cipher.pass_key, "combined_position_key": user.cipher.combined_position_key, "user_position_key": user_position_key, "mask_key": user.cipher.mask_key, "user_passcode_idxs": passcode_property_indices, "combined_property_key": combined_prop_key, "user_passcode_props": user_passcode, "padded_passcode": padded_passcode, "ciphered_passcode": ciphered_passcode, "code": passcode_hash, "passcode_position_idxs": padded_passcode_position_indices[:passcode_len], "pad_user_passcode_idxs": padded_passcode_position_indices, "ordered_user_position_key":ordered_user_position_key, "mask": mask, "selected_keys": selected_keys_login, "login_keypad": display_keypad(login_keypad, keypad_size.props_per_key), "ordered_keys": login_keypad.reshape(-1, keypad_size.props_per_key)[selected_keys_login], "old_props": old_props, "new_props": new_props, "old_pos": old_pos, "new_pos": new_pos, "xor_props": props_xor, "xor_pos": pos_xor, "inter_user_position": user.cipher.combined_position_key ^ pos_xor, "inter_user_property_key": user.cipher.property_key ^ props_xor, "new_user_position": new_user_cipher.combined_position_key, "new_user_property_key": new_user_cipher.property_key, } render_markdown_template(Path("../templates/encipher_decipher_renew_nkode.template.md"), Path("../encipher_decipher_renew_nkode.md"), context)