Files
pynkode/notebooks/nkode_tutorial.ipynb

819 lines
24 KiB
Plaintext

{
"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"
],
"metadata": {
"collapsed": false,
"ExecuteTime": {
"end_time": "2025-03-16T11:17:06.665193Z",
"start_time": "2025-03-16T11:17:06.662525Z"
}
},
"outputs": [],
"execution_count": 23
},
{
"cell_type": "code",
"source": [
"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: list[int], keypad: np.ndarray, props_per_key: int) -> list[int]:\n",
" indices = [np.where(keypad == prop)[0][0] for prop in user_passcode]\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",
" print(\"Keypad View\")\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-16T11:17:06.680622Z",
"start_time": "2025-03-16T11:17:06.677352Z"
}
},
"outputs": [],
"execution_count": 24
},
{
"cell_type": "code",
"source": [
"api = NKodeAPI()"
],
"metadata": {
"collapsed": false,
"ExecuteTime": {
"end_time": "2025-03-16T11:17:06.696721Z",
"start_time": "2025-03-16T11:17:06.694897Z"
}
},
"outputs": [],
"execution_count": 25
},
{
"cell_type": "markdown",
"source": [
"# NKode API\n",
"### Customer NKode Policy and Interface\n",
"A customer defines their NKode Policy and their interface. Below we've set:\n",
"- max nkode length = 10\n",
"- min nkode length = 4\n",
"- distinct properties = 4\n",
"- distinct set = 0\n",
"- byte len = 2\n",
"\n",
"This customer also has an interface with 5 keys and 6 properties per key. The number of properties must be greater than the number of keys to be dispersion resistant."
],
"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",
" byte_len=2,\n",
")\n",
"keypad_size = KeypadSize(\n",
" numb_of_keys = 5,\n",
" props_per_key = 6 # aka number of sets\n",
")\n",
"customer_id = api.create_new_customer(keypad_size, policy)\n",
"customer = api.customers[customer_id]"
],
"metadata": {
"collapsed": false,
"ExecuteTime": {
"end_time": "2025-03-16T11:17:06.708524Z",
"start_time": "2025-03-16T11:17:06.704492Z"
}
},
"outputs": [],
"execution_count": 26
},
{
"cell_type": "markdown",
"source": [
"### NKode Customer\n",
"A customer has users and defines the properties and set values for all its users.\n",
"Since our customer has 5 keys and 6 properties per key, this gives a customer interface of 30 distinct properties and 6 distinct properties sets.\n",
"Each properties belongs to one of the 6 sets."
],
"metadata": {
"collapsed": false
}
},
{
"cell_type": "markdown",
"source": "#### Customer and Properties Values",
"metadata": {
"collapsed": false
}
},
{
"cell_type": "code",
"source": [
"print(f\"Customer Set Key: {customer.cipher.set_key}\")\n",
"print(f\"Customer Properties Key:\")\n",
"customer_prop_keypad = customer.cipher.prop_key.reshape(-1, keypad_size.props_per_key)\n",
"for idx, key_vals in enumerate(customer_prop_keypad):\n",
" print(f\"{key_vals}\")"
],
"metadata": {
"collapsed": false,
"ExecuteTime": {
"end_time": "2025-03-16T11:17:06.718027Z",
"start_time": "2025-03-16T11:17:06.715343Z"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Customer Set Key: [51574 4745 25889 18231 60748 18510]\n",
"Customer Properties Key:\n",
"[60468 25732 54355 40123 30642 22334]\n",
"[12163 30704 51913 11579 53335 30868]\n",
"[36499 37185 3991 26970 25932 19506]\n",
"[ 7000 7490 26410 33717 8308 41888]\n",
"[59350 41496 33957 33571 58466 45968]\n"
]
}
],
"execution_count": 27
},
{
"cell_type": "markdown",
"source": "#### Customer Set To Properties Map",
"metadata": {
"collapsed": false
}
},
{
"cell_type": "code",
"source": [
"set_properties_dict = dict(zip(customer.cipher.set_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-16T11:17:06.735483Z",
"start_time": "2025-03-16T11:17:06.733076Z"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Set to Properties Map:\n",
"51574: [60468 12163 36499 7000 59350]\n",
"4745: [25732 30704 37185 7490 41496]\n",
"25889: [54355 51913 3991 26410 33957]\n",
"18231: [40123 11579 26970 33717 33571]\n",
"60748: [30642 53335 25932 8308 58466]\n",
"18510: [22334 30868 19506 41888 45968]\n"
]
}
],
"execution_count": 28
},
{
"metadata": {},
"cell_type": "markdown",
"source": [
"### User Signup\n",
"To create a new must call this endpoints in order:\n",
"1. Generate 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. To make the keypad dispersable, the server will randomly drop properties sets to the number of properties is equal to the number of keys. 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 \"real\" properties is. All they do is specify an index in the customer keypad\n"
]
},
{
"metadata": {
"ExecuteTime": {
"end_time": "2025-03-16T11:17:06.760751Z",
"start_time": "2025-03-16T11:17:06.758403Z"
}
},
"cell_type": "code",
"source": [
"session_id, signup_keypad = api.generate_signup_keypad(customer_id)\n",
"print(signup_keypad.reshape(-1, keypad_size.numb_of_keys))"
],
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[[21 15 9 3 27]\n",
" [22 16 10 4 28]\n",
" [18 12 6 0 24]\n",
" [20 14 8 2 26]\n",
" [23 17 11 5 29]]\n"
]
}
],
"execution_count": 29
},
{
"metadata": {},
"cell_type": "markdown",
"source": [
"#### Set nKode\n",
"The user identifies properties in the keypad they want in their nkode. Each properties in the gui has an index value. Below the user has selected 16, 9, 6, 19. Graphically represent with anything. The only requirement is that the graphical properties must be associated with the same index value everytime the user goes to login. If the user wants to change anything about their keypad(the number of keys, properties or graphical properties), they must also change their nkode."
]
},
{
"metadata": {
"ExecuteTime": {
"end_time": "2025-03-16T11:17:06.783887Z",
"start_time": "2025-03-16T11:17:06.780577Z"
}
},
"cell_type": "code",
"source": [
"keypad_view(signup_keypad, keypad_size.numb_of_keys)\n",
"username = random_username()\n",
"passcode_len = 4\n",
"user_passcode = signup_keypad[:passcode_len]\n",
"selected_keys_set = select_keys_with_passcode_values(user_passcode, signup_keypad, keypad_size.numb_of_keys)\n",
"print(f\"User Passcode: {user_passcode}\")\n",
"print(f\"Selected Keys\\n{selected_keys_set}\")\n",
"server_side_prop = [int(customer.cipher.prop_key[idx]) for idx in user_passcode]\n",
"print(f\"User Passcode Server-side properties: {server_side_prop}\")"
],
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Keypad View\n",
"Key 0: [21 15 9 3 27]\n",
"Key 1: [22 16 10 4 28]\n",
"Key 2: [18 12 6 0 24]\n",
"Key 3: [20 14 8 2 26]\n",
"Key 4: [23 17 11 5 29]\n",
"User Passcode: [21 15 9 3]\n",
"Selected Keys\n",
"[0, 0, 0, 0]\n",
"User Passcode Server-side properties: [33717, 26970, 11579, 40123]\n"
]
}
],
"execution_count": 30
},
{
"metadata": {
"ExecuteTime": {
"end_time": "2025-03-16T11:17:06.799077Z",
"start_time": "2025-03-16T11:17:06.796555Z"
}
},
"cell_type": "code",
"source": [
"confirm_keypad = api.set_nkode(username, customer_id, selected_keys_set, session_id)\n",
"keypad_view(confirm_keypad, keypad_size.numb_of_keys)\n",
"selected_keys_confirm = select_keys_with_passcode_values(user_passcode, confirm_keypad, keypad_size.numb_of_keys)\n",
"print(f\"Selected Keys\\n{selected_keys_confirm}\")"
],
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Keypad View\n",
"Key 0: [18 17 8 4 27]\n",
"Key 1: [23 16 6 3 26]\n",
"Key 2: [22 15 11 2 24]\n",
"Key 3: [21 14 10 0 29]\n",
"Key 4: [20 12 9 5 28]\n",
"Selected Keys\n",
"[3, 2, 4, 1]\n"
]
}
],
"execution_count": 31
},
{
"metadata": {
"ExecuteTime": {
"end_time": "2025-03-16T11:17:07.061018Z",
"start_time": "2025-03-16T11:17:06.824471Z"
}
},
"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, session_id)\n",
"print(success)"
],
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"True\n"
]
}
],
"execution_count": 32
},
{
"metadata": {},
"cell_type": "markdown",
"source": [
"## Enciphering nKode\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",
"\n"
]
},
{
"metadata": {
"ExecuteTime": {
"end_time": "2025-03-16T11:17:07.070338Z",
"start_time": "2025-03-16T11:17:07.066596Z"
}
},
"cell_type": "code",
"source": [
"from src.user_cipher import UserCipher\n",
"\n",
"user_set_key = np.array([46785, 4782, 4405, 44408, 35377, 55527])\n",
"combined_set_key = np.bitwise_xor(user_set_key, customer.cipher.set_key)\n",
"user_keys = UserCipher(\n",
" prop_key = np.array([\n",
" 57200, 8398, 54694, 25997, 30388,\n",
" 46948, 45549, 30364, 49712, 10447,\n",
" 9205, 1777, 10731, 30979, 2795,\n",
" 17068, 56758, 62574, 28641, 11451,\n",
" 26820, 50373, 48783, 25350, 62177,\n",
" 60608, 54242, 4637, 3525, 16313\n",
" ]),\n",
" pass_key=np.array([16090, 38488, 45111, 32674, 46216, 52013, 48980, 36811, 35296, 17206]),\n",
" mask_key=np.array([29575, 43518, 44373, 62063, 37651, 31671, 31663, 65514, 36454, 47325]),\n",
" combined_set_key=np.array(combined_set_key),\n",
" salt=b'$2b$12$fX.in.GGAjz3QBBwqSWc6e',\n",
" max_nkode_len=customer.nkode_policy.max_nkode_len, \n",
")\n",
"\n",
"ordered_customer_prop_key = customer.cipher.prop_key[user_passcode] # [int(customer.cipher.prop_key[idx]) for idx in user_passcode]\n",
"ordered_customer_set_key = [int(customer.cipher.get_prop_set_val(prop)) for prop in ordered_customer_prop_key]\n",
"print(f\"Passcode Set Vals: {ordered_customer_set_key}\")\n",
"print(f\"Passcode Prop Vals: {ordered_customer_prop_key}\")"
],
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Passcode Set Vals: [18231, 18231, 18231, 18231]\n",
"Passcode Prop Vals: [33717 26970 11579 40123]\n"
]
}
],
"execution_count": 33
},
{
"metadata": {},
"cell_type": "markdown",
"source": [
"#### Encipher Mask\n",
"Recall:\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_set_key\n",
"- mask = mask_rand_num ^ set_val ^ set_rand_numb ^ set_val\n",
"- mask = mask_rand_num ^ set_rand_numb # set_val is cancelled out"
]
},
{
"metadata": {
"ExecuteTime": {
"end_time": "2025-03-16T11:17:07.150818Z",
"start_time": "2025-03-16T11:17:07.148125Z"
}
},
"cell_type": "code",
"source": [
"padded_ordered_customer_set = user_keys.pad_user_mask(ordered_customer_set_key, customer.cipher.set_key)\n",
"set_idx = [customer.cipher.get_set_index(set_val) for set_val in padded_ordered_customer_set]\n",
"ordered_set_key = user_keys.combined_set_key[set_idx]\n",
"ciphered_mask = ordered_set_key ^ padded_ordered_customer_set\n",
"ciphered_mask = np.bitwise_xor(ciphered_mask, user_keys.mask_key)\n",
"mask = user_keys.encode_base64_str(ciphered_mask)"
],
"outputs": [],
"execution_count": 34
},
{
"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-16T11:17:07.413741Z",
"start_time": "2025-03-16T11:17:07.177338Z"
}
},
"cell_type": "code",
"source": [
"import bcrypt\n",
"import hashlib\n",
"import base64\n",
"\n",
"ciphered_customer_props = np.bitwise_xor(customer.cipher.prop_key, user_keys.prop_key)\n",
"passcode_ciphered_props = [ciphered_customer_props[idx] for idx in user_passcode]\n",
"pad_len = customer.nkode_policy.max_nkode_len - passcode_len\n",
"\n",
"passcode_ciphered_props.extend([0 for _ in range(pad_len)])\n",
"\n",
"ciphered_code = np.bitwise_xor(passcode_ciphered_props, user_keys.pass_key)\n",
"\n",
"#passcode_bytes = int_array_to_bytes(ciphered_code)\n",
"passcode_bytes = ciphered_code.tobytes()\n",
"passcode_digest = base64.b64encode(hashlib.sha256(passcode_bytes).digest())\n",
"hashed_data = bcrypt.hashpw(passcode_digest, user_keys.salt)\n",
"code = hashed_data.decode(\"utf-8\")"
],
"outputs": [],
"execution_count": 35
},
{
"metadata": {
"ExecuteTime": {
"end_time": "2025-03-16T11:17:07.428200Z",
"start_time": "2025-03-16T11:17:07.426275Z"
}
},
"cell_type": "code",
"source": [
"from src.models import EncipheredNKode\n",
"\n",
"enciphered_nkode = EncipheredNKode(\n",
" mask=mask,\n",
" code=code,\n",
")"
],
"outputs": [],
"execution_count": 36
},
{
"metadata": {},
"cell_type": "markdown",
"source": [
"### User Login\n",
"1. Get login keypad\n",
"2. Login\n"
]
},
{
"metadata": {
"ExecuteTime": {
"end_time": "2025-03-16T11:17:07.668766Z",
"start_time": "2025-03-16T11:17:07.436169Z"
}
},
"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, login_keypad, keypad_size.props_per_key)\n",
"print(f\"Selected Keys: {selected_keys_login}\")\n",
"success = api.login(customer_id, username, selected_keys_login)\n",
"print(success)"
],
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Keypad View\n",
"Key 0: [18 19 20 21 22 23]\n",
"Key 1: [12 13 14 15 16 17]\n",
"Key 2: [ 6 7 8 9 10 11]\n",
"Key 3: [0 1 2 3 4 5]\n",
"Key 4: [24 25 26 27 28 29]\n",
"Selected Keys: [0, 1, 2, 3]\n",
"True\n"
]
}
],
"execution_count": 37
},
{
"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",
"- set_key = (set_key_rand_numb ^ set_val)\n",
"- mask = mask_key_rand_num ^ set_key_rand_numb\n",
"\n",
"Recover nKode set values: \n",
"- decode mask from base64 to int\n",
"- deciphered_mask = mask ^ mask_key\n",
"- deciphered_mask = set_key_rand_numb # mask_key_rand_num is cancelled out\n",
"- set_key_rand_component = set_key ^ set_values\n",
"- deduce the set value"
]
},
{
"metadata": {
"ExecuteTime": {
"end_time": "2025-03-16T11:17:07.679342Z",
"start_time": "2025-03-16T11:17:07.676500Z"
}
},
"cell_type": "code",
"source": [
"user = api.customers[customer_id].users[username]\n",
"decoded_mask = user.cipher.decode_base64_str(user.enciphered_passcode.mask)\n",
"deciphered_mask = np.bitwise_xor(decoded_mask, user.cipher.mask_key)\n",
"set_key = np.bitwise_xor(customer.cipher.set_key, user.cipher.combined_set_key)\n",
"passcode_sets = []\n",
"for set_cipher in deciphered_mask[:passcode_len]:\n",
" set_idx = np.where(set_key == set_cipher)[0][0]\n",
" passcode_sets.append(int(customer.cipher.set_key[set_idx]))\n",
"print(passcode_sets)"
],
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[18231, 18231, 18231, 18231]\n"
]
}
],
"execution_count": 38
},
{
"metadata": {},
"cell_type": "markdown",
"source": "### Get Presumed Properties\n"
},
{
"metadata": {
"ExecuteTime": {
"end_time": "2025-03-16T11:17:07.690303Z",
"start_time": "2025-03-16T11:17:07.687880Z"
}
},
"cell_type": "code",
"source": [
"set_vals_idx = [customer.cipher.get_set_index(set_val) for set_val in passcode_sets]\n",
"\n",
"presumed_selected_properties_idx = []\n",
"for idx in range(passcode_len):\n",
" key_numb = selected_keys_login[idx]\n",
" set_idx = set_vals_idx[idx]\n",
" selected_prop_idx = customer.users[username].user_keypad.get_prop_idx_by_keynumb_setidx(key_numb, set_idx)\n",
" presumed_selected_properties_idx.append(selected_prop_idx)\n",
"\n",
"print(user_passcode.tolist() == presumed_selected_properties_idx)"
],
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"True\n"
]
}
],
"execution_count": 39
},
{
"metadata": {},
"cell_type": "markdown",
"source": "### Compare Enciphered Passcodes"
},
{
"metadata": {
"ExecuteTime": {
"end_time": "2025-03-16T11:17:07.937619Z",
"start_time": "2025-03-16T11:17:07.705824Z"
}
},
"cell_type": "code",
"source": [
"enciphered_nkode = user.cipher.encipher_salt_hash_code(presumed_selected_properties_idx, customer.cipher)\n",
"print(enciphered_nkode == user.enciphered_passcode.code)\n"
],
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"True\n"
]
}
],
"execution_count": 40
},
{
"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-16T11:17:08.414223Z",
"start_time": "2025-03-16T11:17:07.946756Z"
}
},
"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",
"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, login_keypad, keypad_size.props_per_key)\n",
"success = api.login(customer_id, username, selected_keys_login)\n",
"print(success)\n",
"print_user_enciphered_code()"
],
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"mask: zLwyQdPMPUFVeJjeKNJl1nyJ9OA=, code: $2b$12$RBM/q1Vu0bJy3kbYqMCymu5ojiE9bTq5Y7eK2iPR1FGHlnZdjzOHu\n",
"mask: zLwyQdPMPUFVeJjeKNJl1nyJ9OA=, code: $2b$12$RBM/q1Vu0bJy3kbYqMCymu5ojiE9bTq5Y7eK2iPR1FGHlnZdjzOHu\n",
"True\n",
"mask: Q7Dw+o+qDTXYlg8TC2hOkn9r1s0=, code: $2b$12$Xp2oD/vFDHwzvBmELBxC6e.iLK4xn5ZtLwW4UCFVoFY2ioTvGaWwa\n"
]
}
],
"execution_count": 41
},
{
"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-16T11:17:08.424680Z",
"start_time": "2025-03-16T11:17:08.421148Z"
}
},
"cell_type": "code",
"source": [
"old_props = customer.cipher.prop_key.copy()\n",
"old_sets = customer.cipher.set_key.copy()\n",
"customer.cipher.renew()\n",
"new_props = customer.cipher.prop_key\n",
"new_sets = customer.cipher.set_key"
],
"outputs": [],
"execution_count": 42
},
{
"metadata": {},
"cell_type": "markdown",
"source": [
"### Renew User\n",
"\n"
]
},
{
"metadata": {
"ExecuteTime": {
"end_time": "2025-03-16T11:17:08.434263Z",
"start_time": "2025-03-16T11:17:08.431951Z"
}
},
"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": 43
},
{
"metadata": {},
"cell_type": "markdown",
"source": "### Refresh User Keys"
},
{
"metadata": {
"ExecuteTime": {
"end_time": "2025-03-16T11:17:08.683077Z",
"start_time": "2025-03-16T11:17:08.447107Z"
}
},
"cell_type": "code",
"source": [
"user.cipher = UserCipher.create(\n",
" customer.cipher.keypad_size,\n",
" customer.cipher.set_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": 44
}
],
"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
}