refactor use numpy in user_cipher.py

This commit is contained in:
2025-03-11 10:33:08 -05:00
parent dd0b496a21
commit 526e537586
7 changed files with 230 additions and 177 deletions

View File

@@ -63,8 +63,8 @@ if __name__ == "__main__":
customer_id = api.create_new_customer(keypad_size, policy) customer_id = api.create_new_customer(keypad_size, policy)
customer = api.customers[customer_id] customer = api.customers[customer_id]
set_vals = customer.customer_cipher.set_key set_vals = customer.cipher.set_key
attr_vals = customer.customer_cipher.prop_key attr_vals = customer.cipher.prop_key
customer_attr_view = list_to_matrix(attr_vals, keypad_size.props_per_key) customer_attr_view = list_to_matrix(attr_vals, keypad_size.props_per_key)
attr_keypad_view = list_to_matrix(attr_vals, keypad_size.props_per_key) attr_keypad_view = list_to_matrix(attr_vals, keypad_size.props_per_key)
@@ -78,7 +78,7 @@ if __name__ == "__main__":
passcode_len = 4 passcode_len = 4
user_passcode = signup_interface[:passcode_len] user_passcode = signup_interface[:passcode_len]
selected_keys_set = select_keys_with_passcode_values(user_passcode, signup_interface, keypad_size.numb_of_keys) selected_keys_set = select_keys_with_passcode_values(user_passcode, signup_interface, keypad_size.numb_of_keys)
server_side_attr = [customer.customer_cipher.prop_key[idx] for idx in user_passcode] server_side_attr = [customer.cipher.prop_key[idx] for idx in user_passcode]
confirm_interface = api.set_nkode(username, customer_id, selected_keys_set, session_id) confirm_interface = api.set_nkode(username, customer_id, selected_keys_set, session_id)
@@ -88,20 +88,20 @@ if __name__ == "__main__":
success = api.confirm_nkode(username, customer_id, selected_keys_confirm, session_id) success = api.confirm_nkode(username, customer_id, selected_keys_confirm, session_id)
assert success assert success
passcode_server_attr = [customer.customer_cipher.prop_key[idx] for idx in user_passcode] passcode_server_attr = [customer.cipher.prop_key[idx] for idx in user_passcode]
passcode_server_set = [customer.customer_cipher.get_prop_set_val(attr) for attr in passcode_server_attr] passcode_server_set = [customer.cipher.get_prop_set_val(attr) for attr in passcode_server_attr]
user_keys = customer.users[username].user_keys user_keys = customer.users[username].cipher
padded_passcode_server_set = user_keys.pad_user_mask(passcode_server_set, customer.customer_cipher.set_key) padded_passcode_server_set = user_keys.pad_user_mask(passcode_server_set, customer.cipher.set_key)
set_idx = [customer.customer_cipher.get_set_index(set_val) for set_val in padded_passcode_server_set] set_idx = [customer.cipher.get_set_index(set_val) for set_val in padded_passcode_server_set]
mask_set_keys = [user_keys.set_key[idx] for idx in set_idx] mask_set_keys = [user_keys.set_key[idx] for idx in set_idx]
ciphered_mask = xor_lists(mask_set_keys, padded_passcode_server_set) ciphered_mask = xor_lists(mask_set_keys, padded_passcode_server_set)
ciphered_mask = xor_lists(ciphered_mask, user_keys.mask_key) ciphered_mask = xor_lists(ciphered_mask, user_keys.mask_key)
mask = user_keys.encode_base64_str(ciphered_mask) mask = user_keys.encode_base64_str(ciphered_mask)
ciphered_customer_attrs = xor_lists(customer.customer_cipher.prop_key, user_keys.prop_key) ciphered_customer_attrs = xor_lists(customer.cipher.prop_key, user_keys.prop_key)
passcode_ciphered_attrs = [ciphered_customer_attrs[idx] for idx in user_passcode] passcode_ciphered_attrs = [ciphered_customer_attrs[idx] for idx in user_passcode]
pad_len = customer.nkode_policy.max_nkode_len - passcode_len pad_len = customer.nkode_policy.max_nkode_len - passcode_len
@@ -133,8 +133,8 @@ if __name__ == "__main__":
""" """
user = customer.users[username] user = customer.users[username]
set_vals = customer.customer_cipher.set_key set_vals = customer.cipher.set_key
user_keys = user.user_keys user_keys = user.cipher
user_mask = user.enciphered_passcode.mask user_mask = user.enciphered_passcode.mask
decoded_mask = user_keys.decode_base64_str(user_mask) decoded_mask = user_keys.decode_base64_str(user_mask)
deciphered_mask = xor_lists(decoded_mask, user_keys.mask_key) deciphered_mask = xor_lists(decoded_mask, user_keys.mask_key)
@@ -148,7 +148,7 @@ if __name__ == "__main__":
GET PRESUMED ATTRIBUTES GET PRESUMED ATTRIBUTES
""" """
set_vals_idx = [customer.customer_cipher.get_set_index(set_val) for set_val in login_passcode_sets] set_vals_idx = [customer.cipher.get_set_index(set_val) for set_val in login_passcode_sets]
presumed_selected_attributes_idx = [] presumed_selected_attributes_idx = []
for idx in range(passcode_len): for idx in range(passcode_len):
@@ -161,11 +161,11 @@ if __name__ == "__main__":
RENEW KEYS RENEW KEYS
""" """
old_attrs = customer.customer_cipher.prop_key.copy() old_attrs = customer.cipher.prop_key.copy()
old_sets = customer.customer_cipher.set_key.copy() old_sets = customer.cipher.set_key.copy()
customer.customer_cipher.renew() customer.cipher.renew()
new_attrs = customer.customer_cipher.prop_key new_attrs = customer.cipher.prop_key
new_sets = customer.customer_cipher.set_key new_sets = customer.cipher.set_key
customer_new_attr_view = list_to_matrix(new_attrs, keypad_size.props_per_key) customer_new_attr_view = list_to_matrix(new_attrs, keypad_size.props_per_key)
""" """
@@ -175,18 +175,18 @@ if __name__ == "__main__":
sets_xor = xor_lists(new_sets, old_sets) sets_xor = xor_lists(new_sets, old_sets)
for user in customer.users.values(): for user in customer.users.values():
user.renew = True user.renew = True
user.user_keys.set_key = xor_lists(user.user_keys.set_key, sets_xor) user.cipher.set_key = xor_lists(user.cipher.set_key, sets_xor)
user.user_keys.prop_key = xor_lists(user.user_keys.prop_key, attrs_xor) user.cipher.prop_key = xor_lists(user.cipher.prop_key, attrs_xor)
""" """
REFRESH USER KEYS REFRESH USER KEYS
""" """
user.user_keys = UserCipher.create( user.cipher = UserCipher.create(
customer.customer_cipher.keypad_size, customer.cipher.keypad_size,
customer.customer_cipher.set_key, customer.cipher.set_key,
user.user_keys.max_nkode_len user.cipher.max_nkode_len
) )
user.enciphered_passcode = user.user_keys.encipher_nkode(presumed_selected_attributes_idx, customer.customer_cipher) user.enciphered_passcode = user.cipher.encipher_nkode(presumed_selected_attributes_idx, customer.cipher)
user.renew = False user.renew = False
# Define some data to pass to the template # Define some data to pass to the template
@@ -202,7 +202,7 @@ if __name__ == "__main__":
'server_side_attr': server_side_attr, 'server_side_attr': server_side_attr,
'confirm_keypad': confirm_keypad, 'confirm_keypad': confirm_keypad,
'selected_keys_confirm': selected_keys_confirm, 'selected_keys_confirm': selected_keys_confirm,
'user_keys': user_keys, 'cipher': user_keys,
'passcode_server_attr': passcode_server_attr, 'passcode_server_attr': passcode_server_attr,
'passcode_server_set': passcode_server_set, 'passcode_server_set': passcode_server_set,
'enciphered_nkode': enciphered_nkode, 'enciphered_nkode': enciphered_nkode,

