{ "cells": [ { "cell_type": "code", "source": [ "from src.nkode_api import NKodeAPI\n", "from src.models import NKodePolicy, KeypadSize\n", "from secrets import choice\n", "from string import ascii_lowercase\n", "import numpy as np\n", "import bcrypt\n", "import hashlib\n", "import base64\n", "from IPython.display import Markdown, display\n", "\n", "def random_username() -> str:\n", " return \"test_username\" + \"\".join([choice(ascii_lowercase) for _ in range(6)])\n", "\n", "\n", "def select_keys_with_passcode_values(user_passcode_idxs: list[int], keypad: np.ndarray, props_per_key: int) -> list[int]:\n", " indices = [np.where(keypad == prop)[0][0] for prop in user_passcode_idxs]\n", " return [int(index // props_per_key) for index in indices]\n", "\n", "\n", "def keypad_view(keypad: np.ndarray, props_per_key: int):\n", " interface_keypad = keypad.reshape(-1, props_per_key)\n", " for idx, key_vals in enumerate(interface_keypad):\n", " print(f\"Key {idx}: {key_vals}\")\n" ], "metadata": { "collapsed": false, "ExecuteTime": { "end_time": "2025-03-20T08:32:08.092320Z", "start_time": "2025-03-20T08:32:08.087658Z" } }, "outputs": [], "execution_count": 27 }, { "cell_type": "code", "source": [ "api = NKodeAPI()\n", "user_icons = np.array([\n", " \"😀\", \"😂\", \"🥳\", \"😍\", \"🤓\",\n", " \"😎\", \"🥺\", \"😡\", \"😱\", \"🤯\",\n", " \"🥰\", \"😴\", \"🤔\", \"🙃\", \"😇\",\n", " \"🤖\", \"👽\", \"👾\", \"🐱\", \"🐶\",\n", " \"🦁\", \"🐻\", \"🐸\", \"🐙\", \"🦄\",\n", " \"🌟\", \"⚡\", \"🔥\", \"🍕\", \"🎉\"\n", "])" ], "metadata": { "collapsed": false, "ExecuteTime": { "end_time": "2025-03-20T08:32:08.113043Z", "start_time": "2025-03-20T08:32:08.110624Z" } }, "outputs": [], "execution_count": 28 }, { "metadata": {}, "cell_type": "markdown", "source": [ "### nKode Customer\n", "An nKode customer is business has employees (users). An nKode API can service many customers each with their own users.\n", "Each customer specifies a keypad size and a nkode policy.\n", "The keypad can't be dispersable (`numb_of_keys < properties_per_key`)" ] }, { "cell_type": "markdown", "source": [ "#### Customer Cipher Keys\n", "Each customer has unique cipher keys.\n", "These keys are used to encipher and decipher user nKode.\n", "There are two types of Customer Cipher Keys:\n", "1. property key: Combined with the user property key to get the server-side representation of a users icons.\n", "2. position key: Combined with the user position key to the server-side representation the position in each key.\n" ], "metadata": { "collapsed": false } }, { "cell_type": "code", "source": [ "policy = NKodePolicy(\n", " max_nkode_len=10,\n", " min_nkode_len=4,\n", " distinct_positions=0,\n", " distinct_properties=4,\n", ")\n", "keypad_size = KeypadSize(\n", " numb_of_keys = 5,\n", " props_per_key = 6\n", ")\n", "customer_id = api.create_new_customer(keypad_size, policy)\n", "customer = api.customers[customer_id]\n", "print(f\"Customer Position Key: {customer.cipher.position_key}\")\n", "print(f\"Customer Properties Key:\")\n", "customer_prop_keypad = customer.cipher.property_key.reshape(-1, keypad_size.props_per_key)\n", "for idx, key_vals in enumerate(customer_prop_keypad):\n", " print(f\"{key_vals}\")\n", "position_properties_dict = dict(zip(customer.cipher.position_key, customer_prop_keypad.T))\n", "print(f\"Position to Properties Map:\")\n", "for pos_val, props in position_properties_dict.items():\n", " print(f\"{pos_val}: {props}\")" ], "metadata": { "collapsed": false, "ExecuteTime": { "end_time": "2025-03-20T08:32:08.198233Z", "start_time": "2025-03-20T08:32:08.193182Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Customer Position Key: [21284 3999 4057 48308 14680 46323]\n", "Customer Properties Key:\n", "[45633 21215 48438 45863 52540 14191]\n", "[11907 4042 56372 63103 45179 58318]\n", "[28909 48497 31171 15125 2886 9246]\n", "[15651 10936 5595 16546 8096 13333]\n", "[41923 43364 15227 43001 11056 62605]\n", "Position to Properties Map:\n", "21284: [45633 11907 28909 15651 41923]\n", "3999: [21215 4042 48497 10936 43364]\n", "4057: [48438 56372 31171 5595 15227]\n", "48308: [45863 63103 15125 16546 43001]\n", "14680: [52540 45179 2886 8096 11056]\n", "46323: [14191 58318 9246 13333 62605]\n" ] } ], "execution_count": 29 }, { "metadata": { "ExecuteTime": { "end_time": "2025-03-20T08:32:08.226660Z", "start_time": "2025-03-20T08:32:08.224216Z" } }, "cell_type": "code", "source": [ "user_icon_keypad = user_icons.reshape(-1, keypad_size.props_per_key)\n", "pos_icons_dict = dict(zip(customer.cipher.position_key, user_icon_keypad.T))\n", "print(\"Position Value to Icons Map:\")\n", "for pos_val, icons in pos_icons_dict.items():\n", " print(f\"{pos_val}: {icons}\")\n" ], "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Position Value to Icons Map:\n", "21284: ['😀' '🥺' '🤔' '🐱' '🦄']\n", "3999: ['😂' '😡' '🙃' '🐶' '🌟']\n", "4057: ['🥳' '😱' '😇' '🦁' '⚡']\n", "48308: ['😍' '🤯' '🤖' '🐻' '🔥']\n", "14680: ['🤓' '🥰' '👽' '🐸' '🍕']\n", "46323: ['😎' '😴' '👾' '🐙' '🎉']\n" ] } ], "execution_count": 30 }, { "metadata": {}, "cell_type": "markdown", "source": [ "### User Signup\n", "Users can create an nkode with these steps:\n", "1. Generate a randomly shuffled keypad\n", "2. Set user nKode\n", "3. Confirm user nKode\n", "\n", "#### Generate Keypad\n", " For the server to determine the users nkode, the user's keypad must be dispersable.\n", " To make the keypad dispersable, the server will randomly drop key positions so the number of properties per key is equal to the number of keys.\n", " In our case, the server drops 1 key position to give us a 5 X 5 keypad with possible index values ranging from 0-29.\n", " - Run the cell below over and over to see it change. Notice that values never move out of their columns just their rows.\n", " - each value in the keypad is the index value of a customer properties\n", " - the user never learns what their server-side properties" ] }, { "metadata": { "ExecuteTime": { "end_time": "2025-03-20T08:32:08.256237Z", "start_time": "2025-03-20T08:32:08.250147Z" } }, "cell_type": "code", "source": [ "signup_session_id, set_signup_keypad = api.generate_signup_keypad(customer_id)\n", "display(Markdown(\"\"\"### Icon Keypad\"\"\"))\n", "keypad_view(user_icons[set_signup_keypad], keypad_size.numb_of_keys)\n", "display(Markdown(\"\"\"### Index Keypad\"\"\"))\n", "keypad_view(set_signup_keypad, keypad_size.numb_of_keys)\n", "display(Markdown(\"\"\"### Customer Properties Keypad\"\"\"))\n", "keypad_view(customer.cipher.property_key[set_signup_keypad], keypad_size.numb_of_keys)" ], "outputs": [ { "data": { "text/plain": [ "" ], "text/markdown": "### Icon Keypad" }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "Key 0: ['🦄' '😂' '😇' '👽' '😴']\n", "Key 1: ['🐱' '🌟' '😱' '🐸' '😎']\n", "Key 2: ['🤔' '🙃' '🦁' '🥰' '🐙']\n", "Key 3: ['😀' '😡' '⚡' '🍕' '👾']\n", "Key 4: ['🥺' '🐶' '🥳' '🤓' '🎉']\n" ] }, { "data": { "text/plain": [ "" ], "text/markdown": "### Index Keypad" }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "Key 0: [24 1 14 16 11]\n", "Key 1: [18 25 8 22 5]\n", "Key 2: [12 13 20 10 23]\n", "Key 3: [ 0 7 26 28 17]\n", "Key 4: [ 6 19 2 4 29]\n" ] }, { "data": { "text/plain": [ "" ], "text/markdown": "### Customer Properties Keypad" }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "Key 0: [41923 21215 31171 2886 58318]\n", "Key 1: [15651 43364 56372 8096 14191]\n", "Key 2: [28909 48497 5595 45179 13333]\n", "Key 3: [45633 4042 15227 11056 9246]\n", "Key 4: [11907 10936 48438 52540 62605]\n" ] } ], "execution_count": 31 }, { "metadata": {}, "cell_type": "markdown", "source": [ "## Set nKode\n", "The client receives `user_icons`, `set_signup_keypad`\n" ] }, { "metadata": { "ExecuteTime": { "end_time": "2025-03-20T08:32:08.280568Z", "start_time": "2025-03-20T08:32:08.277339Z" } }, "cell_type": "code", "source": [ "username = random_username()\n", "passcode_len = 4\n", "passcode_property_indices = np.random.choice(set_signup_keypad.reshape(-1), size=passcode_len, replace=False).tolist()\n", "selected_keys_set = select_keys_with_passcode_values(passcode_property_indices, set_signup_keypad, keypad_size.numb_of_keys)\n", "print(f\"User Passcode Indices: {passcode_property_indices}\")\n", "print(f\"User Passcode Icons: {user_icons[passcode_property_indices]}\")\n", "print(f\"User Passcode Server-side properties: {customer.cipher.property_key[passcode_property_indices]}\")\n", "print(f\"Selected Keys: {selected_keys_set}\")" ], "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "User Passcode Indices: [19, 7, 10, 6]\n", "User Passcode Icons: ['🐶' '😡' '🥰' '🥺']\n", "User Passcode Server-side properties: [10936 4042 45179 11907]\n", "Selected Keys: [4, 3, 2, 4]\n" ] } ], "execution_count": 32 }, { "metadata": { "ExecuteTime": { "end_time": "2025-03-20T08:32:08.316148Z", "start_time": "2025-03-20T08:32:08.313495Z" } }, "cell_type": "code", "source": [ "confirm_keypad = api.set_nkode(username, customer_id, selected_keys_set, signup_session_id)\n", "keypad_view(confirm_keypad, keypad_size.numb_of_keys)\n", "selected_keys_confirm = select_keys_with_passcode_values(passcode_property_indices, confirm_keypad, keypad_size.numb_of_keys)\n", "print(f\"Selected Keys\\n{selected_keys_confirm}\")" ], "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Key 0: [18 7 20 4 11]\n", "Key 1: [12 1 26 22 29]\n", "Key 2: [ 0 19 14 10 5]\n", "Key 3: [24 25 2 28 23]\n", "Key 4: [ 6 13 8 16 17]\n", "Selected Keys\n", "[2, 0, 2, 4]\n" ] } ], "execution_count": 33 }, { "metadata": { "ExecuteTime": { "end_time": "2025-03-20T08:32:08.575664Z", "start_time": "2025-03-20T08:32:08.337518Z" } }, "cell_type": "code", "source": [ "# the session is deleted after the nkode is confirmed. To rerun this cell, rerun the cells above starting with cell 8 where the username is created\n", "success = api.confirm_nkode(username, customer_id, selected_keys_confirm, signup_session_id)\n", "assert success" ], "outputs": [], "execution_count": 34 }, { "metadata": {}, "cell_type": "markdown", "source": [ "## User Cipher\n", "\n", "Users have 4 cipher keys:\n", "1. property_key: The counterpart to the `customer_prop_key`. A user's server-side passcode is composed of elements in `user_prop_key XOR customer_prop_key`.\n", "2. pass_key: The passcode key is used to encipher user passcode\n", "3. combined_position_key: The combined position key is `user_pos_key XOR customer_pos_key`.\n", "4. mask_key: The mask key used to encipher user nKode\n", "\n", "\n" ] }, { "metadata": { "ExecuteTime": { "end_time": "2025-03-20T08:32:08.588049Z", "start_time": "2025-03-20T08:32:08.583087Z" } }, "cell_type": "code", "source": [ "from src.user_cipher import UserCipher\n", "user_cipher = UserCipher.create(keypad_size, customer.cipher.position_key, customer.nkode_policy.max_nkode_len)\n", "user_prop_key_keypad = user_cipher.property_key.reshape(-1, keypad_size.props_per_key)" ], "outputs": [], "execution_count": 35 }, { "metadata": { "ExecuteTime": { "end_time": "2025-03-20T08:32:08.596984Z", "start_time": "2025-03-20T08:32:08.595221Z" } }, "cell_type": "code", "source": "print(f\"Property Key:\\n{user_prop_key_keypad}\")", "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Property Key:\n", "[[43643 58945 45655 10493 17462 5635]\n", " [42071 15680 60860 39600 15784 4102]\n", " [60857 21300 14877 25869 12858 50934]\n", " [55451 44486 22660 41758 36853 37697]\n", " [24236 53340 57175 52425 5167 2017]]\n" ] } ], "execution_count": 36 }, { "metadata": { "ExecuteTime": { "end_time": "2025-03-20T08:32:08.615012Z", "start_time": "2025-03-20T08:32:08.613119Z" } }, "cell_type": "code", "source": "print(f\"Passcode Key: {user_cipher.pass_key}\")", "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Passcode Key: [31049 4633 40678 55986 14115 22499 3470 53359 20871 60539]\n" ] } ], "execution_count": 37 }, { "metadata": { "ExecuteTime": { "end_time": "2025-03-20T08:32:08.639696Z", "start_time": "2025-03-20T08:32:08.637469Z" } }, "cell_type": "code", "source": "print(f\"Mask Key: {user_cipher.mask_key}\")", "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Mask Key: [55361 38182 36656 63013 26815 17961 23911 65497 28524 60226]\n" ] } ], "execution_count": 38 }, { "metadata": { "ExecuteTime": { "end_time": "2025-03-20T08:32:08.658960Z", "start_time": "2025-03-20T08:32:08.657009Z" } }, "cell_type": "code", "source": "print(f\"Combined Position Key: {user_cipher.combined_position_key}\")", "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Combined Position Key: [33934 3750 42586 25190 7504 35546]\n" ] } ], "execution_count": 39 }, { "metadata": { "ExecuteTime": { "end_time": "2025-03-20T08:32:08.678360Z", "start_time": "2025-03-20T08:32:08.676228Z" } }, "cell_type": "code", "source": "print(f\"User Position Key = combined_pos_key XOR customer_pos_key: {user_cipher.combined_position_key ^ customer.cipher.position_key}\")", "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "User Position Key = combined_pos_key XOR customer_pos_key: [55210 313 43395 57042 9224 15913]\n" ] } ], "execution_count": 40 }, { "metadata": { "ExecuteTime": { "end_time": "2025-03-20T08:32:08.698976Z", "start_time": "2025-03-20T08:32:08.696420Z" } }, "cell_type": "code", "source": [ "position_properties_dict = dict(zip(user_cipher.combined_position_key, user_prop_key_keypad.T))\n", "print(f\"Combined Position to Properties Map:\")\n", "for pos_val, props in position_properties_dict.items():\n", " print(f\"{pos_val}: {props}\")" ], "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Combined Position to Properties Map:\n", "33934: [43643 42071 60857 55451 24236]\n", "3750: [58945 15680 21300 44486 53340]\n", "42586: [45655 60860 14877 22660 57175]\n", "25190: [10493 39600 25869 41758 52425]\n", "7504: [17462 15784 12858 36853 5167]\n", "35546: [ 5635 4102 50934 37697 2017]\n" ] } ], "execution_count": 41 }, { "metadata": {}, "cell_type": "markdown", "source": [ "#### Encipher Mask\n", "1. Get the `padded_passcode_position_indices`; padded with random position indices to equal length `max_nkode_len`.\n", "2. Recover the `user_position_key`. Recall `user.cipher.combined_position_key = user_position_key XOR customer.cipher.positon_key`\n", "3. Order the `user_position_key` by the `padded_passcode_position_indices`\n", "4. Mask the `ordered_user_position_key`\n", "5. Base 64 encode the mask" ] }, { "metadata": { "ExecuteTime": { "end_time": "2025-03-20T08:32:08.762578Z", "start_time": "2025-03-20T08:32:08.760236Z" } }, "cell_type": "code", "source": [ "padded_passcode_position_indices = customer.cipher.get_passcode_position_indices_padded(list(passcode_property_indices), customer.nkode_policy.max_nkode_len)\n", "user_position_key = user_cipher.combined_position_key ^ customer.cipher.position_key\n", "ordered_user_position_key = user_position_key[padded_passcode_position_indices]\n", "mask = ordered_user_position_key ^ user_cipher.mask_key\n", "encoded_mask = user_cipher.encode_base64_str(mask)" ], "outputs": [], "execution_count": 42 }, { "metadata": {}, "cell_type": "markdown", "source": [ "#### Encipher Passcode\n", "UserCipherKeys.encipher_salt_hash_code:\n", "\n", "- ciphered_customer_prop = alpha_key ^ customer_prop\n", "- ciphered_passcode_i = pass_key_i ^ ciphered_customer_prop_i\n", "- code = hash(ciphered_passcode, salt)" ] }, { "metadata": { "ExecuteTime": { "end_time": "2025-03-20T08:32:09.024060Z", "start_time": "2025-03-20T08:32:08.789902Z" } }, "cell_type": "code", "source": [ "combined_prop_key = customer.cipher.property_key ^ user_cipher.property_key\n", "user_passcode = combined_prop_key[passcode_property_indices]\n", "pad_len = customer.nkode_policy.max_nkode_len - passcode_len\n", "user_passcode_padded = np.concatenate((user_passcode, np.zeros(pad_len, dtype=user_passcode.dtype)))\n", "ciphered_passcode = user_passcode_padded ^ user_cipher.pass_key\n", "passcode_prehash = base64.b64encode(hashlib.sha256(ciphered_passcode.tobytes()).digest())\n", "passcode_hash = bcrypt.hashpw(passcode_prehash, bcrypt.gensalt(rounds=12)).decode(\"utf-8\")" ], "outputs": [], "execution_count": 43 }, { "metadata": {}, "cell_type": "markdown", "source": [ "### Enciphered nKode\n", "An encipher passcode has two parts:\n", "1. Code: the enciphered and hashed passcode\n", "2. Mask: the mask is used to recover the passcode sets. The mask and the users key select are used to recover the property values of the user's passcode\n", "The method UserCipherKeys.encipher_nkode secures a users nKode in the database. This method is called in api.confirm_nkode\n", "```\n", "class EncipheredNKode(BaseModel):\n", " code: str\n", " mask: str\n", "```\n" ] }, { "metadata": { "ExecuteTime": { "end_time": "2025-03-20T08:32:09.032955Z", "start_time": "2025-03-20T08:32:09.030937Z" } }, "cell_type": "code", "source": [ "from src.models import EncipheredNKode\n", "\n", "enciphered_nkode = EncipheredNKode(\n", " mask=encoded_mask,\n", " code=passcode_hash,\n", ")" ], "outputs": [], "execution_count": 44 }, { "metadata": {}, "cell_type": "markdown", "source": [ "### User Login\n", "1. Get login keypad\n", "2. Login\n" ] }, { "metadata": { "ExecuteTime": { "end_time": "2025-03-20T08:32:09.273099Z", "start_time": "2025-03-20T08:32:09.040255Z" } }, "cell_type": "code", "source": [ "login_keypad = api.get_login_keypad(username, customer_id)\n", "keypad_view(login_keypad, keypad_size.props_per_key)\n", "selected_keys_login = select_keys_with_passcode_values(passcode_property_indices, login_keypad, keypad_size.props_per_key)\n", "print(f\"User Passcode: {passcode_property_indices}\\n\")\n", "print(f\"Selected Keys:\\n {selected_keys_login}\\n\")\n", "success = api.login(customer_id, username, selected_keys_login)\n", "assert success" ], "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Key 0: [24 1 14 27 16 11]\n", "Key 1: [18 25 8 3 22 5]\n", "Key 2: [12 13 20 21 10 23]\n", "Key 3: [ 0 7 26 9 28 17]\n", "Key 4: [ 6 19 2 15 4 29]\n", "User Passcode: [19, 7, 10, 6]\n", "\n", "Selected Keys:\n", " [4, 3, 2, 4]\n", "\n" ] } ], "execution_count": 45 }, { "metadata": {}, "cell_type": "markdown", "source": [ "## Validate Login Key Entry\n", "- decipher user mask and recover nkode set values\n", "- get presumed properties from key selection and set values\n", "- encipher, salt and hash presumed properties values and compare it to the users hashed code" ] }, { "metadata": {}, "cell_type": "markdown", "source": [ "### Decipher Mask\n", "Recall:\n", "- combined_set_key = user_set_key ^ customer_set_key\n", "- mask = mask_key ^ ordered_user_set_key\n", "\n", "Recover nKode set values: \n", "- decode mask from base64 to int\n", "- ordered_user_set_key = mask ^ mask_key\n", "- ordered_combined_set_key = ordered_customer_set_key ^ ordered_user_set_key\n", "- deduce the set indices" ] }, { "metadata": { "ExecuteTime": { "end_time": "2025-03-20T08:32:09.282728Z", "start_time": "2025-03-20T08:32:09.279895Z" } }, "cell_type": "code", "source": [ "login_keypad = api.get_login_keypad(username, customer_id)\n", "selected_keys_login = select_keys_with_passcode_values(passcode_property_indices, login_keypad, keypad_size.props_per_key)\n", "user = api.customers[customer_id].users[username]\n", "mask = user.cipher.decode_base64_str(user.enciphered_passcode.mask)\n", "deciphered_mask = mask ^ user.cipher.mask_key\n", "set_key = customer.cipher.position_key ^ user.cipher.combined_position_key\n", "passcode_set_index = [int(np.where(set_key == set_cipher)[0][0]) for set_cipher in deciphered_mask[:passcode_len]]\n", "presumed_selected_properties_idx = customer.users[username].user_keypad.get_prop_idxs_by_keynumb_setidx(selected_keys_login, passcode_set_index)\n", "assert passcode_property_indices == presumed_selected_properties_idx\n" ], "outputs": [], "execution_count": 46 }, { "metadata": {}, "cell_type": "markdown", "source": "### Compare Enciphered Passcodes" }, { "metadata": { "ExecuteTime": { "end_time": "2025-03-20T08:32:09.526068Z", "start_time": "2025-03-20T08:32:09.295445Z" } }, "cell_type": "code", "source": [ "valid_nkode = user.cipher.compare_nkode(presumed_selected_properties_idx, customer.cipher, user.enciphered_passcode.code)\n", "assert valid_nkode\n" ], "outputs": [], "execution_count": 47 }, { "metadata": {}, "cell_type": "markdown", "source": [ "## Renew Properties\n", "1. Renew Customer Properties\n", "2. Renew User Keys\n", "3. Refresh User on Login\n", "\n" ] }, { "metadata": { "ExecuteTime": { "end_time": "2025-03-20T08:32:09.996256Z", "start_time": "2025-03-20T08:32:09.529950Z" } }, "cell_type": "code", "source": [ "def print_user_enciphered_code():\n", " mask = api.customers[customer_id].users[username].enciphered_passcode.mask\n", " code = api.customers[customer_id].users[username].enciphered_passcode.code\n", " print(f\"mask: {mask}, code: {code}\\n\")\n", "\n", "print_user_enciphered_code() \n", "api.renew_keys(customer_id)\n", "print_user_enciphered_code()\n", "\n", "login_keypad = api.get_login_keypad(username, customer_id)\n", "selected_keys_login = select_keys_with_passcode_values(passcode_property_indices, login_keypad, keypad_size.props_per_key)\n", "success = api.login(customer_id, username, selected_keys_login)\n", "assert success\n", "print_user_enciphered_code()" ], "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "mask: cz9m1OunYlEK42X0jRrGAzKvheg=, code: $2b$12$Z.N7qwUTMgSVJFQC9hKgjeQ8owBpZMm5Aa14RQdiJH7C8l61QJENS\n", "\n", "mask: cz9m1OunYlEK42X0jRrGAzKvheg=, code: $2b$12$Z.N7qwUTMgSVJFQC9hKgjeQ8owBpZMm5Aa14RQdiJH7C8l61QJENS\n", "\n", "mask: e+RtDYeB1G1RfuTOjCna6K9xLUU=, code: $2b$12$DHdD52jbBdVoXYArhWCm7eABlnch.tNhO/1Eipygj8fpoUFuPzyEC\n", "\n" ] } ], "execution_count": 48 }, { "metadata": {}, "cell_type": "markdown", "source": [ "#### Renew Customer Keys\n", "- Get old properties and sets\n", "- Replace properties and sets" ] }, { "metadata": { "ExecuteTime": { "end_time": "2025-03-20T08:32:10.012897Z", "start_time": "2025-03-20T08:32:10.009292Z" } }, "cell_type": "code", "source": [ "old_props = customer.cipher.property_key.copy()\n", "old_sets = customer.cipher.position_key.copy()\n", "customer.cipher.renew()\n", "new_props = customer.cipher.property_key\n", "new_sets = customer.cipher.position_key" ], "outputs": [], "execution_count": 49 }, { "metadata": {}, "cell_type": "markdown", "source": [ "### Renew User\n", "\n" ] }, { "metadata": { "ExecuteTime": { "end_time": "2025-03-20T08:32:10.019285Z", "start_time": "2025-03-20T08:32:10.017224Z" } }, "cell_type": "code", "source": [ "props_xor = np.bitwise_xor(new_props, old_props)\n", "sets_xor = np.bitwise_xor(new_sets, old_sets)\n", "for user in customer.users.values():\n", " user.renew = True\n", " user.cipher.combined_position_key = np.bitwise_xor(user.cipher.combined_position_key, sets_xor)\n", " user.cipher.property_key = np.bitwise_xor(user.cipher.property_key, props_xor)" ], "outputs": [], "execution_count": 50 }, { "metadata": {}, "cell_type": "markdown", "source": "### Refresh User Keys" }, { "metadata": { "ExecuteTime": { "end_time": "2025-03-20T08:32:10.260051Z", "start_time": "2025-03-20T08:32:10.026503Z" } }, "cell_type": "code", "source": [ "user.cipher = UserCipher.create(\n", " customer.cipher.keypad_size,\n", " customer.cipher.position_key,\n", " user.cipher.max_nkode_len\n", ")\n", "user.enciphered_passcode = user.cipher.encipher_nkode(presumed_selected_properties_idx, customer.cipher)\n", "user.renew = False" ], "outputs": [], "execution_count": 51 } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 2 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython2", "version": "2.7.6" } }, "nbformat": 4, "nbformat_minor": 0 }