822 lines
24 KiB
Plaintext
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\n",
|
|
"import bcrypt"
|
|
],
|
|
"metadata": {
|
|
"collapsed": false,
|
|
"ExecuteTime": {
|
|
"end_time": "2025-03-16T12:51:50.430038Z",
|
|
"start_time": "2025-03-16T12:51:50.426267Z"
|
|
}
|
|
},
|
|
"outputs": [],
|
|
"execution_count": 17
|
|
},
|
|
{
|
|
"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-16T12:51:50.441672Z",
|
|
"start_time": "2025-03-16T12:51:50.437979Z"
|
|
}
|
|
},
|
|
"outputs": [],
|
|
"execution_count": 18
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"source": [
|
|
"api = NKodeAPI()"
|
|
],
|
|
"metadata": {
|
|
"collapsed": false,
|
|
"ExecuteTime": {
|
|
"end_time": "2025-03-16T12:51:50.451921Z",
|
|
"start_time": "2025-03-16T12:51:50.449896Z"
|
|
}
|
|
},
|
|
"outputs": [],
|
|
"execution_count": 19
|
|
},
|
|
{
|
|
"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-16T12:51:50.462932Z",
|
|
"start_time": "2025-03-16T12:51:50.458899Z"
|
|
}
|
|
},
|
|
"outputs": [],
|
|
"execution_count": 20
|
|
},
|
|
{
|
|
"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-16T12:51:50.471838Z",
|
|
"start_time": "2025-03-16T12:51:50.469241Z"
|
|
}
|
|
},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"Customer Set Key: [29252 55146 27501 36339 61988 56812]\n",
|
|
"Customer Properties Key:\n",
|
|
"[58958 438 23479 56544 19227 62335]\n",
|
|
"[19972 45333 49189 28952 25210 7101]\n",
|
|
"[27924 36712 27932 6192 11310 25890]\n",
|
|
"[41961 42300 62264 30572 21755 25167]\n",
|
|
"[56659 59117 55559 18611 58570 62570]\n"
|
|
]
|
|
}
|
|
],
|
|
"execution_count": 21
|
|
},
|
|
{
|
|
"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-16T12:51:50.482832Z",
|
|
"start_time": "2025-03-16T12:51:50.480624Z"
|
|
}
|
|
},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"Set to Properties Map:\n",
|
|
"29252: [58958 19972 27924 41961 56659]\n",
|
|
"55146: [ 438 45333 36712 42300 59117]\n",
|
|
"27501: [23479 49189 27932 62264 55559]\n",
|
|
"36339: [56544 28952 6192 30572 18611]\n",
|
|
"61988: [19227 25210 11310 21755 58570]\n",
|
|
"56812: [62335 7101 25890 25167 62570]\n"
|
|
]
|
|
}
|
|
],
|
|
"execution_count": 22
|
|
},
|
|
{
|
|
"metadata": {},
|
|
"cell_type": "markdown",
|
|
"source": [
|
|
"### User Signup\n",
|
|
"To create a new must call this endpoints in order:\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 \"real\" properties is. All they do is specify an index in the customer keypad\n"
|
|
]
|
|
},
|
|
{
|
|
"metadata": {
|
|
"ExecuteTime": {
|
|
"end_time": "2025-03-16T12:51:50.496968Z",
|
|
"start_time": "2025-03-16T12:51:50.494830Z"
|
|
}
|
|
},
|
|
"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": [
|
|
"[[10 4 22 16 28]\n",
|
|
" [11 5 23 17 29]\n",
|
|
" [ 9 3 21 15 27]\n",
|
|
" [ 8 2 20 14 26]\n",
|
|
" [ 7 1 19 13 25]]\n"
|
|
]
|
|
}
|
|
],
|
|
"execution_count": 23
|
|
},
|
|
{
|
|
"metadata": {},
|
|
"cell_type": "markdown",
|
|
"source": [
|
|
"#### Set nKode\n",
|
|
"The user identifies properties in the keypad they want in their nkode.\n",
|
|
"Each properties in the gui has an index value.\n",
|
|
"Below the user has selected 16, 9, 6, 19.\n",
|
|
"Graphically represent with anything.\n",
|
|
"The only requirement is that the graphical properties must be associated with the same index value everytime the user goes to login.\n",
|
|
"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-16T12:51:50.521411Z",
|
|
"start_time": "2025-03-16T12:51:50.518203Z"
|
|
}
|
|
},
|
|
"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: [10 4 22 16 28]\n",
|
|
"Key 1: [11 5 23 17 29]\n",
|
|
"Key 2: [ 9 3 21 15 27]\n",
|
|
"Key 3: [ 8 2 20 14 26]\n",
|
|
"Key 4: [ 7 1 19 13 25]\n",
|
|
"User Passcode: [10 4 22 16]\n",
|
|
"Selected Keys\n",
|
|
"[0, 0, 0, 0]\n",
|
|
"User Passcode Server-side properties: [25210, 19227, 21755, 11310]\n"
|
|
]
|
|
}
|
|
],
|
|
"execution_count": 24
|
|
},
|
|
{
|
|
"metadata": {
|
|
"ExecuteTime": {
|
|
"end_time": "2025-03-16T12:51:50.539870Z",
|
|
"start_time": "2025-03-16T12:51:50.536979Z"
|
|
}
|
|
},
|
|
"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: [ 7 2 22 15 29]\n",
|
|
"Key 1: [ 9 4 23 14 25]\n",
|
|
"Key 2: [ 8 5 19 16 27]\n",
|
|
"Key 3: [10 1 21 17 26]\n",
|
|
"Key 4: [11 3 20 13 28]\n",
|
|
"Selected Keys\n",
|
|
"[3, 1, 0, 2]\n"
|
|
]
|
|
}
|
|
],
|
|
"execution_count": 25
|
|
},
|
|
{
|
|
"metadata": {
|
|
"ExecuteTime": {
|
|
"end_time": "2025-03-16T12:51:50.790192Z",
|
|
"start_time": "2025-03-16T12:51:50.552031Z"
|
|
}
|
|
},
|
|
"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": 26
|
|
},
|
|
{
|
|
"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-16T12:51:50.801004Z",
|
|
"start_time": "2025-03-16T12:51:50.797001Z"
|
|
}
|
|
},
|
|
"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 = 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",
|
|
" 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: [61988, 61988, 61988, 61988]\n",
|
|
"Passcode Prop Vals: [25210 19227 21755 11310]\n"
|
|
]
|
|
}
|
|
],
|
|
"execution_count": 27
|
|
},
|
|
{
|
|
"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_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-16T12:51:50.811181Z",
|
|
"start_time": "2025-03-16T12:51:50.808721Z"
|
|
}
|
|
},
|
|
"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",
|
|
"mask = ordered_set_key ^ padded_ordered_customer_set ^ user_keys.mask_key\n",
|
|
"encoded_mask = user_keys.encode_base64_str(mask)"
|
|
],
|
|
"outputs": [],
|
|
"execution_count": 28
|
|
},
|
|
{
|
|
"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-16T12:51:51.058527Z",
|
|
"start_time": "2025-03-16T12:51:50.823135Z"
|
|
}
|
|
},
|
|
"cell_type": "code",
|
|
"source": [
|
|
"import hashlib\n",
|
|
"import base64\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 = ciphered_code.tobytes()\n",
|
|
"passcode_digest = user_keys.prehash_passcode(user_passcode, customer.cipher)# base64.b64encode(hashlib.sha256(passcode_bytes).digest())\n",
|
|
"hashed_data = bcrypt.hashpw(passcode_digest, bcrypt.gensalt(rounds=12))\n",
|
|
"code = hashed_data.decode(\"utf-8\")"
|
|
],
|
|
"outputs": [],
|
|
"execution_count": 29
|
|
},
|
|
{
|
|
"metadata": {
|
|
"ExecuteTime": {
|
|
"end_time": "2025-03-16T12:51:51.063978Z",
|
|
"start_time": "2025-03-16T12:51:51.061965Z"
|
|
}
|
|
},
|
|
"cell_type": "code",
|
|
"source": [
|
|
"from src.models import EncipheredNKode\n",
|
|
"\n",
|
|
"enciphered_nkode = EncipheredNKode(\n",
|
|
" mask=encoded_mask,\n",
|
|
" code=code,\n",
|
|
")"
|
|
],
|
|
"outputs": [],
|
|
"execution_count": 30
|
|
},
|
|
{
|
|
"metadata": {},
|
|
"cell_type": "markdown",
|
|
"source": [
|
|
"### User Login\n",
|
|
"1. Get login keypad\n",
|
|
"2. Login\n"
|
|
]
|
|
},
|
|
{
|
|
"metadata": {
|
|
"ExecuteTime": {
|
|
"end_time": "2025-03-16T12:51:51.305419Z",
|
|
"start_time": "2025-03-16T12:51:51.071190Z"
|
|
}
|
|
},
|
|
"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: [ 6 7 8 9 10 11]\n",
|
|
"Key 1: [0 1 2 3 4 5]\n",
|
|
"Key 2: [18 19 20 21 22 23]\n",
|
|
"Key 3: [12 13 14 15 16 17]\n",
|
|
"Key 4: [24 25 26 27 28 29]\n",
|
|
"Selected Keys: [0, 1, 2, 3]\n",
|
|
"True\n"
|
|
]
|
|
}
|
|
],
|
|
"execution_count": 31
|
|
},
|
|
{
|
|
"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-16T12:51:51.315072Z",
|
|
"start_time": "2025-03-16T12:51:51.312249Z"
|
|
}
|
|
},
|
|
"cell_type": "code",
|
|
"source": [
|
|
"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.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": [
|
|
"[61988, 61988, 61988, 61988]\n"
|
|
]
|
|
}
|
|
],
|
|
"execution_count": 32
|
|
},
|
|
{
|
|
"metadata": {},
|
|
"cell_type": "markdown",
|
|
"source": "### Get Presumed Properties\n"
|
|
},
|
|
{
|
|
"metadata": {
|
|
"ExecuteTime": {
|
|
"end_time": "2025-03-16T12:51:51.324331Z",
|
|
"start_time": "2025-03-16T12:51:51.321676Z"
|
|
}
|
|
},
|
|
"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": 33
|
|
},
|
|
{
|
|
"metadata": {},
|
|
"cell_type": "markdown",
|
|
"source": "### Compare Enciphered Passcodes"
|
|
},
|
|
{
|
|
"metadata": {
|
|
"ExecuteTime": {
|
|
"end_time": "2025-03-16T12:51:51.571291Z",
|
|
"start_time": "2025-03-16T12:51:51.338129Z"
|
|
}
|
|
},
|
|
"cell_type": "code",
|
|
"source": [
|
|
"enciphered_nkode = user.cipher.compare_nkode(presumed_selected_properties_idx, customer.cipher, user.enciphered_passcode.code)\n",
|
|
"print(enciphered_nkode)\n"
|
|
],
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"True\n"
|
|
]
|
|
}
|
|
],
|
|
"execution_count": 34
|
|
},
|
|
{
|
|
"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-16T12:51:52.048827Z",
|
|
"start_time": "2025-03-16T12:51:51.579003Z"
|
|
}
|
|
},
|
|
"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: 8T1ZD3B2c6v+ofoNRIzBbqxVYFw=, code: $2b$12$lAmbDegOx03xLmrB//ZCh.1dyrjtpEmAdv1TWNUO/XjjPofQItzVq\n",
|
|
"mask: 8T1ZD3B2c6v+ofoNRIzBbqxVYFw=, code: $2b$12$lAmbDegOx03xLmrB//ZCh.1dyrjtpEmAdv1TWNUO/XjjPofQItzVq\n",
|
|
"True\n",
|
|
"mask: rY763sxEo+aU8G2h7Avf9btV0h8=, code: $2b$12$ZB.x5hSFVjDg4niUAL7TsOtwkTG2uXedMsnFqXNjm0Y0SDf5fgOui\n"
|
|
]
|
|
}
|
|
],
|
|
"execution_count": 35
|
|
},
|
|
{
|
|
"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-16T12:51:52.059119Z",
|
|
"start_time": "2025-03-16T12:51:52.055816Z"
|
|
}
|
|
},
|
|
"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": 36
|
|
},
|
|
{
|
|
"metadata": {},
|
|
"cell_type": "markdown",
|
|
"source": [
|
|
"### Renew User\n",
|
|
"\n"
|
|
]
|
|
},
|
|
{
|
|
"metadata": {
|
|
"ExecuteTime": {
|
|
"end_time": "2025-03-16T12:51:52.068302Z",
|
|
"start_time": "2025-03-16T12:51:52.065921Z"
|
|
}
|
|
},
|
|
"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": 37
|
|
},
|
|
{
|
|
"metadata": {},
|
|
"cell_type": "markdown",
|
|
"source": "### Refresh User Keys"
|
|
},
|
|
{
|
|
"metadata": {
|
|
"ExecuteTime": {
|
|
"end_time": "2025-03-16T12:51:52.311112Z",
|
|
"start_time": "2025-03-16T12:51:52.074783Z"
|
|
}
|
|
},
|
|
"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": 38
|
|
}
|
|
],
|
|
"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
|
|
}
|