View File

@@ -12,12 +12,12 @@
"metadata": { "metadata": {
"collapsed": false, "collapsed": false,
"ExecuteTime": { "ExecuteTime": {
"end_time": "2025-03-07T19:01:08.154404Z", "end_time": "2025-03-10T15:54:01.727846Z",
"start_time": "2025-03-07T19:01:08.149432Z" "start_time": "2025-03-10T15:54:01.637744Z"
} }
}, },
"outputs": [], "outputs": [],
"execution_count": 58 "execution_count": 2
}, },
{ {
"cell_type": "code", "cell_type": "code",
@@ -38,12 +38,12 @@
"metadata": { "metadata": {
"collapsed": false, "collapsed": false,
"ExecuteTime": { "ExecuteTime": {
"end_time": "2025-03-07T19:01:08.165511Z", "end_time": "2025-03-10T15:54:01.735895Z",
"start_time": "2025-03-07T19:01:08.162339Z" "start_time": "2025-03-10T15:54:01.733121Z"
} }
}, },
"outputs": [], "outputs": [],
"execution_count": 59 "execution_count": 3
}, },
{ {
"cell_type": "code", "cell_type": "code",
@@ -53,12 +53,12 @@
"metadata": { "metadata": {
"collapsed": false, "collapsed": false,
"ExecuteTime": { "ExecuteTime": {
"end_time": "2025-03-07T19:01:08.174320Z", "end_time": "2025-03-10T15:54:01.746332Z",
"start_time": "2025-03-07T19:01:08.172724Z" "start_time": "2025-03-10T15:54:01.744308Z"
} }
}, },
"outputs": [], "outputs": [],
"execution_count": 60 "execution_count": 4
}, },
{ {
"cell_type": "markdown", "cell_type": "markdown",
@@ -90,7 +90,7 @@
")\n", ")\n",
"keypad_size = KeypadSize(\n", "keypad_size = KeypadSize(\n",
" numb_of_keys = 5,\n", " numb_of_keys = 5,\n",
" attrs_per_key = 6 # aka number of sets\n", " props_per_key = 6 # aka number of sets\n",
")\n", ")\n",
"customer_id = api.create_new_customer(keypad_size, policy)\n", "customer_id = api.create_new_customer(keypad_size, policy)\n",
"customer = api.customers[customer_id]" "customer = api.customers[customer_id]"
@@ -98,12 +98,12 @@
"metadata": { "metadata": {
"collapsed": false, "collapsed": false,
"ExecuteTime": { "ExecuteTime": {
"end_time": "2025-03-07T19:01:08.378578Z", "end_time": "2025-03-10T15:54:02.001142Z",
"start_time": "2025-03-07T19:01:08.188114Z" "start_time": "2025-03-10T15:54:01.752948Z"
} }
}, },
"outputs": [], "outputs": [],
"execution_count": 61 "execution_count": 5
}, },
{ {
"cell_type": "markdown", "cell_type": "markdown",
@@ -129,19 +129,19 @@
{ {
"cell_type": "code", "cell_type": "code",
"source": [ "source": [
"set_vals = customer.attributes.set_vals\n", "set_vals = customer.cipher.set_key\n",
"attr_vals = customer.attributes.attr_vals\n", "attr_vals = customer.cipher.prop_key\n",
"print(f\"Customer Sets: {set_vals}\")\n", "print(f\"Customer Sets: {set_vals}\")\n",
"print(f\"Customer Attributes:\")\n", "print(f\"Customer Attributes:\")\n",
"interface_keypad = list_to_matrix(attr_vals, keypad_size.attrs_per_key)\n", "interface_keypad = list_to_matrix(attr_vals, keypad_size.props_per_key)\n",
"for idx, key_vals in enumerate(interface_keypad):\n", "for idx, key_vals in enumerate(interface_keypad):\n",
" print(f\"{key_vals}\")" " print(f\"{key_vals}\")"
], ],
"metadata": { "metadata": {
"collapsed": false, "collapsed": false,
"ExecuteTime": { "ExecuteTime": {
"end_time": "2025-03-07T19:01:08.387613Z", "end_time": "2025-03-10T15:54:02.011259Z",
"start_time": "2025-03-07T19:01:08.385501Z" "start_time": "2025-03-10T15:54:02.008541Z"
} }
}, },
"outputs": [ "outputs": [
@@ -149,17 +149,17 @@
"name": "stdout", "name": "stdout",
"output_type": "stream", "output_type": "stream",
"text": [ "text": [
"Customer Sets: [14533, 13441, 52408, 39610, 49828, 11300]\n", "Customer Sets: [5584, 23615, 13665, 42236, 20931, 35557]\n",
"Customer Attributes:\n", "Customer Attributes:\n",
"[50415, 3350, 62907, 34493, 46982, 55292]\n", "[51116, 4647, 54248, 42959, 35151, 56238]\n",
"[23503, 57678, 17001, 8963, 4893, 53685]\n", "[37806, 51776, 33630, 63761, 13028, 29812]\n",
"[25912, 9324, 2770, 57761, 57056, 5837]\n", "[41783, 30499, 23526, 21846, 1217, 40587]\n",
"[49831, 16518, 53473, 35853, 12433, 20763]\n", "[20418, 53142, 62008, 29738, 64343, 49564]\n",
"[60930, 19614, 2083, 2879, 58781, 13705]\n" "[4306, 19073, 56680, 38208, 21317, 14264]\n"
] ]
} }
], ],
"execution_count": 62 "execution_count": 6
}, },
{ {
"cell_type": "markdown", "cell_type": "markdown",
@@ -173,7 +173,7 @@
{ {
"cell_type": "code", "cell_type": "code",
"source": [ "source": [
"attr_keypad_view = list_to_matrix(attr_vals, keypad_size.attrs_per_key)\n", "attr_keypad_view = list_to_matrix(attr_vals, keypad_size.props_per_key)\n",
"attr_set_view = matrix_transpose(attr_keypad_view)\n", "attr_set_view = matrix_transpose(attr_keypad_view)\n",
"set_attribute_dict = dict(zip(set_vals, attr_set_view))\n", "set_attribute_dict = dict(zip(set_vals, attr_set_view))\n",
"print(f\"Set to Attribute Map:\")\n", "print(f\"Set to Attribute Map:\")\n",
@@ -183,8 +183,8 @@
"metadata": { "metadata": {
"collapsed": false, "collapsed": false,
"ExecuteTime": { "ExecuteTime": {
"end_time": "2025-03-07T19:01:08.412394Z", "end_time": "2025-03-10T15:54:16.867336Z",
"start_time": "2025-03-07T19:01:08.410114Z" "start_time": "2025-03-10T15:54:16.864589Z"
} }
}, },
"outputs": [ "outputs": [
@@ -193,16 +193,16 @@
"output_type": "stream", "output_type": "stream",
"text": [ "text": [
"Set to Attribute Map:\n", "Set to Attribute Map:\n",
"14533: [50415, 23503, 25912, 49831, 60930]\n", "5584: [51116, 37806, 41783, 20418, 4306]\n",
"13441: [3350, 57678, 9324, 16518, 19614]\n", "23615: [4647, 51776, 30499, 53142, 19073]\n",
"52408: [62907, 17001, 2770, 53473, 2083]\n", "13665: [54248, 33630, 23526, 62008, 56680]\n",
"39610: [34493, 8963, 57761, 35853, 2879]\n", "42236: [42959, 63761, 21846, 29738, 38208]\n",
"49828: [46982, 4893, 57056, 12433, 58781]\n", "20931: [35151, 13028, 1217, 64343, 21317]\n",
"11300: [55292, 53685, 5837, 20763, 13705]\n" "35557: [56238, 29812, 40587, 49564, 14264]\n"
] ]
} }
], ],
"execution_count": 63 "execution_count": 8
}, },
{ {
"cell_type": "markdown", "cell_type": "markdown",
@@ -232,27 +232,24 @@
"metadata": { "metadata": {
"collapsed": false, "collapsed": false,
"ExecuteTime": { "ExecuteTime": {
"end_time": "2025-03-07T19:01:08.439639Z", "end_time": "2025-03-10T15:54:20.741427Z",
"start_time": "2025-03-07T19:01:08.436629Z" "start_time": "2025-03-10T15:54:20.731719Z"
} }
}, },
"outputs": [ "outputs": [
{ {
"data": { "ename": "AttributeError",
"text/plain": [ "evalue": "'NKodeAPI' object has no attribute 'generate_signup_interface'",
"[[3, 20, 10, 6, 29],\n", "output_type": "error",
" [27, 26, 4, 24, 11],\n", "traceback": [
" [15, 2, 22, 0, 5],\n", "\u001B[0;31m---------------------------------------------------------------------------\u001B[0m",
" [9, 8, 16, 12, 23],\n", "\u001B[0;31mAttributeError\u001B[0m Traceback (most recent call last)",
" [21, 14, 28, 18, 17]]" "Cell \u001B[0;32mIn[9], line 1\u001B[0m\n\u001B[0;32m----> 1\u001B[0m session_id, signup_interface \u001B[38;5;241m=\u001B[39m \u001B[43mapi\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mgenerate_signup_interface\u001B[49m(customer_id)\n\u001B[1;32m 2\u001B[0m list_to_matrix(signup_interface, keypad_size\u001B[38;5;241m.\u001B[39mnumb_of_keys)\n",
] "\u001B[0;31mAttributeError\u001B[0m: 'NKodeAPI' object has no attribute 'generate_signup_interface'"
}, ]
"execution_count": 64,
"metadata": {},
"output_type": "execute_result"
} }
], ],
"execution_count": 64 "execution_count": 9
}, },
{ {
"cell_type": "markdown", "cell_type": "markdown",
@@ -280,7 +277,7 @@
"metadata": { "metadata": {
"collapsed": false, "collapsed": false,
"ExecuteTime": { "ExecuteTime": {
"end_time": "2025-03-07T19:01:08.474579Z", "end_time": "2025-03-10T15:54:02.091787Z",
"start_time": "2025-03-07T19:01:08.471813Z" "start_time": "2025-03-07T19:01:08.471813Z"
} }
}, },
@@ -320,7 +317,7 @@
"metadata": { "metadata": {
"collapsed": false, "collapsed": false,
"ExecuteTime": { "ExecuteTime": {
"end_time": "2025-03-07T19:01:08.496620Z", "end_time": "2025-03-10T15:54:02.111894Z",
"start_time": "2025-03-07T19:01:08.494090Z" "start_time": "2025-03-07T19:01:08.494090Z"
} }
}, },
@@ -352,7 +349,7 @@
"metadata": { "metadata": {
"collapsed": false, "collapsed": false,
"ExecuteTime": { "ExecuteTime": {
"end_time": "2025-03-07T19:01:09.173784Z", "end_time": "2025-03-10T15:54:02.115281Z",
"start_time": "2025-03-07T19:01:08.522178Z" "start_time": "2025-03-07T19:01:08.522178Z"
} }
}, },
@@ -384,30 +381,31 @@
{ {
"metadata": { "metadata": {
"ExecuteTime": { "ExecuteTime": {
"end_time": "2025-03-07T19:01:09.193871Z", "end_time": "2025-03-10T15:54:02.129677Z",
"start_time": "2025-03-07T19:01:09.190856Z" "start_time": "2025-03-10T15:41:40.490919Z"
} }
}, },
"cell_type": "code", "cell_type": "code",
"source": [ "source": [
"from src.user_cipher_keys import UserCipherKeys\n", "from src.user_cipher import UserCipher\n",
"from src.utils import xor_lists\n", "from src.utils import xor_lists\n",
"import numpy as np\n",
"\n", "\n",
"\n", "\n",
"set_key = [46785, 4782, 4405, 44408, 35377, 55527]\n", "set_key = [46785, 4782, 4405, 44408, 35377, 55527]\n",
"set_key = xor_lists(set_key, customer.attributes.set_vals)\n", "set_key = xor_lists(set_key, customer.attributes.set_vals)\n",
"user_keys = UserCipherKeys(\n", "user_keys = UserCipher(\n",
" alpha_key = [\n", " prop_key = np.array([\n",
" 57200, 8398, 54694, 25997, 30388,\n", " 57200, 8398, 54694, 25997, 30388,\n",
" 46948, 45549, 30364, 49712, 10447,\n", " 46948, 45549, 30364, 49712, 10447,\n",
" 9205, 1777, 10731, 30979, 2795,\n", " 9205, 1777, 10731, 30979, 2795,\n",
" 17068, 56758, 62574, 28641, 11451,\n", " 17068, 56758, 62574, 28641, 11451,\n",
" 26820, 50373, 48783, 25350, 62177,\n", " 26820, 50373, 48783, 25350, 62177,\n",
" 60608, 54242, 4637, 3525, 16313\n", " 60608, 54242, 4637, 3525, 16313\n",
" ],\n", " ]),\n",
" pass_key=[16090, 38488, 45111, 32674, 46216, 52013, 48980, 36811, 35296, 17206],\n", " pass_key=np.array([16090, 38488, 45111, 32674, 46216, 52013, 48980, 36811, 35296, 17206]),\n",
" mask_key=[29575, 43518, 44373, 62063, 37651, 31671, 31663, 65514, 36454, 47325],\n", " mask_key=np.array([29575, 43518, 44373, 62063, 37651, 31671, 31663, 65514, 36454, 47325]),\n",
" set_key=set_key,\n", " set_key=np.array(set_key),\n",
" salt=b'$2b$12$fX.in.GGAjz3QBBwqSWc6e',\n", " salt=b'$2b$12$fX.in.GGAjz3QBBwqSWc6e',\n",
" max_nkode_len=customer.nkode_policy.max_nkode_len, \n", " max_nkode_len=customer.nkode_policy.max_nkode_len, \n",
")\n", ")\n",
@@ -419,15 +417,18 @@
], ],
"outputs": [ "outputs": [
{ {
"name": "stdout", "ename": "NameError",
"output_type": "stream", "evalue": "name 'customer' is not defined",
"text": [ "output_type": "error",
"Passcode Set Vals: [39610, 52408, 49828, 14533]\n", "traceback": [
"Passcode Attr Vals: [34493, 53473, 4893, 23503]\n" "\u001B[0;31m---------------------------------------------------------------------------\u001B[0m",
"\u001B[0;31mNameError\u001B[0m Traceback (most recent call last)",
"Cell \u001B[0;32mIn[5], line 6\u001B[0m\n\u001B[1;32m 2\u001B[0m \u001B[38;5;28;01mfrom\u001B[39;00m \u001B[38;5;21;01msrc\u001B[39;00m\u001B[38;5;21;01m.\u001B[39;00m\u001B[38;5;21;01mutils\u001B[39;00m \u001B[38;5;28;01mimport\u001B[39;00m xor_lists\n\u001B[1;32m 5\u001B[0m set_key \u001B[38;5;241m=\u001B[39m [\u001B[38;5;241m46785\u001B[39m, \u001B[38;5;241m4782\u001B[39m, \u001B[38;5;241m4405\u001B[39m, \u001B[38;5;241m44408\u001B[39m, \u001B[38;5;241m35377\u001B[39m, \u001B[38;5;241m55527\u001B[39m]\n\u001B[0;32m----> 6\u001B[0m set_key \u001B[38;5;241m=\u001B[39m xor_lists(set_key, \u001B[43mcustomer\u001B[49m\u001B[38;5;241m.\u001B[39mattributes\u001B[38;5;241m.\u001B[39mset_vals)\n\u001B[1;32m 7\u001B[0m user_keys \u001B[38;5;241m=\u001B[39m UserCipher(\n\u001B[1;32m 8\u001B[0m prop_key \u001B[38;5;241m=\u001B[39m [\n\u001B[1;32m 9\u001B[0m \u001B[38;5;241m57200\u001B[39m, \u001B[38;5;241m8398\u001B[39m, \u001B[38;5;241m54694\u001B[39m, \u001B[38;5;241m25997\u001B[39m, \u001B[38;5;241m30388\u001B[39m,\n\u001B[0;32m (...)\u001B[0m\n\u001B[1;32m 20\u001B[0m max_nkode_len\u001B[38;5;241m=\u001B[39mcustomer\u001B[38;5;241m.\u001B[39mnkode_policy\u001B[38;5;241m.\u001B[39mmax_nkode_len, \n\u001B[1;32m 21\u001B[0m )\n\u001B[1;32m 23\u001B[0m passcode_server_attr \u001B[38;5;241m=\u001B[39m [customer\u001B[38;5;241m.\u001B[39mattributes\u001B[38;5;241m.\u001B[39mattr_vals[idx] \u001B[38;5;28;01mfor\u001B[39;00m idx \u001B[38;5;129;01min\u001B[39;00m user_passcode]\n",
"\u001B[0;31mNameError\u001B[0m: name 'customer' is not defined"
] ]
} }
], ],
"execution_count": 68 "execution_count": 5
}, },
{ {
"metadata": {}, "metadata": {},
@@ -449,24 +450,36 @@
{ {
"metadata": { "metadata": {
"ExecuteTime": { "ExecuteTime": {
"end_time": "2025-03-07T19:01:09.223843Z", "end_time": "2025-03-10T15:54:02.130699Z",
"start_time": "2025-03-07T19:01:09.221595Z" "start_time": "2025-03-10T15:45:03.947109Z"
} }
}, },
"cell_type": "code", "cell_type": "code",
"source": [ "source": [
"from src.utils import xor_lists\n", "from src.utils import xor_lists\n",
"\n", "\n",
"padded_passcode_server_set = user_keys.pad_user_mask(passcode_server_set, customer.attributes.set_vals)\n", "padded_passcode_server_set = user_keys.pad_user_mask(passcode_server_set, customer.properites.set_vals)\n",
"\n", "\n",
"set_idx = [customer.attributes.get_set_index(set_val) for set_val in padded_passcode_server_set]\n", "set_idx = [customer.properites.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", "mask_set_keys = [user_keys.set_key[idx] for idx in set_idx]\n",
"ciphered_mask = xor_lists(mask_set_keys, padded_passcode_server_set)\n", "ciphered_mask = xor_lists(mask_set_keys, padded_passcode_server_set)\n",
"ciphered_mask = xor_lists(ciphered_mask, user_keys.mask_key)\n", "ciphered_mask = xor_lists(ciphered_mask, user_keys.mask_key)\n",
"mask = user_keys.encode_base64_str(ciphered_mask)" "mask = user_keys.encode_base64_str(ciphered_mask)"
], ],
"outputs": [], "outputs": [
"execution_count": 69 {
"ename": "NameError",
"evalue": "name 'user_keys' is not defined",
"output_type": "error",
"traceback": [
"\u001B[0;31m---------------------------------------------------------------------------\u001B[0m",
"\u001B[0;31mNameError\u001B[0m Traceback (most recent call last)",
"Cell \u001B[0;32mIn[5], line 3\u001B[0m\n\u001B[1;32m 1\u001B[0m \u001B[38;5;28;01mfrom\u001B[39;00m \u001B[38;5;21;01msrc\u001B[39;00m\u001B[38;5;21;01m.\u001B[39;00m\u001B[38;5;21;01mutils\u001B[39;00m \u001B[38;5;28;01mimport\u001B[39;00m xor_lists\n\u001B[0;32m----> 3\u001B[0m padded_passcode_server_set \u001B[38;5;241m=\u001B[39m \u001B[43muser_keys\u001B[49m\u001B[38;5;241m.\u001B[39mpad_user_mask(passcode_server_set, customer\u001B[38;5;241m.\u001B[39mproperites\u001B[38;5;241m.\u001B[39mset_vals)\n\u001B[1;32m 5\u001B[0m set_idx \u001B[38;5;241m=\u001B[39m [customer\u001B[38;5;241m.\u001B[39mproperites\u001B[38;5;241m.\u001B[39mget_set_index(set_val) \u001B[38;5;28;01mfor\u001B[39;00m set_val \u001B[38;5;129;01min\u001B[39;00m padded_passcode_server_set]\n\u001B[1;32m 6\u001B[0m mask_set_keys \u001B[38;5;241m=\u001B[39m [user_keys\u001B[38;5;241m.\u001B[39mset_key[idx] \u001B[38;5;28;01mfor\u001B[39;00m idx \u001B[38;5;129;01min\u001B[39;00m set_idx]\n",
"\u001B[0;31mNameError\u001B[0m: name 'user_keys' is not defined"
]
}
],
"execution_count": 5
}, },
{ {
"metadata": {}, "metadata": {},
@@ -483,7 +496,7 @@
{ {
"metadata": { "metadata": {
"ExecuteTime": { "ExecuteTime": {
"end_time": "2025-03-07T19:01:09.479816Z", "end_time": "2025-03-10T15:54:02.130948Z",
"start_time": "2025-03-07T19:01:09.236822Z" "start_time": "2025-03-07T19:01:09.236822Z"
} }
}, },
@@ -494,7 +507,7 @@
"import base64\n", "import base64\n",
"from src.utils import int_array_to_bytes\n", "from src.utils import int_array_to_bytes\n",
"\n", "\n",
"ciphered_customer_attrs = xor_lists(customer.attributes.attr_vals, user_keys.alpha_key)\n", "ciphered_customer_attrs = xor_lists(customer.attributes.attr_vals, user_keys.prop_key)\n",
"passcode_ciphered_attrs = [ciphered_customer_attrs[idx] for idx in user_passcode]\n", "passcode_ciphered_attrs = [ciphered_customer_attrs[idx] for idx in user_passcode]\n",
"pad_len = customer.nkode_policy.max_nkode_len - passcode_len\n", "pad_len = customer.nkode_policy.max_nkode_len - passcode_len\n",
"\n", "\n",
@@ -513,7 +526,7 @@
{ {
"metadata": { "metadata": {
"ExecuteTime": { "ExecuteTime": {
"end_time": "2025-03-07T19:01:09.495420Z", "end_time": "2025-03-10T15:54:02.141842Z",
"start_time": "2025-03-07T19:01:09.488943Z" "start_time": "2025-03-07T19:01:09.488943Z"
} }
}, },
@@ -553,7 +566,7 @@
"metadata": { "metadata": {
"collapsed": false, "collapsed": false,
"ExecuteTime": { "ExecuteTime": {
"end_time": "2025-03-07T19:01:09.736403Z", "end_time": "2025-03-10T15:54:02.143871Z",
"start_time": "2025-03-07T19:01:09.500580Z" "start_time": "2025-03-07T19:01:09.500580Z"
} }
}, },
@@ -605,7 +618,7 @@
{ {
"metadata": { "metadata": {
"ExecuteTime": { "ExecuteTime": {
"end_time": "2025-03-07T19:01:09.774425Z", "end_time": "2025-03-10T15:54:02.144830Z",
"start_time": "2025-03-07T19:01:09.772200Z" "start_time": "2025-03-07T19:01:09.772200Z"
} }
}, },
@@ -613,7 +626,7 @@
"source": [ "source": [
"user = customer.users[username]\n", "user = customer.users[username]\n",
"set_vals = customer.attributes.set_vals\n", "set_vals = customer.attributes.set_vals\n",
"user_keys = user.user_keys\n", "user_keys = user.cipher\n",
"user_mask = user.enciphered_passcode.mask\n", "user_mask = user.enciphered_passcode.mask\n",
"decoded_mask = user_keys.decode_base64_str(user_mask)\n", "decoded_mask = user_keys.decode_base64_str(user_mask)\n",
"deciphered_mask = xor_lists(decoded_mask, user_keys.mask_key)\n", "deciphered_mask = xor_lists(decoded_mask, user_keys.mask_key)\n",
@@ -643,7 +656,7 @@
{ {
"metadata": { "metadata": {
"ExecuteTime": { "ExecuteTime": {
"end_time": "2025-03-07T19:01:09.795190Z", "end_time": "2025-03-10T15:54:02.145423Z",
"start_time": "2025-03-07T19:01:09.792579Z" "start_time": "2025-03-07T19:01:09.792579Z"
} }
}, },
@@ -679,7 +692,7 @@
{ {
"metadata": { "metadata": {
"ExecuteTime": { "ExecuteTime": {
"end_time": "2025-03-07T19:01:10.057899Z", "end_time": "2025-03-10T15:54:02.145859Z",
"start_time": "2025-03-07T19:01:09.819860Z" "start_time": "2025-03-07T19:01:09.819860Z"
} }
}, },
@@ -716,7 +729,7 @@
{ {
"metadata": { "metadata": {
"ExecuteTime": { "ExecuteTime": {
"end_time": "2025-03-07T19:01:11.147274Z", "end_time": "2025-03-10T15:54:02.146298Z",
"start_time": "2025-03-07T19:01:10.066784Z" "start_time": "2025-03-07T19:01:10.066784Z"
} }
}, },
@@ -763,7 +776,7 @@
{ {
"metadata": { "metadata": {
"ExecuteTime": { "ExecuteTime": {
"end_time": "2025-03-07T19:01:11.355505Z", "end_time": "2025-03-10T15:54:02.148090Z",
"start_time": "2025-03-07T19:01:11.153001Z" "start_time": "2025-03-07T19:01:11.153001Z"
} }
}, },
@@ -789,7 +802,7 @@
{ {
"metadata": { "metadata": {
"ExecuteTime": { "ExecuteTime": {
"end_time": "2025-03-07T19:01:11.363643Z", "end_time": "2025-03-10T15:54:02.154941Z",
"start_time": "2025-03-07T19:01:11.361690Z" "start_time": "2025-03-07T19:01:11.361690Z"
} }
}, },
@@ -799,8 +812,8 @@
"sets_xor = xor_lists(new_sets, old_sets)\n", "sets_xor = xor_lists(new_sets, old_sets)\n",
"for user in customer.users.values():\n", "for user in customer.users.values():\n",
" user.renew = True\n", " user.renew = True\n",
" user.user_keys.set_key = xor_lists(user.user_keys.set_key, sets_xor)\n", " user.cipher.set_key = xor_lists(user.cipher.set_key, sets_xor)\n",
" user.user_keys.alpha_key = xor_lists(user.user_keys.alpha_key, attrs_xor)" " user.cipher.prop_key = xor_lists(user.cipher.prop_key, attrs_xor)"
], ],
"outputs": [], "outputs": [],
"execution_count": 78 "execution_count": 78
@@ -813,18 +826,18 @@
{ {
"metadata": { "metadata": {
"ExecuteTime": { "ExecuteTime": {
"end_time": "2025-03-07T19:01:11.989265Z", "end_time": "2025-03-10T15:54:02.155673Z",
"start_time": "2025-03-07T19:01:11.369911Z" "start_time": "2025-03-07T19:01:11.369911Z"
} }
}, },
"cell_type": "code", "cell_type": "code",
"source": [ "source": [
"user.user_keys = UserCipherKeys.new(\n", "user.cipher = UserCipher.create(\n",
" customer.attributes.keypad_size,\n", " customer.attributes.keypad_size,\n",
" customer.attributes.set_vals,\n", " customer.attributes.set_vals,\n",
" user.user_keys.max_nkode_len\n", " user.cipher.max_nkode_len\n",
")\n", ")\n",
"user.enciphered_passcode = user.user_keys.encipher_nkode(presumed_selected_attributes_idx, customer.attributes)\n", "user.enciphered_passcode = user.cipher.encipher_nkode(presumed_selected_attributes_idx, customer.attributes)\n",
"user.renew = False" "user.renew = False"
], ],
"outputs": [], "outputs": [],

View File

@@ -9,7 +9,7 @@ from src.utils import xor_lists
class Customer: class Customer:
customer_id: UUID customer_id: UUID
nkode_policy: NKodePolicy nkode_policy: NKodePolicy
customer_cipher: CustomerCipher cipher: CustomerCipher
users: dict[str, User] users: dict[str, User]
# TODO: validate policy and keypad size don't conflict # TODO: validate policy and keypad size don't conflict
@@ -23,16 +23,16 @@ class Customer:
if username not in self.users: if username not in self.users:
raise ValueError(f"User '{username}' does not exist") raise ValueError(f"User '{username}' does not exist")
numb_of_keys = self.customer_cipher.keypad_size.numb_of_keys numb_of_keys = self.cipher.keypad_size.numb_of_keys
if not all(0 <= key_idx < numb_of_keys for key_idx in selected_keys): if not all(0 <= key_idx < numb_of_keys for key_idx in selected_keys):
raise ValueError(f"Invalid key indices. Must be between 0 and {numb_of_keys - 1}") raise ValueError(f"Invalid key indices. Must be between 0 and {numb_of_keys - 1}")
passcode_len = len(selected_keys) passcode_len = len(selected_keys)
user = self.users[username] user = self.users[username]
passcode_set_vals = user.user_keys.decipher_mask( passcode_set_vals = user.cipher.decipher_mask(
user.enciphered_passcode.mask, self.customer_cipher.set_key, passcode_len) user.enciphered_passcode.mask, self.cipher.set_key, passcode_len)
set_vals_idx = [self.customer_cipher.get_set_index(set_val) for set_val in passcode_set_vals] set_vals_idx = [self.cipher.get_set_index(set_val) for set_val in passcode_set_vals]
presumed_selected_attributes_idx = [] presumed_selected_attributes_idx = []
for idx in range(passcode_len): for idx in range(passcode_len):
@@ -41,20 +41,20 @@ class Customer:
selected_attr_idx = user.user_keypad.get_attr_idx_by_keynumb_setidx(key_numb, set_idx) selected_attr_idx = user.user_keypad.get_attr_idx_by_keynumb_setidx(key_numb, set_idx)
presumed_selected_attributes_idx.append(selected_attr_idx) presumed_selected_attributes_idx.append(selected_attr_idx)
enciphered_attr = user.user_keys.encipher_salt_hash_code(presumed_selected_attributes_idx, self.customer_cipher) enciphered_attr = user.cipher.encipher_salt_hash_code(presumed_selected_attributes_idx, self.cipher)
if enciphered_attr != user.enciphered_passcode.code: if enciphered_attr != user.enciphered_passcode.code:
return False return False
if user.renew: if user.renew:
user.refresh_passcode(presumed_selected_attributes_idx, self.customer_cipher) user.refresh_passcode(presumed_selected_attributes_idx, self.cipher)
return True return True
def renew_keys(self) -> bool: def renew_keys(self) -> bool:
old_attrs = self.customer_cipher.prop_key.copy() old_attrs = self.cipher.prop_key.copy()
old_sets = self.customer_cipher.set_key.copy() old_sets = self.cipher.set_key.copy()
self.customer_cipher.renew() self.cipher.renew()
new_attrs = self.customer_cipher.prop_key new_attrs = self.cipher.prop_key
new_sets = self.customer_cipher.set_key new_sets = self.cipher.set_key
attrs_xor = xor_lists(new_attrs, old_attrs) attrs_xor = xor_lists(new_attrs, old_attrs)
set_xor = xor_lists(new_sets, old_sets) set_xor = xor_lists(new_sets, old_sets)
@@ -66,7 +66,7 @@ class Customer:
def valid_new_nkode(self, passcode_attr_idx: list[int]) -> bool: def valid_new_nkode(self, passcode_attr_idx: list[int]) -> bool:
nkode_len = len(passcode_attr_idx) nkode_len = len(passcode_attr_idx)
passcode_set_values = [ passcode_set_values = [
self.customer_cipher.get_prop_set_val(self.customer_cipher.prop_key[attr_idx]) for attr_idx in passcode_attr_idx self.cipher.get_prop_set_val(self.cipher.prop_key[attr_idx]) for attr_idx in passcode_attr_idx
] ]
distinct_sets = len(set(passcode_set_values)) distinct_sets = len(set(passcode_set_values))
distinct_attributes = len(set(passcode_attr_idx)) distinct_attributes = len(set(passcode_attr_idx))

View File

@@ -1,7 +1,6 @@
from dataclasses import dataclass, field from dataclasses import dataclass, field
from uuid import UUID, uuid4 from uuid import UUID, uuid4
from typing import Dict, List, Tuple from typing import Dict, List, Tuple
from src.customer import Customer from src.customer import Customer
from src.models import NKodePolicy, KeypadSize from src.models import NKodePolicy, KeypadSize
from src.user import User from src.user import User
@@ -19,7 +18,7 @@ class NKodeAPI:
def create_new_customer(self, keypad_size: KeypadSize, nkode_policy: NKodePolicy) -> UUID: def create_new_customer(self, keypad_size: KeypadSize, nkode_policy: NKodePolicy) -> UUID:
new_customer = Customer( new_customer = Customer(
customer_id=uuid4(), customer_id=uuid4(),
customer_cipher=CustomerCipher.create(keypad_size), cipher=CustomerCipher.create(keypad_size),
users={}, users={},
nkode_policy=nkode_policy nkode_policy=nkode_policy
) )
@@ -30,7 +29,7 @@ class NKodeAPI:
if customer_id not in self.customers.keys(): if customer_id not in self.customers.keys():
raise ValueError(f"Customer with ID '{customer_id}' does not exist") raise ValueError(f"Customer with ID '{customer_id}' does not exist")
customer = self.customers[customer_id] customer = self.customers[customer_id]
login_keypad = UserKeypad.create(customer.customer_cipher.keypad_size) login_keypad = UserKeypad.create(customer.cipher.keypad_size)
set_keypad = login_keypad.sign_up_keypad() set_keypad = login_keypad.sign_up_keypad()
new_session = UserSignupSession( new_session = UserSignupSession(
session_id=uuid4(), session_id=uuid4(),
@@ -76,15 +75,15 @@ class NKodeAPI:
customer = self.customers[customer_id] customer = self.customers[customer_id]
passcode = self.signup_sessions[session_id].deduce_passcode(confirm_key_entry) passcode = self.signup_sessions[session_id].deduce_passcode(confirm_key_entry)
new_user_keys = UserCipher.create( new_user_keys = UserCipher.create(
customer.customer_cipher.keypad_size, customer.cipher.keypad_size,
customer.customer_cipher.set_key, customer.cipher.set_key,
customer.nkode_policy.max_nkode_len customer.nkode_policy.max_nkode_len
) )
enciphered_passcode = new_user_keys.encipher_nkode(passcode, customer.customer_cipher) enciphered_passcode = new_user_keys.encipher_nkode(passcode, customer.cipher)
new_user = User( new_user = User(
username=username, username=username,
enciphered_passcode=enciphered_passcode, enciphered_passcode=enciphered_passcode,
user_keys=new_user_keys, cipher=new_user_keys,
user_keypad=self.signup_sessions[session_id].login_keypad, user_keypad=self.signup_sessions[session_id].login_keypad,
) )
self.customers[customer_id].add_new_user(new_user) self.customers[customer_id].add_new_user(new_user)

View File

@@ -10,20 +10,20 @@ from src.utils import xor_lists
class User: class User:
username: str username: str
enciphered_passcode: EncipheredNKode enciphered_passcode: EncipheredNKode
user_keys: UserCipher cipher: UserCipher
user_keypad: UserKeypad user_keypad: UserKeypad
renew: bool = field(default=False) renew: bool = field(default=False)
def renew_keys(self, sets_xor: list[int], attrs_xor: list[int]): def renew_keys(self, set_xor: list[int], prop_xor: list[int]):
self.renew = True self.renew = True
self.user_keys.set_key = xor_lists(self.user_keys.set_key, sets_xor) self.cipher.set_key = xor_lists(self.cipher.set_key, set_xor)
self.user_keys.prop_key = xor_lists(self.user_keys.prop_key, attrs_xor) self.cipher.prop_key = xor_lists(self.cipher.prop_key, prop_xor)
def refresh_passcode(self, passcode_attr_idx: list[int], customer_attributes: CustomerCipher): def refresh_passcode(self, passcode_attr_idx: list[int], customer_attributes: CustomerCipher):
self.user_keys = UserCipher.create( self.cipher = UserCipher.create(
customer_attributes.keypad_size, customer_attributes.keypad_size,
customer_attributes.set_key, customer_attributes.set_key,
self.user_keys.max_nkode_len self.cipher.max_nkode_len
) )
self.enciphered_passcode = self.user_keys.encipher_nkode(passcode_attr_idx, customer_attributes) self.enciphered_passcode = self.cipher.encipher_nkode(passcode_attr_idx, customer_attributes)
self.renew = False self.renew = False

View File

@@ -2,17 +2,18 @@ import base64
import hashlib import hashlib
from dataclasses import dataclass from dataclasses import dataclass
import bcrypt import bcrypt
import numpy as np
from secrets import choice from secrets import choice
from src.models import EncipheredNKode, KeypadSize from src.models import EncipheredNKode, KeypadSize
from src.customer_cipher import CustomerCipher from src.customer_cipher import CustomerCipher
from src.utils import generate_random_nonrepeating_list, xor_lists, int_array_to_bytes
@dataclass @dataclass
class UserCipher: class UserCipher:
prop_key: list[int] prop_key: np.ndarray
set_key: list[int] set_key: np.ndarray
pass_key: list[int] pass_key: np.ndarray
mask_key: list[int] mask_key: np.ndarray
salt: bytes salt: bytes
max_nkode_len: int max_nkode_len: int
@@ -21,41 +22,50 @@ class UserCipher:
if len(set_values) != keypad_size.props_per_key: if len(set_values) != keypad_size.props_per_key:
raise ValueError("Invalid set values") raise ValueError("Invalid set values")
set_key = generate_random_nonrepeating_list(keypad_size.props_per_key) set_values_array = np.array(set_values, dtype=np.uint16)
set_key = xor_lists(set_key, set_values) set_key = generate_random_nonrepeating_array(keypad_size.props_per_key)
set_key = np.bitwise_xor(set_key, set_values_array)
return UserCipher( return UserCipher(
prop_key=generate_random_nonrepeating_list(keypad_size.props_per_key * keypad_size.numb_of_keys), prop_key=generate_random_nonrepeating_array(keypad_size.props_per_key * keypad_size.numb_of_keys),
pass_key=generate_random_nonrepeating_list(max_nkode_len), pass_key=generate_random_nonrepeating_array(max_nkode_len),
mask_key=generate_random_nonrepeating_list(max_nkode_len), mask_key=generate_random_nonrepeating_array(max_nkode_len),
set_key=set_key, set_key=set_key,
salt=bcrypt.gensalt(), salt=bcrypt.gensalt(),
max_nkode_len=max_nkode_len max_nkode_len=max_nkode_len
) )
def pad_user_mask(self, user_mask: list[int], set_vals: list[int]) -> list[int]: def pad_user_mask(self, user_mask: list[int], set_vals: list[int]) -> np.ndarray:
if len(user_mask) >= self.max_nkode_len: if len(user_mask) >= self.max_nkode_len:
raise ValueError("User mask is too long") raise ValueError("User mask is too long")
padded_user_mask = user_mask.copy()
for _ in range(self.max_nkode_len - len(user_mask)): user_mask_array = np.array(user_mask, dtype=np.uint16)
padded_user_mask.append(choice(set_vals)) set_vals_array = np.array(set_vals, dtype=np.uint16)
# Create padding of random choices from set_vals
padding_size = self.max_nkode_len - len(user_mask)
padding_indices = np.random.choice(len(set_vals), padding_size)
padding = np.array([set_vals[i] for i in padding_indices], dtype=np.uint16)
# Concatenate original mask with padding
padded_user_mask = np.concatenate([user_mask_array, padding])
return padded_user_mask return padded_user_mask
@staticmethod @staticmethod
def encode_base64_str(data: list[int]) -> str: def encode_base64_str(data: np.ndarray) -> str:
return base64.b64encode(int_array_to_bytes(data)).decode("utf-8") return base64.b64encode(int_array_to_bytes(data)).decode("utf-8")
@staticmethod @staticmethod
def decode_base64_str(data: str) -> list[int]: def decode_base64_str(data: str) -> np.ndarray:
byte_data = base64.b64decode(data) byte_data = base64.b64decode(data)
int_list = [] int_list = []
for i in range(0, len(byte_data), 2): for i in range(0, len(byte_data), 2):
int_val = int.from_bytes(byte_data[i:i + 2], byteorder='big') int_val = int.from_bytes(byte_data[i:i + 2], byteorder='big')
int_list.append(int_val) int_list.append(int_val)
return int_list return np.array(int_list, dtype=np.uint16)
def _hash_passcode(self, passcode: list[int]) -> str: def _hash_passcode(self, passcode: np.ndarray) -> str:
passcode_bytes = int_array_to_bytes(passcode) passcode_bytes = int_array_to_bytes(passcode)
passcode_digest = base64.b64encode(hashlib.sha256(passcode_bytes).digest()) passcode_digest = base64.b64encode(hashlib.sha256(passcode_bytes).digest())
hashed_data = bcrypt.hashpw(passcode_digest, self.salt) hashed_data = bcrypt.hashpw(passcode_digest, self.salt)
@@ -66,10 +76,10 @@ class UserCipher:
passcode_prop_idx: list[int], passcode_prop_idx: list[int],
customer_cipher: CustomerCipher customer_cipher: CustomerCipher
) -> EncipheredNKode: ) -> EncipheredNKode:
passcode_prop_idx_array = np.array(passcode_prop_idx, dtype=np.uint16)
passcode_attrs = [customer_cipher.prop_key[idx] for idx in passcode_prop_idx] passcode_attrs = np.array([customer_cipher.prop_key[idx] for idx in passcode_prop_idx_array], dtype=np.uint16)
passcode_sets = [customer_cipher.get_prop_set_val(attr) for attr in passcode_attrs] passcode_sets = np.array([customer_cipher.get_prop_set_val(attr) for attr in passcode_attrs], dtype=np.uint16)
mask = self.encipher_mask(passcode_sets, customer_cipher) mask = self.encipher_mask(passcode_sets.tolist(), customer_cipher)
code = self.encipher_salt_hash_code(passcode_prop_idx, customer_cipher) code = self.encipher_salt_hash_code(passcode_prop_idx, customer_cipher)
return EncipheredNKode( return EncipheredNKode(
code=code, code=code,
@@ -81,12 +91,15 @@ class UserCipher:
passcode_prop_idx: list[int], passcode_prop_idx: list[int],
customer_prop: CustomerCipher, customer_prop: CustomerCipher,
) -> str: ) -> str:
passcode_len = len(passcode_prop_idx) passcode_prop_idx_array = np.array(passcode_prop_idx, dtype=np.uint16)
passcode_attrs = [customer_prop.prop_key[idx] for idx in passcode_prop_idx] passcode_len = len(passcode_prop_idx_array)
passcode_attrs = np.array([customer_prop.prop_key[idx] for idx in passcode_prop_idx_array], dtype=np.uint16)
passcode_cipher = self.pass_key.copy() passcode_cipher = self.pass_key.copy()
for idx in range(passcode_len): for idx in range(passcode_len):
attr_idx = passcode_prop_idx[idx] attr_idx = passcode_prop_idx_array[idx]
passcode_cipher[idx] ^= self.prop_key[attr_idx] ^ passcode_attrs[idx] passcode_cipher[idx] = passcode_cipher[idx] ^ self.prop_key[attr_idx] ^ passcode_attrs[idx]
return self._hash_passcode(passcode_cipher) return self._hash_passcode(passcode_cipher)
def encipher_mask( def encipher_mask(
@@ -95,19 +108,47 @@ class UserCipher:
customer_attributes: CustomerCipher customer_attributes: CustomerCipher
) -> str: ) -> str:
padded_passcode_sets = self.pad_user_mask(passcode_sets, customer_attributes.set_key) padded_passcode_sets = self.pad_user_mask(passcode_sets, customer_attributes.set_key)
set_idx = [customer_attributes.get_set_index(set_val) for set_val in padded_passcode_sets]
mask_set_keys = [self.set_key[idx] for idx in set_idx] # Get indices of set values
ciphered_mask = xor_lists(mask_set_keys, padded_passcode_sets) set_idx = np.array([customer_attributes.get_set_index(set_val) for set_val in padded_passcode_sets],
ciphered_mask = xor_lists(ciphered_mask, self.mask_key) dtype=np.uint16)
mask_set_keys = np.array([self.set_key[idx] for idx in set_idx], dtype=np.uint16)
# XOR operations
ciphered_mask = np.bitwise_xor(mask_set_keys, padded_passcode_sets)
ciphered_mask = np.bitwise_xor(ciphered_mask, self.mask_key)
mask = self.encode_base64_str(ciphered_mask) mask = self.encode_base64_str(ciphered_mask)
return mask return mask
def decipher_mask(self, mask: str, set_vals: list, passcode_len: int) -> list[int]: def decipher_mask(self, mask: str, set_vals: list, passcode_len: int) -> list[int]:
set_vals_array = np.array(set_vals, dtype=np.uint16)
decoded_mask = self.decode_base64_str(mask) decoded_mask = self.decode_base64_str(mask)
deciphered_mask = xor_lists(decoded_mask, self.mask_key) deciphered_mask = np.bitwise_xor(decoded_mask, self.mask_key)
set_key_rand_component = xor_lists(set_vals, self.set_key)
set_key_rand_component = np.bitwise_xor(set_vals_array, self.set_key)
passcode_sets = [] passcode_sets = []
for set_cipher in deciphered_mask[:passcode_len]: for set_cipher in deciphered_mask[:passcode_len]:
set_idx = set_key_rand_component.index(set_cipher) # Find index where values match
set_idx = np.where(set_key_rand_component == set_cipher)[0][0]
passcode_sets.append(set_vals[set_idx]) passcode_sets.append(set_vals[set_idx])
return passcode_sets return passcode_sets
# NumPy utility functions to replace the existing ones
def generate_random_nonrepeating_array(array_len: int, min_val: int = 0, max_val: int = 2 ** 16) -> np.ndarray:
if max_val - min_val < array_len:
raise ValueError("Range of values is less than the array length requested")
# Generate array of random unique integers
return np.random.choice(
np.arange(min_val, max_val, dtype=np.uint16),
size=array_len,
replace=False
)
def int_array_to_bytes(int_arr: np.ndarray, byte_size: int = 2) -> bytes:
return b"".join([int(num).to_bytes(byte_size, byteorder='big') for num in int_arr])

View File

@@ -22,7 +22,7 @@ def test_shuffle_attrs(user_keypad):
expected statistical outcomes like: expected statistical outcomes like:
- every attribute gets to every key with a uniform distribution - every attribute gets to every key with a uniform distribution
- every attribute is adjacent to every other attribute with uniform distribution - every attribute is adjacent to every other attribute with uniform distribution
- the order in which the customer_cipher move from key to key is random (i.e. the distance traveled is uniform) - the order in which the cipher move from key to key is random (i.e. the distance traveled is uniform)
""" """
pre_shuffle_keypad = user_keypad.keypad pre_shuffle_keypad = user_keypad.keypad
user_keypad.partial_keypad_shuffle() user_keypad.partial_keypad_shuffle()