Files
pynkode/notebooks/nkode_tutorial.ipynb
2025-03-14 09:35:19 -05:00

822 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-14T14:35:01.634660Z",
"start_time": "2025-03-14T14:35:01.631713Z"
}
},
"outputs": [],
"execution_count": 67
},
{
"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-14T14:35:01.653961Z",
"start_time": "2025-03-14T14:35:01.650229Z"
}
},
"outputs": [],
"execution_count": 68
},
{
"cell_type": "code",
"source": [
"api = NKodeAPI()"
],
"metadata": {
"collapsed": false,
"ExecuteTime": {
"end_time": "2025-03-14T14:35:01.663429Z",
"start_time": "2025-03-14T14:35:01.661723Z"
}
},
"outputs": [],
"execution_count": 69
},
{
"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-14T14:35:01.675378Z",
"start_time": "2025-03-14T14:35:01.671221Z"
}
},
"outputs": [],
"execution_count": 70
},
{
"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-14T14:35:01.692557Z",
"start_time": "2025-03-14T14:35:01.689797Z"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Customer Set Key: [21871 61274 2713 19029 26505 50649]\n",
"Customer properties Key:\n",
"[42655 23174 1254 25551 11488 27210]\n",
"[60953 53938 20104 25057 1695 3339]\n",
"[32918 29164 48427 35503 41361 24040]\n",
"[44451 37655 36339 20189 49770 11581]\n",
"[31824 8094 2501 29432 12778 20956]\n"
]
}
],
"execution_count": 71
},
{
"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-14T14:35:01.702167Z",
"start_time": "2025-03-14T14:35:01.699777Z"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Set to Properties Map:\n",
"21871: [42655 60953 32918 44451 31824]\n",
"61274: [23174 53938 29164 37655 8094]\n",
"2713: [ 1254 20104 48427 36339 2501]\n",
"19029: [25551 25057 35503 20189 29432]\n",
"26505: [11488 1695 41361 49770 12778]\n",
"50649: [27210 3339 24040 11581 20956]\n"
]
}
],
"execution_count": 72
},
{
"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-14T14:35:01.722470Z",
"start_time": "2025-03-14T14:35:01.719357Z"
}
},
"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": [
"[[24 0 12 6 18]\n",
" [28 4 16 10 22]\n",
" [27 3 15 9 21]\n",
" [26 2 14 8 20]\n",
" [25 1 13 7 19]]\n"
]
}
],
"execution_count": 73
},
{
"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-14T14:35:01.746158Z",
"start_time": "2025-03-14T14:35:01.742671Z"
}
},
"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: [24 0 12 6 18]\n",
"Key 1: [28 4 16 10 22]\n",
"Key 2: [27 3 15 9 21]\n",
"Key 3: [26 2 14 8 20]\n",
"Key 4: [25 1 13 7 19]\n",
"User Passcode: [24 0 12 6]\n",
"Selected Keys\n",
"[0, 0, 0, 0]\n",
"User Passcode Server-side properties: [31824, 42655, 32918, 60953]\n"
]
}
],
"execution_count": 74
},
{
"metadata": {
"ExecuteTime": {
"end_time": "2025-03-14T14:35:01.770157Z",
"start_time": "2025-03-14T14:35:01.766784Z"
}
},
"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: [26 3 16 6 19]\n",
"Key 1: [27 0 13 10 20]\n",
"Key 2: [24 4 14 7 21]\n",
"Key 3: [28 1 15 8 18]\n",
"Key 4: [25 2 12 9 22]\n",
"Selected Keys\n",
"[2, 1, 4, 0]\n"
]
}
],
"execution_count": 75
},
{
"metadata": {
"ExecuteTime": {
"end_time": "2025-03-14T14:35:02.101712Z",
"start_time": "2025-03-14T14:35:01.792851Z"
}
},
"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": 76
},
{
"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-14T14:35:02.115075Z",
"start_time": "2025-03-14T14:35:02.110397Z"
}
},
"cell_type": "code",
"source": [
"from src.user_cipher import UserCipher\n",
"\n",
"\n",
"set_key = np.array([46785, 4782, 4405, 44408, 35377, 55527])\n",
"set_key = np.bitwise_xor(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",
" set_key=np.array(set_key),\n",
" salt=b'$2b$12$fX.in.GGAjz3QBBwqSWc6e',\n",
" max_nkode_len=customer.nkode_policy.max_nkode_len, \n",
")\n",
"\n",
"passcode_server_prop = [int(customer.cipher.prop_key[idx]) for idx in user_passcode]\n",
"passcode_server_set = [int(customer.cipher.get_prop_set_val(prop)) for prop in passcode_server_prop]\n",
"print(f\"Passcode Set Vals: {passcode_server_set}\")\n",
"print(f\"Passcode prop Vals: {passcode_server_prop}\")"
],
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Passcode Set Vals: [21871, 21871, 21871, 21871]\n",
"Passcode prop Vals: [31824, 42655, 32918, 60953]\n"
]
}
],
"execution_count": 77
},
{
"metadata": {},
"cell_type": "markdown",
"source": [
"#### Encipher Mask\n",
"Recall:\n",
"1. set_key_i = (set_rand_numb_i ^ set_val_i) \n",
"2. mask_key_i = mask_rand_numb_i\n",
"3. padded_passcode_server_set_i = set_val_i\n",
"4. len(set_key) == len(mask_key) == (padded_passcode_server_set) == max_nkode_len == 10\n",
"where i is the index\n",
" \n",
"- mask_i = mask_key_i ^ padded_passcode_server_set_i ^ set_key_i\n",
"- mask_i = mask_rand_num_i ^ set_val_i ^ set_rand_numb_i ^ set_val_i\n",
"- mask_i = mask_rand_num_i ^ set_rand_numb_i # set_val_i is cancelled out"
]
},
{
"metadata": {
"ExecuteTime": {
"end_time": "2025-03-14T14:35:02.132228Z",
"start_time": "2025-03-14T14:35:02.129307Z"
}
},
"cell_type": "code",
"source": [
"padded_passcode_server_set = user_keys.pad_user_mask(passcode_server_set, customer.cipher.set_key)\n",
"\n",
"set_idx = [customer.cipher.get_set_index(set_val) for set_val in padded_passcode_server_set]\n",
"mask_set_keys = [user_keys.set_key[idx] for idx in set_idx]\n",
"ciphered_mask = np.bitwise_xor(mask_set_keys, padded_passcode_server_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": 78
},
{
"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-14T14:35:02.448903Z",
"start_time": "2025-03-14T14:35:02.143953Z"
}
},
"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": 79
},
{
"metadata": {
"ExecuteTime": {
"end_time": "2025-03-14T14:35:02.459349Z",
"start_time": "2025-03-14T14:35:02.457325Z"
}
},
"cell_type": "code",
"source": [
"from src.models import EncipheredNKode\n",
"\n",
"enciphered_nkode = EncipheredNKode(\n",
" mask=mask,\n",
" code=code,\n",
")"
],
"outputs": [],
"execution_count": 80
},
{
"metadata": {},
"cell_type": "markdown",
"source": [
"### User Login\n",
"1. Get login keypad\n",
"2. Login\n"
]
},
{
"metadata": {
"ExecuteTime": {
"end_time": "2025-03-14T14:35:02.775720Z",
"start_time": "2025-03-14T14:35:02.468856Z"
}
},
"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: [24 25 26 27 28 29]\n",
"Key 1: [0 1 2 3 4 5]\n",
"Key 2: [12 13 14 15 16 17]\n",
"Key 3: [ 6 7 8 9 10 11]\n",
"Key 4: [18 19 20 21 22 23]\n",
"Selected Keys: [0, 1, 2, 3]\n",
"True\n"
]
}
],
"execution_count": 81
},
{
"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_i = (set_key_rand_numb_i ^ set_val_i) \n",
"- mask_i = mask_key_rand_num_i ^ set_key_rand_numb_i\n",
"\n",
"Recover nKode set values: \n",
"- decode mask from base64 to int\n",
"- deciphered_mask = mask ^ mask_key\n",
"- deciphered_mask_i = set_key_rand_numb # mask_key_rand_num_i is cancelled out\n",
"- set_key_rand_component = set_key ^ set_values\n",
"- deduce the set value"
]
},
{
"metadata": {
"ExecuteTime": {
"end_time": "2025-03-14T14:35:02.787442Z",
"start_time": "2025-03-14T14:35:02.784207Z"
}
},
"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.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": [
"[21871, 21871, 21871, 21871]\n"
]
}
],
"execution_count": 82
},
{
"metadata": {},
"cell_type": "markdown",
"source": "### Get Presumed Properties\n"
},
{
"metadata": {
"ExecuteTime": {
"end_time": "2025-03-14T14:35:02.805826Z",
"start_time": "2025-03-14T14:35:02.802523Z"
}
},
"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": 83
},
{
"metadata": {},
"cell_type": "markdown",
"source": "### Compare Enciphered Passcodes"
},
{
"metadata": {
"ExecuteTime": {
"end_time": "2025-03-14T14:35:03.129079Z",
"start_time": "2025-03-14T14:35:02.822467Z"
}
},
"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": 84
},
{
"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-14T14:35:03.757448Z",
"start_time": "2025-03-14T14:35:03.142511Z"
}
},
"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: QUR1wAPG8jJh/nG1LbgMIupAY1I=, code: $2b$12$0Ia665myY64l8.UyKRc4tu/OR.0BG6KFLyXcuDdIXrDkpP6cjo7xO\n",
"mask: QUR1wAPG8jJh/nG1LbgMIupAY1I=, code: $2b$12$0Ia665myY64l8.UyKRc4tu/OR.0BG6KFLyXcuDdIXrDkpP6cjo7xO\n",
"True\n",
"mask: SB1G0mGYnu2Fy2usk08r9uTTugo=, code: $2b$12$pKJtlWu9gwXqA4b.Q/WEZ.yzz9ntnXnFSindkyVOWa3sNOoVd0LLK\n"
]
}
],
"execution_count": 85
},
{
"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-14T14:35:03.770972Z",
"start_time": "2025-03-14T14:35:03.766802Z"
}
},
"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": 86
},
{
"metadata": {},
"cell_type": "markdown",
"source": [
"### Renew User\n",
"\n"
]
},
{
"metadata": {
"ExecuteTime": {
"end_time": "2025-03-14T14:35:03.781705Z",
"start_time": "2025-03-14T14:35:03.779309Z"
}
},
"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.set_key = np.bitwise_xor(user.cipher.set_key, sets_xor)\n",
" user.cipher.prop_key = np.bitwise_xor(user.cipher.prop_key, props_xor)"
],
"outputs": [],
"execution_count": 87
},
{
"metadata": {},
"cell_type": "markdown",
"source": "### Refresh User Keys"
},
{
"metadata": {
"ExecuteTime": {
"end_time": "2025-03-14T14:35:04.107750Z",
"start_time": "2025-03-14T14:35:03.797025Z"
}
},
"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": 88
}
],
"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
}