{ "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-19T14:18:48.405476Z", "start_time": "2025-03-19T14:18:48.400091Z" } }, "outputs": [], "execution_count": 195 }, { "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-19T14:18:48.416324Z", "start_time": "2025-03-19T14:18:48.413345Z" } }, "outputs": [], "execution_count": 196 }, { "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. Each property belongs to a set.\n", "2. set key: Combined with the user set Key to the 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_sets=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 Set 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", "set_properties_dict = dict(zip(customer.cipher.position_key, customer_prop_keypad.T))\n", "print(f\"Set to Properties Map:\")\n", "for set_val, props in set_properties_dict.items():\n", " print(f\"{set_val}: {props}\")" ], "metadata": { "collapsed": false, "ExecuteTime": { "end_time": "2025-03-19T14:18:48.432441Z", "start_time": "2025-03-19T14:18:48.426289Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Customer Set Key: [52236 1143 22391 5610 24876 51604]\n", "Customer Properties Key:\n", "[48274 26421 59355 34554 61533 13623]\n", "[22492 47901 17487 10515 61939 8923]\n", "[32708 61921 973 1449 52341 29868]\n", "[10212 24136 41690 31747 29169 19891]\n", "[18093 29532 18702 45116 15485 53514]\n", "Set to Properties Map:\n", "52236: [48274 22492 32708 10212 18093]\n", "1143: [26421 47901 61921 24136 29532]\n", "22391: [59355 17487 973 41690 18702]\n", "5610: [34554 10515 1449 31747 45116]\n", "24876: [61533 61939 52341 29169 15485]\n", "51604: [13623 8923 29868 19891 53514]\n" ] } ], "execution_count": 197 }, { "metadata": { "ExecuteTime": { "end_time": "2025-03-19T14:18:48.443885Z", "start_time": "2025-03-19T14:18:48.441137Z" } }, "cell_type": "code", "source": [ "user_icon_keypad = user_icons.reshape(-1, keypad_size.props_per_key)\n", "set_icons_dict = dict(zip(customer.cipher.position_key, user_icon_keypad.T))\n", "print(\"Set to Icons Map:\")\n", "for set_val, icons in set_icons_dict.items():\n", " print(f\"{set_val}: {icons}\")\n" ], "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Set to Icons Map:\n", "52236: ['😀' '🥺' '🤔' '🐱' '🦄']\n", "1143: ['😂' '😡' '🙃' '🐶' '🌟']\n", "22391: ['🥳' '😱' '😇' '🦁' '⚡']\n", "5610: ['😍' '🤯' '🤖' '🐻' '🔥']\n", "24876: ['🤓' '🥰' '👽' '🐸' '🍕']\n", "51604: ['😎' '😴' '👾' '🐙' '🎉']\n" ] } ], "execution_count": 198 }, { "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 properties sets to the number of properties is equal to the number of keys.\n", " In our case, the server drops 1 properties set 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-19T14:21:05.988739Z", "start_time": "2025-03-19T14:21:05.981809Z" } }, "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: [13 2 27 22 17]\n", "Key 1: [ 7 8 9 10 11]\n", "Key 2: [25 20 21 28 5]\n", "Key 3: [19 26 15 16 29]\n", "Key 4: [ 1 14 3 4 23]\n" ] }, { "data": { "text/plain": [ "" ], "text/markdown": "### Customer Properties Keypad" }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "Key 0: [32049 6729 60466 26997 1309]\n", "Key 1: [61686 12369 40030 7765 16822]\n", "Key 2: [29442 13543 37604 7572 18665]\n", "Key 3: [29124 1259 53208 47841 51215]\n", "Key 4: [48741 14803 46096 27958 19258]\n" ] } ], "execution_count": 229 }, { "metadata": {}, "cell_type": "markdown", "source": [ "## Set nKode\n", "The client receives `user_icons`, `set_signup_keypad`\n" ] }, { "metadata": { "ExecuteTime": { "end_time": "2025-03-19T14:22:48.143268Z", "start_time": "2025-03-19T14:22:48.140039Z" } }, "cell_type": "code", "source": [ "username = random_username()\n", "passcode_len = 4\n", "user_passcode_indices = np.random.choice(set_signup_keypad.reshape(-1), size=passcode_len, replace=False).tolist()\n", "selected_keys_set = select_keys_with_passcode_values(user_passcode_indices, set_signup_keypad, keypad_size.numb_of_keys)\n", "print(f\"User Passcode Indices: {user_passcode_indices}\")\n", "print(f\"User Passcode Icons: {user_icons[user_passcode_indices]}\")\n", "print(f\"User Passcode Server-side properties: {customer.cipher.property_key[user_passcode_indices]}\")\n", "print(f\"Selected Keys: {selected_keys_set}\")" ], "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "User Passcode Indices: [11, 22, 1, 23]\n", "User Passcode Icons: ['😴' '🐸' '😂' '🐙']\n", "User Passcode Server-side properties: [16822 26997 48741 19258]\n", "Selected Keys: [1, 0, 4, 4]\n" ] } ], "execution_count": 237 }, { "metadata": { "ExecuteTime": { "end_time": "2025-03-19T14:18:48.697364Z", "start_time": "2025-03-19T14:18:48.694055Z" } }, "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(user_passcode_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: [13 14 9 10 23]\n", "Key 1: [25 20 21 4 17]\n", "Key 2: [ 1 8 15 22 5]\n", "Key 3: [19 26 27 28 11]\n", "Key 4: [ 7 2 3 16 29]\n", "Selected Keys\n", "[2, 2, 3, 0]\n" ] } ], "execution_count": 202 }, { "metadata": { "ExecuteTime": { "end_time": "2025-03-19T14:18:49.028822Z", "start_time": "2025-03-19T14:18:48.719642Z" } }, "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": 203 }, { "metadata": {}, "cell_type": "markdown", "source": [ "## User Cipher\n", "\n", "Users have 4 cipher keys:\n", "1. prop_key: Half of the user's server-side passcode. the counterpart to the `customer_prop_key`. A user's passcode is made from elements in `user_prop_key XOR customer_prop_key`. Each property belongs to a set.\n", "2. pass_key: The passcode key is used to encipher user passcode\n", "3. combined_set_key: The combined set key is `user_set_key XOR customer_set_key`. The user_set_key isn't stored and can't be recovered with the `customer_set_key`\n", "4. mask_key: The mask key used to encipher user nKode\n", "\n", "\n" ] }, { "metadata": { "ExecuteTime": { "end_time": "2025-03-19T14:18:49.044808Z", "start_time": "2025-03-19T14:18:49.038903Z" } }, "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.prop_key.reshape(-1, keypad_size.props_per_key)" ], "outputs": [], "execution_count": 204 }, { "metadata": { "ExecuteTime": { "end_time": "2025-03-19T14:18:49.056184Z", "start_time": "2025-03-19T14:18:49.053919Z" } }, "cell_type": "code", "source": "print(f\"Property Key:\\n{user_prop_key_keypad}\")", "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Property Key:\n", "[[42472 31697 42349 63196 42777 61068]\n", " [ 7243 387 55065 19589 60418 22963]\n", " [26541 59081 11622 22333 35608 42306]\n", " [58621 57412 35828 19293 16394 53334]\n", " [ 5908 43761 45282 44085 8881 21753]]\n" ] } ], "execution_count": 205 }, { "metadata": { "ExecuteTime": { "end_time": "2025-03-19T14:18:49.080744Z", "start_time": "2025-03-19T14:18:49.078469Z" } }, "cell_type": "code", "source": "print(f\"Passcode Key: {user_cipher.pass_key}\")", "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Passcode Key: [15958 16933 12810 19682 61534 54403 52645 54893 63261 22611]\n" ] } ], "execution_count": 206 }, { "metadata": { "ExecuteTime": { "end_time": "2025-03-19T14:18:49.125439Z", "start_time": "2025-03-19T14:18:49.123Z" } }, "cell_type": "code", "source": "print(f\"Mask Key: {user_cipher.mask_key}\")", "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Mask Key: [11511 36348 3693 57612 7883 59516 54039 57361 15218 43846]\n" ] } ], "execution_count": 207 }, { "metadata": { "ExecuteTime": { "end_time": "2025-03-19T14:18:49.154768Z", "start_time": "2025-03-19T14:18:49.152444Z" } }, "cell_type": "code", "source": "print(f\"Combined Set Key: {user_cipher.combined_set_key}\")", "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Combined Set Key: [16302 28740 39642 59999 35588 576]\n" ] } ], "execution_count": 208 }, { "metadata": { "ExecuteTime": { "end_time": "2025-03-19T14:18:49.188943Z", "start_time": "2025-03-19T14:18:49.186648Z" } }, "cell_type": "code", "source": "print(f\"User Set Key = combined_set_key XOR customer_set_key: {user_cipher.combined_set_key ^ customer.cipher.position_key}\")", "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "User Set Key = combined_set_key XOR customer_set_key: [62370 29747 52653 65461 59944 52180]\n" ] } ], "execution_count": 209 }, { "metadata": { "ExecuteTime": { "end_time": "2025-03-19T14:18:49.217942Z", "start_time": "2025-03-19T14:18:49.215165Z" } }, "cell_type": "code", "source": [ "set_properties_dict = dict(zip(user_cipher.combined_set_key, user_prop_key_keypad.T))\n", "print(f\"Combined Set to Properties Map:\")\n", "for set_val, props in set_properties_dict.items():\n", " print(f\"{set_val}: {props}\")" ], "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Combined Set to Properties Map:\n", "16302: [42472 7243 26541 58621 5908]\n", "28740: [31697 387 59081 57412 43761]\n", "39642: [42349 55065 11622 35828 45282]\n", "59999: [63196 19589 22333 19293 44085]\n", "35588: [42777 60418 35608 16394 8881]\n", "576: [61068 22963 42306 53334 21753]\n" ] } ], "execution_count": 210 }, { "metadata": {}, "cell_type": "markdown", "source": [ "#### Encipher Mask\n", "1. Order customer properties by user passcode.\n", "2. Get the set indices (`set_indices`) of the ordered customer properties.\n", "3. Pad the\n", "1. combined_set_key = user_set_key ^ customer_set_key\n", "2. padded_ordered_customer_set = customer_set_key # ordered by user passcode and padded with extra set key values to be equal to max_nkode_len\n", "3. len(set_key) == len(mask_key) == len(padded_ordered_customer_set) == max_nkode_len == 10\n", "where i is the index\n", " \n", "- mask = mask_key ^ padded_ordered_customer_set ^ ordered_combined_set_key\n", "- mask = mask_key ^ (customer_set_key) ^ set_rand_numb ^ set_val\n", "- mask = mask_rand_num ^ set_rand_numb # set_val is cancelled out" ] }, { "metadata": { "ExecuteTime": { "end_time": "2025-03-19T14:18:49.244375Z", "start_time": "2025-03-19T14:18:49.241861Z" } }, "cell_type": "code", "source": [ "set_indices = customer.cipher.get_passcode_position_indices_padded(list(user_passcode_indices), customer.nkode_policy.max_nkode_len)\n", "ordered_combined_set_key = user_cipher.combined_set_key[set_indices]\n", "ordered_customer_set_key = customer.cipher.position_key[set_indices]\n", "ordered_user_set_key = ordered_customer_set_key ^ ordered_combined_set_key\n", "mask = ordered_user_set_key ^ user_cipher.mask_key\n", "encoded_mask = user_cipher.encode_base64_str(mask)" ], "outputs": [], "execution_count": 211 }, { "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-19T14:18:49.575573Z", "start_time": "2025-03-19T14:18:49.268784Z" } }, "cell_type": "code", "source": [ "combined_prop_key = customer.cipher.property_key ^ user_cipher.prop_key\n", "user_passcode = combined_prop_key[user_passcode_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": 212 }, { "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-19T14:18:49.585161Z", "start_time": "2025-03-19T14:18:49.583132Z" } }, "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": 213 }, { "metadata": {}, "cell_type": "markdown", "source": [ "### User Login\n", "1. Get login keypad\n", "2. Login\n" ] }, { "metadata": { "ExecuteTime": { "end_time": "2025-03-19T14:18:49.901534Z", "start_time": "2025-03-19T14:18:49.594710Z" } }, "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(user_passcode_indices, login_keypad, keypad_size.props_per_key)\n", "print(f\"User Passcode: {user_passcode_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: [ 6 19 8 3 4 23]\n", "Key 1: [18 13 2 21 28 5]\n", "Key 2: [12 25 14 15 16 11]\n", "Key 3: [24 7 26 9 22 17]\n", "Key 4: [ 0 1 20 27 10 29]\n", "User Passcode: [15, 1, 19, 23]\n", "\n", "Selected Keys:\n", " [2, 4, 0, 0]\n", "\n" ] } ], "execution_count": 214 }, { "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-19T14:18:49.914512Z", "start_time": "2025-03-19T14:18:49.911338Z" } }, "cell_type": "code", "source": [ "login_keypad = api.get_login_keypad(username, customer_id)\n", "selected_keys_login = select_keys_with_passcode_values(user_passcode_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_set_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 user_passcode_indices == presumed_selected_properties_idx\n" ], "outputs": [], "execution_count": 215 }, { "metadata": {}, "cell_type": "markdown", "source": "### Compare Enciphered Passcodes" }, { "metadata": { "ExecuteTime": { "end_time": "2025-03-19T14:18:50.236818Z", "start_time": "2025-03-19T14:18:49.932427Z" } }, "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": 216 }, { "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-19T14:18:50.851576Z", "start_time": "2025-03-19T14:18:50.240709Z" } }, "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(user_passcode_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: tBqaWnmsGlsclLRq7qdFeuZ/Krg=, code: $2b$12$iBdtB4bRMx9VnWKwAInkwecUx5wwiL1C0DVWO.sk9EG1syVVe2CaS\n", "\n", "mask: tBqaWnmsGlsclLRq7qdFeuZ/Krg=, code: $2b$12$iBdtB4bRMx9VnWKwAInkwecUx5wwiL1C0DVWO.sk9EG1syVVe2CaS\n", "\n", "mask: DpuEwDyPrOF4pAxxozyqUHigaak=, code: $2b$12$ngd6PgpZo/UhIANnrRimlOliRIGwAaS6zbe5gqTzYHPBaeAa3vJsy\n", "\n" ] } ], "execution_count": 217 }, { "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-19T14:18:50.865243Z", "start_time": "2025-03-19T14:18:50.861260Z" } }, "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": 218 }, { "metadata": {}, "cell_type": "markdown", "source": [ "### Renew User\n", "\n" ] }, { "metadata": { "ExecuteTime": { "end_time": "2025-03-19T14:18:50.876670Z", "start_time": "2025-03-19T14:18:50.874092Z" } }, "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_set_key = np.bitwise_xor(user.cipher.combined_set_key, sets_xor)\n", " user.cipher.prop_key = np.bitwise_xor(user.cipher.prop_key, props_xor)" ], "outputs": [], "execution_count": 219 }, { "metadata": {}, "cell_type": "markdown", "source": "### Refresh User Keys" }, { "metadata": { "ExecuteTime": { "end_time": "2025-03-19T14:18:51.191895Z", "start_time": "2025-03-19T14:18:50.885862Z" } }, "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": 220 } ], "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 }