implement jinja nkode_authentication_template.md
This commit is contained in:
0
docs/__init__.py
Normal file
0
docs/__init__.py
Normal file
419
docs/nkode_authentication_template.md
Normal file
419
docs/nkode_authentication_template.md
Normal file
@@ -0,0 +1,419 @@
|
||||
# nKode Authentication
|
||||
Play around with the code in [this](http://sesolgit/Repository/Blob/92a60227-4ef9-4196-8ebb-595581abf98c?encodedName=main&encodedPath=nkode_tutorial.ipynb) jupyter notebook.
|
||||
|
||||
|
||||
## Customer Creation
|
||||
Before a user can be created, a customer with random attribute and set
|
||||
values is created. The customers manage user's. They define an nKode policy, keypad's dimensions,
|
||||
attributes/sets in the keypad, and the frequency of attribute renew.
|
||||
### nKode Policy and Keypad Size
|
||||
An nKode policy defines:
|
||||
<ul>
|
||||
<li>the maximum length of a user's nKode</li>
|
||||
<li>the minimum length of a user's nKode</li>
|
||||
<li>the number of unique set values in a user's nKode</li>
|
||||
<li>the number of unique values in a user's nKode</li>
|
||||
<li>the number of bytes an attribute or set value is</li>
|
||||
</ul>
|
||||
|
||||
The keypad size defines:
|
||||
<ul>
|
||||
<li>the number of keys in the keypad displayed to the user</li>
|
||||
<li>attributes per key</li>
|
||||
</ul>
|
||||
|
||||
The number of attributes must be greater than the number of keys to be [dispersion](nkode_concepts.md/#dispersion-resistant-interface) resistant.
|
||||
```
|
||||
api = NKodeAPI()
|
||||
|
||||
policy = NKodePolicy(
|
||||
max_nkode_len=10,
|
||||
min_nkode_len=4,
|
||||
distinct_sets=0,
|
||||
distinct_attributes=4,
|
||||
byte_len=2
|
||||
)
|
||||
|
||||
keypad_size = KeypadSize(
|
||||
numb_of_keys = 5,
|
||||
attrs_per_key = 6 # aka number of sets
|
||||
)
|
||||
|
||||
customer_id = api.create_new_customer(keypad_size, policy)
|
||||
customer = api.customers[customer_id]
|
||||
```
|
||||
### Customer Attributes and Sets
|
||||
A customer has users and defines the attributes and set values for all its users.
|
||||
Since our customer has 5 keys and 6 attributes per key, this gives a customer interface of 30 distinct attributes and 6 distinct attribute sets.
|
||||
Each attribute belongs to one of the 6 sets. In this example, each attribute and set value is a unique 2 byte integer.
|
||||
|
||||
```
|
||||
set_vals = customer.attributes.set_vals
|
||||
|
||||
Customer Sets: {{ customer_set_vals }}
|
||||
```
|
||||
|
||||
```
|
||||
attr_vals = customer.attributes.attr_vals
|
||||
keypad_view(attr_vals, keypad_size.attrs_per_key)
|
||||
|
||||
Customer Attributes:
|
||||
{% for attrs in customer_attr_view -%}
|
||||
{{ attrs }}
|
||||
{% endfor %}
|
||||
```
|
||||
|
||||
Attributes organized by set:
|
||||
```
|
||||
attr_set_view = matrix_transpose(attr_keypad_view)
|
||||
set_attribute_dict = dict(zip(set_vals, attr_set_view))
|
||||
|
||||
Set to Attribute Map:
|
||||
{% for set_val, attrs in set_attribute_dict.items() -%}
|
||||
{{ set_val }} : {{ attrs }}
|
||||
{% endfor %}
|
||||
```
|
||||
|
||||
## User Signup
|
||||
Now that we have a customer, we can create users. To create a new user:
|
||||
|
||||
1. Generate a random interface
|
||||
2. User sets their nKode and sends their selection to the server
|
||||
3. User confirms their nKode and the user is created if the nKode matches the nKode policy
|
||||
### Random Interface Generation
|
||||
For the server to determine the users nkode, the user's interface must be dispersable.
|
||||
To make the interface dispersable, the server will randomly drop attribute sets to make the
|
||||
number of attributes equal to the number of keys. In our case, the server randomly drops 1 attribute set
|
||||
to give us a 5 X 5 keypad with possible index values ranging from 0-29.
|
||||
Each value in the interface is the index value of a customer attribute.
|
||||
The user never learns what their "real" attribute is. They don't see the index value that represents their nKode or
|
||||
the customer value it is associated with.
|
||||
```
|
||||
session_id, signup_interface = api.generate_index_interface(customer_id)
|
||||
signup_interface_keypad = list_to_matrix(signup_interface, keypad_size.attrs_per_key)
|
||||
|
||||
Signup Keypad:
|
||||
{% for key in signup_keypad -%}
|
||||
Key {{ loop.index }}: {{ key }}
|
||||
{% endfor %}
|
||||
```
|
||||
|
||||
### Set nKode
|
||||
The user identifies attributes in the interface they want in their nkode. Each attribute has an index value.
|
||||
Below the user has selected `{{ user_passcode }}`. These index values can be represented by anything in the GUI.
|
||||
The only requirement is that the GUI attributes must be associated with the same index everytime the user goes to login.
|
||||
If the user wants to change anything about their interface, they must also change their nkode.
|
||||
```
|
||||
username = {{ username }}
|
||||
user_passcode = {{ user_passcode }}
|
||||
selected_keys_set = select_keys_with_passcode_values(user_passcode, signup_interface, keypad_size.attrs_per_key)
|
||||
|
||||
Selected Keys
|
||||
{{ selected_keys_set }}
|
||||
```
|
||||
|
||||
The user's passcode server side attributes are:
|
||||
```
|
||||
server_side_attr = [customer.attributes.attr_vals[idx] for idx in user_passcode]
|
||||
|
||||
User Passcode Server-side Attributes: {{ server_side_attr }}
|
||||
```
|
||||
|
||||
### Confirm nKode
|
||||
The user submits the set interface to the sever and recieves the _confirm interface_ as a response.
|
||||
The user finds their nKode again.
|
||||
```
|
||||
confirm_interface = api.set_nkode(username, customer_id, selected_keys_set, session_id)
|
||||
keypad_view(confirm_interface, keypad_size.numb_of_keys)
|
||||
selected_keys_confirm = select_keys_with_passcode_values(user_passcode, confirm_interface, keypad_size.numb_of_keys)
|
||||
|
||||
Confirm Keypad:
|
||||
{% for key in confirm_keypad -%}
|
||||
Key {{ loop.index }}: {{ key }}
|
||||
{% endfor %}
|
||||
Selected Keys:
|
||||
{{ selected_keys_confirm }}
|
||||
```
|
||||
|
||||
The user submits their confirm key selection and the user is created
|
||||
```
|
||||
success = api.confirm_nkode(username, customer_id, selected_keys_confirm, session_id)
|
||||
```
|
||||
|
||||
### Passcode Enciphering, Hashing, and Salting
|
||||
When a new user creates an nKode, the server caches its set and confirm interface as well as the users key selection.
|
||||
The on the last api.confirm_nkode the server:
|
||||
|
||||
1. Deduces the users attributes
|
||||
2. Validates the Passcode against the nKodePolicy
|
||||
3. Creates new User Cipher Keys
|
||||
4. Enciphers the user's mask
|
||||
5. Enciphers, salts and hashes the user's passcode
|
||||
|
||||
Steps 1-2 are straight forward. For a better idea of how they work, see pyNKode
|
||||
|
||||
#### User Cipher Keys
|
||||
|
||||
##### User Cipher Keys Data Structure
|
||||
```
|
||||
set_key = generate_random_nonrepeating_list(keypad_size.attrs_per_key, max_numb=2**(8*numb_of_bytes))
|
||||
set_key = xor_lists(set_key, customer_attr.set_vals)
|
||||
|
||||
UserCipherKeys(
|
||||
alpha_key=generate_random_nonrepeating_list(keypad_size.attrs_per_key * keypad_size.numb_of_keys, max_numb=2**(8*numb_of_bytes)),
|
||||
pass_key=generate_random_nonrepeating_list(max_nkode_len, max_numb=2**(8*numb_of_bytes)),
|
||||
mask_key=generate_random_nonrepeating_list(max_nkode_len, max_numb=2**(8*numb_of_bytes)),
|
||||
set_key=set_key,
|
||||
salt=bcrypt.gensalt(),
|
||||
max_nkode_len=max_nkode_len
|
||||
)
|
||||
```
|
||||
|
||||
##### User Cipher Keys Values
|
||||
```
|
||||
user_keys = UserCipherKeys(
|
||||
alpha_key = {{ user_keys.alpha_key }},
|
||||
pass_key = {{ user_keys.pass_key }},
|
||||
mask_key = {{ user_keys.mask_key }},
|
||||
set_key = {{ user_keys.set_key }},
|
||||
salt = {{ user_keys.salt }},
|
||||
max_nkode_len = {{ user_keys.max_nkode_len }}
|
||||
)
|
||||
```
|
||||
|
||||
The method UserCipherKeys.encipher_nkode secures a users nKode in the database. This method is called in api.confirm_nkode
|
||||
```
|
||||
class EncipheredNKode(BaseModel):
|
||||
code: str
|
||||
mask: str
|
||||
```
|
||||
|
||||
#### Mask Enciphering
|
||||
|
||||
Recall:
|
||||
|
||||
- set_key_i = (set_rand_numb_i ^ set_val_i)
|
||||
- mask_key_i = mask_rand_numb_i
|
||||
- padded_passcode_server_set_i = set_val_i
|
||||
- len(set_key) == len(mask_key) == (padded_passcode_server_set) == max_nkode_len == 10
|
||||
where i is the index
|
||||
|
||||
- mask_i = mask_key_i ^ padded_passcode_server_set_i ^ set_key_i
|
||||
- mask_i = mask_rand_num_i ^ set_val_i ^ set_rand_numb_i ^ set_val_i
|
||||
- mask_i = mask_rand_num_i ^ set_rand_numb_i # set_val_i is cancelled out
|
||||
|
||||
|
||||
```
|
||||
# the passcode is deduced in confirm_nkode. These values are the index values of the customer attribute values
|
||||
passcode = {{ user_passcode }}
|
||||
passcode_server_attr = [customer.attributes.attr_vals[idx] for idx in passcode]
|
||||
passcode_server_set = [customer.attributes.get_attr_set_val(attr) for attr in passcode_server_attr]
|
||||
|
||||
Passcode Set Vals: {{ passcode_server_attr }}
|
||||
Passcode Attr Vals: {{ passcode_server_set }}
|
||||
```
|
||||
|
||||
```
|
||||
# pad passcode set list with random set values so the list is equal to the max nkode value. This hids the nKode's length
|
||||
padded_passcode_server_set = user_keys.pad_user_mask(passcode_server_set, customer.nkode_policy.max_nkode_len)
|
||||
|
||||
# get the index of each set value
|
||||
set_idx = [customer.attributes.get_set_index(set_val) for set_val in padded_passcode_server_set]
|
||||
|
||||
# find the set values matching set key to cancel out the set value
|
||||
mask_set_keys = [user_keys.set_key[idx] for idx in set_idx]
|
||||
|
||||
# xor the set key, passocode set value and the mask key
|
||||
ciphered_mask = xor_lists(mask_set_keys, padded_passcode_server_set)
|
||||
ciphered_mask = xor_lists(ciphered_mask, user_keys.mask_key)
|
||||
|
||||
# encode ciphered mask in base64
|
||||
mask = user_keys.encode_base64_str(ciphered_mask)
|
||||
Mask: {{ enciphered_nkode.mask }}
|
||||
```
|
||||
|
||||
#### Passcode Enciphering and Hashing
|
||||
|
||||
- ciphered_customer_attr = alpha_key ^ customer_attr
|
||||
- ciphered_passcode_i = pass_key_i ^ ciphered_customer_attr_i
|
||||
- code = hash(ciphered_passcode, salt)
|
||||
|
||||
```
|
||||
ciphered_customer_attrs = xor_lists(customer.attributes.attr_vals, user_keys.alpha_key)
|
||||
passcode_ciphered_attrs = [ciphered_customer_attrs[idx] for idx in passcode]
|
||||
pad_len = customer.nkode_policy.max_nkode_len - passcode_len
|
||||
|
||||
passcode_ciphered_attrs.extend([0 for _ in range(pad_len)])
|
||||
|
||||
ciphered_code = xor_lists(passcode_ciphered_attrs, user_keys.pass_key)
|
||||
|
||||
passcode_bytes = int_array_to_bytes(ciphered_code)
|
||||
passcode_digest = base64.b64encode(hashlib.sha256(passcode_bytes).digest())
|
||||
hashed_data = bcrypt.hashpw(passcode_digest, user_keys.salt)
|
||||
code = hashed_data.decode("utf-8")
|
||||
|
||||
Code: {{ enciphered_nkode.code }}
|
||||
```
|
||||
|
||||
## User Login
|
||||
1. Get login interface
|
||||
2. Login
|
||||
|
||||
### Get Login Interface
|
||||
The client requests the user's login interface.
|
||||
```
|
||||
login_interface = api.get_login_interface(username, customer_id)
|
||||
keypad_view(login_interface, keypad_size.attrs_per_key)
|
||||
```
|
||||
The server returns a randomly shuffled interface. Learn more about how the [User Interface Shuffle](nkode_concepts.md/#user-interface-shuffle) works
|
||||
```
|
||||
Login Interface Keypad View:
|
||||
{% for key in login_keypad -%}
|
||||
Key {{ loop.index }}: {{ key }}
|
||||
{% endfor %}
|
||||
```
|
||||
Recall the user's passcode is `user_passcode = {{ user_passcode }}` so the user selects keys ` selected_keys_login = {{ selected_login_keys }}`
|
||||
|
||||
```
|
||||
success = api.login(customer_id, username, selected_keys_login)
|
||||
```
|
||||
|
||||
### Validate Login Key Entry
|
||||
- decipher user mask and recover nkode set values
|
||||
- get presumed attribute from key selection and set values
|
||||
- encipher, salt and hash presumed attribute values and compare it to the users hashed code
|
||||
|
||||
#### Decipher Mask
|
||||
Recall:
|
||||
- set_key_i = (set_key_rand_numb_i ^ set_val_i)
|
||||
- mask_i = mask_key_rand_num_i ^ set_key_rand_numb_i
|
||||
|
||||
Recover nKode set values:
|
||||
- decode mask from base64 to int
|
||||
- deciphered_mask = mask ^ mask_key
|
||||
- deciphered_mask_i = set_key_rand_numb # mask_key_rand_num_i is cancelled out
|
||||
- set_key_rand_component = set_key ^ set_values
|
||||
- deduce the set value
|
||||
|
||||
```
|
||||
user = customer.users[username]
|
||||
user_keys = user.user_keys
|
||||
user_mask = user.enciphered_passcode.mask
|
||||
decoded_mask = user_keys.decode_base64_str(user_mask)
|
||||
deciphered_mask = xor_lists(decoded_mask, user_keys.mask_key)
|
||||
set_key_rand_component = xor_lists(set_vals, user_keys.set_key)
|
||||
passcode_sets = []
|
||||
for set_cipher in deciphered_mask[:passcode_len]:
|
||||
set_idx = set_key_rand_component.index(set_cipher)
|
||||
passcode_sets.append(set_vals[set_idx])
|
||||
|
||||
Passcode Sets: {{ login_passcode_sets }}
|
||||
```
|
||||
|
||||
|
||||
### Get Presumed Attributes
|
||||
```
|
||||
set_vals_idx = [customer.attributes.get_set_index(set_val) for set_val in passcode_sets]
|
||||
|
||||
presumed_selected_attributes_idx = []
|
||||
for idx in range(passcode_len):
|
||||
key_numb = selected_keys_login[idx]
|
||||
set_idx = set_vals_idx[idx]
|
||||
selected_attr_idx = customer.users[username].user_interface.get_attr_idx_by_keynumb_setidx(key_numb, set_idx)
|
||||
presumed_selected_attributes_idx.append(selected_attr_idx)
|
||||
|
||||
Presumped Passcode: {{ presumed_selected_attributes_idx }}
|
||||
Recall User Passcode: {{ user_passcode }}
|
||||
```
|
||||
### Compare Enciphered Passcodes
|
||||
```
|
||||
enciphered_nkode = user_keys.encipher_salt_hash_code(presumed_selected_attributes_idx, customer.attributes)
|
||||
|
||||
```
|
||||
If `enciphered_nkode == user.enciphered_passcode.code`, the user's key selection is valid and the login is successful.
|
||||
|
||||
## Renew Attributes
|
||||
Attributes renew is invoked with the renew_attributes method: `api.renew_attributes(customer_id)`
|
||||
The renew attributes processes has three steps:
|
||||
1. Renew Customer Attributes
|
||||
2. Renew User Keys
|
||||
3. Refresh User on Login
|
||||
|
||||
When the `renew_attributes` method is called, the customer attributes are renewed and all it's users go through an intermediate
|
||||
renew step. The user if fully renewed after their first successful login. This first login refreshes their keys, salt, and hash.
|
||||
|
||||
|
||||
### Customer Renew
|
||||
Old Customer attributes and set values are cached copied to variables before they are renewed.
|
||||
```
|
||||
old_sets = customer.attributes.set_vals
|
||||
|
||||
Customer Sets: {{ customer_set_vals }}
|
||||
```
|
||||
|
||||
```
|
||||
old_attr = customer.attributes.attr_vals
|
||||
|
||||
Customer Attributes:
|
||||
{% for attrs in customer_attr_view -%}
|
||||
{{ attrs }}
|
||||
{% endfor %}
|
||||
```
|
||||
|
||||
After the renew, the customer attributes and sets are new randomly generated values.
|
||||
```
|
||||
api.renew_attributes(customer_id)
|
||||
|
||||
set_vals = customer.attributes.set_vals
|
||||
|
||||
Customer Sets: {{ customer_new_set_vals }}
|
||||
```
|
||||
|
||||
```
|
||||
attr_vals = customer.attributes.attr_vals
|
||||
|
||||
Customer Attributes:
|
||||
{% for attrs in customer_new_attr_view -%}
|
||||
{{ attrs }}
|
||||
{% endfor %}
|
||||
```
|
||||
|
||||
### Renew User
|
||||
During the renew, each user goes through a temporary transition period.
|
||||
```
|
||||
attrs_xor = xor_lists(new_attrs, old_attrs)
|
||||
sets_xor = xor_lists(new_sets, old_sets)
|
||||
for user in customer.users.values():
|
||||
user.renew = True
|
||||
user.user_keys.set_key = xor_lists(user.user_keys.set_key, sets_xor)
|
||||
user.user_keys.alpha_key = xor_lists(user.user_keys.alpha_key, attrs_xor)
|
||||
```
|
||||
##### User Alpha Key
|
||||
The user's alpha key was a randomly generated list of length `numb_of_keys * attr_per_key`.
|
||||
Now each value in the alpha key is `alpha_key_i = old_alpha_key_i ^ new_attr_i ^ old_attr_i`.
|
||||
Recall in the login process, `ciphered_customer_attrs = alpha_key ^ customer_attr`.
|
||||
Since the customer_attr is now the new value, it gets cancelled out leaving:
|
||||
```
|
||||
new_alpha_key = old_alpha_key ^ old_attr ^ new_attr
|
||||
ciphered_customer_attrs = new_alpha_key ^ new_attr
|
||||
ciphered_customer_attrs = old_alpha_key ^ old_attr # since new_attr cancel out
|
||||
```
|
||||
We can valid the user's login attempt with the same hash using the new customer attributes
|
||||
|
||||
##### User Set Key
|
||||
The user's set key was a randomly generated list of length `attr_per_key` xor `customer_set_vals`.
|
||||
Now the `old_set_vals` have been replaced with the new `new_set_vals`. The deciphering process described above
|
||||
remains the same.
|
||||
|
||||
### User Refresh
|
||||
Once the user has a successful login, they get a new salt and cipher keys, and their `enciphered_passcode` is recomputed
|
||||
with the new values.
|
||||
```
|
||||
user.user_keys = UserCipherKeys.new(
|
||||
customer.attributes.keypad_size,
|
||||
customer.attributes.set_vals,
|
||||
user.user_keys.max_nkode_len
|
||||
)
|
||||
user.enciphered_passcode = user.user_keys.encipher_nkode(presumed_selected_attributes_idx, customer.attributes)
|
||||
user.renew = False
|
||||
```
|
||||
@@ -95,6 +95,6 @@ class NKodeAPI(BaseModel):
|
||||
customer = self.customers[customer_id]
|
||||
return customer.valid_key_entry(username, key_selection)
|
||||
|
||||
def renew_keys(self, customer_id: UUID) -> bool:
|
||||
def renew_attributes(self, customer_id: UUID) -> bool:
|
||||
assert (customer_id in self.customers.keys())
|
||||
return self.customers[customer_id].renew_keys()
|
||||
|
||||
@@ -12,12 +12,12 @@
|
||||
"metadata": {
|
||||
"collapsed": false,
|
||||
"ExecuteTime": {
|
||||
"end_time": "2024-08-01T19:17:14.809230Z",
|
||||
"start_time": "2024-08-01T19:17:14.807153Z"
|
||||
"end_time": "2024-08-05T17:40:17.475149Z",
|
||||
"start_time": "2024-08-05T17:40:17.473025Z"
|
||||
}
|
||||
},
|
||||
"outputs": [],
|
||||
"execution_count": 90
|
||||
"execution_count": 12
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
@@ -38,12 +38,12 @@
|
||||
"metadata": {
|
||||
"collapsed": false,
|
||||
"ExecuteTime": {
|
||||
"end_time": "2024-08-01T19:17:14.881089Z",
|
||||
"start_time": "2024-08-01T19:17:14.877818Z"
|
||||
"end_time": "2024-08-05T17:40:17.556128Z",
|
||||
"start_time": "2024-08-05T17:40:17.552985Z"
|
||||
}
|
||||
},
|
||||
"outputs": [],
|
||||
"execution_count": 91
|
||||
"execution_count": 13
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
@@ -53,12 +53,12 @@
|
||||
"metadata": {
|
||||
"collapsed": false,
|
||||
"ExecuteTime": {
|
||||
"end_time": "2024-08-01T19:17:14.887878Z",
|
||||
"start_time": "2024-08-01T19:17:14.885951Z"
|
||||
"end_time": "2024-08-05T17:40:17.559851Z",
|
||||
"start_time": "2024-08-05T17:40:17.557794Z"
|
||||
}
|
||||
},
|
||||
"outputs": [],
|
||||
"execution_count": 92
|
||||
"execution_count": 14
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
@@ -98,12 +98,12 @@
|
||||
"metadata": {
|
||||
"collapsed": false,
|
||||
"ExecuteTime": {
|
||||
"end_time": "2024-08-01T19:17:15.071180Z",
|
||||
"start_time": "2024-08-01T19:17:14.890419Z"
|
||||
"end_time": "2024-08-05T17:40:17.740656Z",
|
||||
"start_time": "2024-08-05T17:40:17.570041Z"
|
||||
}
|
||||
},
|
||||
"outputs": [],
|
||||
"execution_count": 93
|
||||
"execution_count": 15
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
@@ -132,13 +132,16 @@
|
||||
"set_vals = customer.attributes.set_vals\n",
|
||||
"attr_vals = customer.attributes.attr_vals\n",
|
||||
"print(f\"Customer Sets: {set_vals}\")\n",
|
||||
"keypad_view(attr_vals, keypad_size.attrs_per_key)"
|
||||
"print(f\"Customer Attributes:\")\n",
|
||||
"interface_keypad = list_to_matrix(attr_vals, keypad_size.attrs_per_key)\n",
|
||||
"for idx, key_vals in enumerate(interface_keypad):\n",
|
||||
" print(f\"{key_vals}\")"
|
||||
],
|
||||
"metadata": {
|
||||
"collapsed": false,
|
||||
"ExecuteTime": {
|
||||
"end_time": "2024-08-01T19:17:15.075131Z",
|
||||
"start_time": "2024-08-01T19:17:15.072535Z"
|
||||
"end_time": "2024-08-05T17:40:17.744240Z",
|
||||
"start_time": "2024-08-05T17:40:17.741773Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
@@ -146,17 +149,17 @@
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Customer Sets: [27169, 36659, 54746, 56159, 47007, 38654]\n",
|
||||
"Keypad View\n",
|
||||
"Key 0: [63421, 44364, 4387, 12321, 14840, 38251]\n",
|
||||
"Key 1: [42757, 19108, 4797, 54866, 10010, 33108]\n",
|
||||
"Key 2: [61136, 42782, 46073, 53243, 53024, 53858]\n",
|
||||
"Key 3: [44676, 54825, 25002, 7458, 37684, 16872]\n",
|
||||
"Key 4: [65393, 10661, 14854, 8995, 64876, 36070]\n"
|
||||
"Customer Sets: [41463, 23817, 10115, 59621, 17701, 39232]\n",
|
||||
"Customer Attributes:\n",
|
||||
"[15101, 42072, 1835, 15413, 46991, 41978]\n",
|
||||
"[47133, 25183, 43097, 17581, 20893, 52753]\n",
|
||||
"[14863, 31428, 41789, 18633, 3962, 50372]\n",
|
||||
"[53357, 51786, 31149, 59745, 30907, 16058]\n",
|
||||
"[60389, 36053, 8246, 53494, 23730, 15317]\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"execution_count": 94
|
||||
"execution_count": 16
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
@@ -180,8 +183,8 @@
|
||||
"metadata": {
|
||||
"collapsed": false,
|
||||
"ExecuteTime": {
|
||||
"end_time": "2024-08-01T19:17:15.078753Z",
|
||||
"start_time": "2024-08-01T19:17:15.076083Z"
|
||||
"end_time": "2024-08-05T17:40:17.747131Z",
|
||||
"start_time": "2024-08-05T17:40:17.744937Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
@@ -190,16 +193,16 @@
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Set to Attribute Map:\n",
|
||||
"27169: [63421, 42757, 61136, 44676, 65393]\n",
|
||||
"36659: [44364, 19108, 42782, 54825, 10661]\n",
|
||||
"54746: [4387, 4797, 46073, 25002, 14854]\n",
|
||||
"56159: [12321, 54866, 53243, 7458, 8995]\n",
|
||||
"47007: [14840, 10010, 53024, 37684, 64876]\n",
|
||||
"38654: [38251, 33108, 53858, 16872, 36070]\n"
|
||||
"41463: [15101, 47133, 14863, 53357, 60389]\n",
|
||||
"23817: [42072, 25183, 31428, 51786, 36053]\n",
|
||||
"10115: [1835, 43097, 41789, 31149, 8246]\n",
|
||||
"59621: [15413, 17581, 18633, 59745, 53494]\n",
|
||||
"17701: [46991, 20893, 3962, 30907, 23730]\n",
|
||||
"39232: [41978, 52753, 50372, 16058, 15317]\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"execution_count": 95
|
||||
"execution_count": 17
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
@@ -229,27 +232,27 @@
|
||||
"metadata": {
|
||||
"collapsed": false,
|
||||
"ExecuteTime": {
|
||||
"end_time": "2024-08-01T19:17:15.083395Z",
|
||||
"start_time": "2024-08-01T19:17:15.080158Z"
|
||||
"end_time": "2024-08-05T17:40:17.751757Z",
|
||||
"start_time": "2024-08-05T17:40:17.748531Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"[[25, 14, 15, 23, 28],\n",
|
||||
" [13, 26, 21, 17, 4],\n",
|
||||
" [19, 20, 27, 29, 10],\n",
|
||||
" [1, 8, 3, 5, 22],\n",
|
||||
" [7, 2, 9, 11, 16]]"
|
||||
"[[29, 3, 19, 12, 26],\n",
|
||||
" [5, 27, 1, 0, 8],\n",
|
||||
" [23, 9, 13, 24, 20],\n",
|
||||
" [11, 21, 25, 18, 14],\n",
|
||||
" [17, 15, 7, 6, 2]]"
|
||||
]
|
||||
},
|
||||
"execution_count": 96,
|
||||
"execution_count": 18,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"execution_count": 96
|
||||
"execution_count": 18
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
@@ -270,13 +273,15 @@
|
||||
"user_passcode = signup_interface[:passcode_len]\n",
|
||||
"selected_keys_set = select_keys_with_passcode_values(user_passcode, signup_interface, keypad_size.numb_of_keys)\n",
|
||||
"print(f\"User Passcode: {user_passcode}\")\n",
|
||||
"print(f\"Selected Keys\\n{selected_keys_set}\")"
|
||||
"print(f\"Selected Keys\\n{selected_keys_set}\")\n",
|
||||
"server_side_attr = [customer.attributes.attr_vals[idx] for idx in user_passcode]\n",
|
||||
"print(f\"User Passcode Server-side Attributes: {server_side_attr}\")"
|
||||
],
|
||||
"metadata": {
|
||||
"collapsed": false,
|
||||
"ExecuteTime": {
|
||||
"end_time": "2024-08-01T19:17:15.087201Z",
|
||||
"start_time": "2024-08-01T19:17:15.084377Z"
|
||||
"end_time": "2024-08-05T17:40:17.755453Z",
|
||||
"start_time": "2024-08-05T17:40:17.752507Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
@@ -285,18 +290,24 @@
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Keypad View\n",
|
||||
"Key 0: [25, 14, 15, 23, 28]\n",
|
||||
"Key 1: [13, 26, 21, 17, 4]\n",
|
||||
"Key 2: [19, 20, 27, 29, 10]\n",
|
||||
"Key 3: [1, 8, 3, 5, 22]\n",
|
||||
"Key 4: [7, 2, 9, 11, 16]\n",
|
||||
"User Passcode: [25, 14, 15, 23]\n",
|
||||
"Key 0: [29, 3, 19, 12, 26]\n",
|
||||
"Key 1: [5, 27, 1, 0, 8]\n",
|
||||
"Key 2: [23, 9, 13, 24, 20]\n",
|
||||
"Key 3: [11, 21, 25, 18, 14]\n",
|
||||
"Key 4: [17, 15, 7, 6, 2]\n",
|
||||
"User Passcode: [29, 3, 19, 12]\n",
|
||||
"Selected Keys\n",
|
||||
"[0, 0, 0, 0]\n"
|
||||
"[0, 0, 0, 0]\n",
|
||||
"User Passcode Server-side Attributes: [15317, 15413, 51786, 14863]\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"execution_count": 97
|
||||
"execution_count": 19
|
||||
},
|
||||
{
|
||||
"metadata": {},
|
||||
"cell_type": "markdown",
|
||||
"source": ""
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
@@ -309,8 +320,8 @@
|
||||
"metadata": {
|
||||
"collapsed": false,
|
||||
"ExecuteTime": {
|
||||
"end_time": "2024-08-01T19:17:15.090959Z",
|
||||
"start_time": "2024-08-01T19:17:15.088160Z"
|
||||
"end_time": "2024-08-05T17:40:17.760514Z",
|
||||
"start_time": "2024-08-05T17:40:17.758171Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
@@ -319,17 +330,17 @@
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Keypad View\n",
|
||||
"Key 0: [1, 14, 21, 11, 10]\n",
|
||||
"Key 1: [19, 2, 15, 5, 4]\n",
|
||||
"Key 2: [13, 8, 9, 29, 28]\n",
|
||||
"Key 3: [25, 20, 3, 17, 16]\n",
|
||||
"Key 4: [7, 26, 27, 23, 22]\n",
|
||||
"Key 0: [23, 3, 25, 6, 8]\n",
|
||||
"Key 1: [17, 9, 19, 0, 14]\n",
|
||||
"Key 2: [5, 15, 13, 18, 26]\n",
|
||||
"Key 3: [11, 27, 7, 12, 20]\n",
|
||||
"Key 4: [29, 21, 1, 24, 2]\n",
|
||||
"Selected Keys\n",
|
||||
"[3, 0, 1, 4]\n"
|
||||
"[4, 0, 1, 3]\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"execution_count": 98
|
||||
"execution_count": 20
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
@@ -341,8 +352,8 @@
|
||||
"metadata": {
|
||||
"collapsed": false,
|
||||
"ExecuteTime": {
|
||||
"end_time": "2024-08-01T19:17:15.725645Z",
|
||||
"start_time": "2024-08-01T19:17:15.091674Z"
|
||||
"end_time": "2024-08-05T17:40:18.401946Z",
|
||||
"start_time": "2024-08-05T17:40:17.761154Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
@@ -354,7 +365,7 @@
|
||||
]
|
||||
}
|
||||
],
|
||||
"execution_count": 99
|
||||
"execution_count": 21
|
||||
},
|
||||
{
|
||||
"metadata": {},
|
||||
@@ -373,26 +384,50 @@
|
||||
{
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2024-08-01T19:17:16.066633Z",
|
||||
"start_time": "2024-08-01T19:17:15.726507Z"
|
||||
"end_time": "2024-08-05T17:54:37.484873Z",
|
||||
"start_time": "2024-08-05T17:54:37.480227Z"
|
||||
}
|
||||
},
|
||||
"cell_type": "code",
|
||||
"source": [
|
||||
"from src.user_cipher_keys import UserCipherKeys\n",
|
||||
"from src.utils import xor_lists\n",
|
||||
"\n",
|
||||
"user_keys = UserCipherKeys.new(\n",
|
||||
" customer.attributes.keypad_size,\n",
|
||||
" customer.attributes.set_vals,\n",
|
||||
" customer.nkode_policy.max_nkode_len\n",
|
||||
"\n",
|
||||
"set_key = [46785, 4782, 4405, 44408, 35377, 55527]\n",
|
||||
"set_key = xor_lists(set_key, customer.attributes.set_vals)\n",
|
||||
"user_keys = UserCipherKeys(\n",
|
||||
" alpha_key = [\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=[16090, 38488, 45111, 32674, 46216, 52013, 48980, 36811, 35296, 17206],\n",
|
||||
" mask_key=[29575, 43518, 44373, 62063, 37651, 31671, 31663, 65514, 36454, 47325],\n",
|
||||
" set_key=set_key,\n",
|
||||
" salt=b'$2b$12$fX.in.GGAjz3QBBwqSWc6e',\n",
|
||||
" max_nkode_len=customer.nkode_policy.max_nkode_len, \n",
|
||||
")\n",
|
||||
"\n",
|
||||
"passcode = [10, 23, 14, 7]\n",
|
||||
"passcode_server_attr = [customer.attributes.attr_vals[idx] for idx in passcode]\n",
|
||||
"passcode_server_set = [customer.attributes.get_attr_set_val(attr) for attr in passcode_server_attr]"
|
||||
"passcode_server_attr = [customer.attributes.attr_vals[idx] for idx in user_passcode]\n",
|
||||
"passcode_server_set = [customer.attributes.get_attr_set_val(attr) for attr in passcode_server_attr]\n",
|
||||
"print(f\"Passcode Set Vals: {passcode_server_set}\")\n",
|
||||
"print(f\"Passcode Attr Vals: {passcode_server_attr}\")"
|
||||
],
|
||||
"outputs": [],
|
||||
"execution_count": 100
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Passcode Set Vals: [17701, 39232, 10115, 23817]\n",
|
||||
"Passcode Attr Vals: [20893, 16058, 41789, 25183]\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"execution_count": 36
|
||||
},
|
||||
{
|
||||
"metadata": {},
|
||||
@@ -414,8 +449,8 @@
|
||||
{
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2024-08-01T19:17:16.070242Z",
|
||||
"start_time": "2024-08-01T19:17:16.067409Z"
|
||||
"end_time": "2024-08-05T17:52:29.553010Z",
|
||||
"start_time": "2024-08-05T17:52:29.549861Z"
|
||||
}
|
||||
},
|
||||
"cell_type": "code",
|
||||
@@ -431,7 +466,7 @@
|
||||
"mask = user_keys.encode_base64_str(ciphered_mask)"
|
||||
],
|
||||
"outputs": [],
|
||||
"execution_count": 101
|
||||
"execution_count": 28
|
||||
},
|
||||
{
|
||||
"metadata": {},
|
||||
@@ -448,8 +483,8 @@
|
||||
{
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2024-08-01T19:17:16.378573Z",
|
||||
"start_time": "2024-08-01T19:17:16.072571Z"
|
||||
"end_time": "2024-08-05T17:52:34.104235Z",
|
||||
"start_time": "2024-08-05T17:52:33.794884Z"
|
||||
}
|
||||
},
|
||||
"cell_type": "code",
|
||||
@@ -473,13 +508,13 @@
|
||||
"code = hashed_data.decode(\"utf-8\")"
|
||||
],
|
||||
"outputs": [],
|
||||
"execution_count": 102
|
||||
"execution_count": 29
|
||||
},
|
||||
{
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2024-08-01T19:17:16.381295Z",
|
||||
"start_time": "2024-08-01T19:17:16.379384Z"
|
||||
"end_time": "2024-08-05T17:52:34.205433Z",
|
||||
"start_time": "2024-08-05T17:52:34.203278Z"
|
||||
}
|
||||
},
|
||||
"cell_type": "code",
|
||||
@@ -492,7 +527,7 @@
|
||||
")"
|
||||
],
|
||||
"outputs": [],
|
||||
"execution_count": 103
|
||||
"execution_count": 30
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
@@ -518,8 +553,8 @@
|
||||
"metadata": {
|
||||
"collapsed": false,
|
||||
"ExecuteTime": {
|
||||
"end_time": "2024-08-01T19:17:16.687966Z",
|
||||
"start_time": "2024-08-01T19:17:16.382136Z"
|
||||
"end_time": "2024-08-05T17:52:38.297363Z",
|
||||
"start_time": "2024-08-05T17:52:37.990052Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
@@ -528,17 +563,17 @@
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Keypad View\n",
|
||||
"Key 0: [0, 7, 20, 3, 10, 29]\n",
|
||||
"Key 1: [6, 25, 26, 15, 4, 17]\n",
|
||||
"Key 2: [12, 19, 14, 21, 28, 23]\n",
|
||||
"Key 3: [18, 1, 2, 9, 16, 11]\n",
|
||||
"Key 4: [24, 13, 8, 27, 22, 5]\n",
|
||||
"Selected Keys: [1, 2, 1, 2]\n",
|
||||
"Key 0: [6, 19, 14, 15, 4, 17]\n",
|
||||
"Key 1: [24, 13, 26, 3, 28, 23]\n",
|
||||
"Key 2: [0, 7, 2, 9, 16, 5]\n",
|
||||
"Key 3: [18, 1, 8, 27, 22, 11]\n",
|
||||
"Key 4: [12, 25, 20, 21, 10, 29]\n",
|
||||
"Selected Keys: [4, 1, 0, 4]\n",
|
||||
"True\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"execution_count": 104
|
||||
"execution_count": 31
|
||||
},
|
||||
{
|
||||
"metadata": {},
|
||||
@@ -570,13 +605,14 @@
|
||||
{
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2024-08-01T19:17:16.691445Z",
|
||||
"start_time": "2024-08-01T19:17:16.688722Z"
|
||||
"end_time": "2024-08-05T17:59:58.753205Z",
|
||||
"start_time": "2024-08-05T17:59:58.749714Z"
|
||||
}
|
||||
},
|
||||
"cell_type": "code",
|
||||
"source": [
|
||||
"user = customer.users[username]\n",
|
||||
"set_vals = customer.attributes.set_vals\n",
|
||||
"user_keys = user.user_keys\n",
|
||||
"user_mask = user.enciphered_passcode.mask\n",
|
||||
"decoded_mask = user_keys.decode_base64_str(user_mask)\n",
|
||||
@@ -593,11 +629,11 @@
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"[36659, 54746, 56159, 38654]\n"
|
||||
"[39232, 59621, 23817, 41463]\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"execution_count": 105
|
||||
"execution_count": 38
|
||||
},
|
||||
{
|
||||
"metadata": {},
|
||||
@@ -607,8 +643,8 @@
|
||||
{
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2024-08-01T19:17:16.694718Z",
|
||||
"start_time": "2024-08-01T19:17:16.692225Z"
|
||||
"end_time": "2024-08-05T17:54:03.252644Z",
|
||||
"start_time": "2024-08-05T17:54:03.249271Z"
|
||||
}
|
||||
},
|
||||
"cell_type": "code",
|
||||
@@ -633,7 +669,7 @@
|
||||
]
|
||||
}
|
||||
],
|
||||
"execution_count": 106
|
||||
"execution_count": 35
|
||||
},
|
||||
{
|
||||
"metadata": {},
|
||||
@@ -641,34 +677,21 @@
|
||||
"source": "### Compare Enciphered Passcodes"
|
||||
},
|
||||
{
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2024-08-01T19:17:17.000271Z",
|
||||
"start_time": "2024-08-01T19:17:16.695443Z"
|
||||
}
|
||||
},
|
||||
"metadata": {},
|
||||
"cell_type": "code",
|
||||
"source": [
|
||||
"enciphered_nkode = user_keys.encipher_salt_hash_code(presumed_selected_attributes_idx, customer.attributes)\n",
|
||||
"\n",
|
||||
"print(enciphered_nkode == user.enciphered_passcode.code)\n"
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"True\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"execution_count": 107
|
||||
"outputs": [],
|
||||
"execution_count": null
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"#### Renew Keys\n",
|
||||
"1. Renew Customer Keys\n",
|
||||
"## Renew Attributes \n",
|
||||
"1. Renew Customer Attributes \n",
|
||||
"2. Renew User Keys\n",
|
||||
"3. Refresh User on Login\n",
|
||||
"\n"
|
||||
@@ -678,12 +701,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2024-08-01T19:17:18.107245Z",
|
||||
"start_time": "2024-08-01T19:17:17.001318Z"
|
||||
}
|
||||
},
|
||||
"metadata": {},
|
||||
"cell_type": "code",
|
||||
"source": [
|
||||
"def print_user_enciphered_code():\n",
|
||||
@@ -692,7 +710,7 @@
|
||||
" print(f\"mask: {mask}, code: {code}\")\n",
|
||||
"\n",
|
||||
"print_user_enciphered_code() \n",
|
||||
"api.renew_keys(customer_id)\n",
|
||||
"api.renew_attributes(customer_id)\n",
|
||||
"print_user_enciphered_code()\n",
|
||||
"\n",
|
||||
"login_interface = api.get_login_interface(username, customer_id)\n",
|
||||
@@ -701,19 +719,8 @@
|
||||
"print(success)\n",
|
||||
"print_user_enciphered_code()"
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"mask: AH3tBMcj4vYN+WBQa4Wgwe3KDgE=, code: $2b$12$2w4nllgf0wnWMsdTYL4HNuxVN5A5AzqP5X2Xraj0ijKCAjM3kRlLm\n",
|
||||
"mask: AH3tBMcj4vYN+WBQa4Wgwe3KDgE=, code: $2b$12$2w4nllgf0wnWMsdTYL4HNuxVN5A5AzqP5X2Xraj0ijKCAjM3kRlLm\n",
|
||||
"True\n",
|
||||
"mask: pbB0tDKAFPtJUEQjyUZBdSCRsIc=, code: $2b$12$KW3WJQ2YNsbmyWJ6Rq32eed4/GJ6howBNsKA/sUhFOHRf.sIW2Pz6\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"execution_count": 108
|
||||
"outputs": [],
|
||||
"execution_count": null
|
||||
},
|
||||
{
|
||||
"metadata": {},
|
||||
@@ -725,12 +732,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2024-08-01T19:17:18.281874Z",
|
||||
"start_time": "2024-08-01T19:17:18.108020Z"
|
||||
}
|
||||
},
|
||||
"metadata": {},
|
||||
"cell_type": "code",
|
||||
"source": [
|
||||
"old_attrs = customer.attributes.attr_vals.copy()\n",
|
||||
@@ -740,7 +742,7 @@
|
||||
"new_sets = customer.attributes.set_vals"
|
||||
],
|
||||
"outputs": [],
|
||||
"execution_count": 109
|
||||
"execution_count": null
|
||||
},
|
||||
{
|
||||
"metadata": {},
|
||||
@@ -751,12 +753,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2024-08-01T19:17:18.285195Z",
|
||||
"start_time": "2024-08-01T19:17:18.282828Z"
|
||||
}
|
||||
},
|
||||
"metadata": {},
|
||||
"cell_type": "code",
|
||||
"source": [
|
||||
"attrs_xor = xor_lists(new_attrs, old_attrs)\n",
|
||||
@@ -767,7 +764,7 @@
|
||||
" user.user_keys.alpha_key = xor_lists(user.user_keys.alpha_key, attrs_xor)"
|
||||
],
|
||||
"outputs": [],
|
||||
"execution_count": 110
|
||||
"execution_count": null
|
||||
},
|
||||
{
|
||||
"metadata": {},
|
||||
@@ -775,12 +772,7 @@
|
||||
"source": "### Refresh User Keys"
|
||||
},
|
||||
{
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2024-08-01T19:17:18.921478Z",
|
||||
"start_time": "2024-08-01T19:17:18.286363Z"
|
||||
}
|
||||
},
|
||||
"metadata": {},
|
||||
"cell_type": "code",
|
||||
"source": [
|
||||
"user.user_keys = UserCipherKeys.new(\n",
|
||||
@@ -792,7 +784,7 @@
|
||||
"user.renew = False"
|
||||
],
|
||||
"outputs": [],
|
||||
"execution_count": 111
|
||||
"execution_count": null
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
|
||||
216
render_markdown.py
Normal file
216
render_markdown.py
Normal file
@@ -0,0 +1,216 @@
|
||||
from jinja2 import Environment, FileSystemLoader
|
||||
import os
|
||||
from nkode_api import NKodeAPI
|
||||
from src.models import NKodePolicy, KeypadSize, EncipheredNKode
|
||||
from src.user_cipher_keys import UserCipherKeys
|
||||
from src.utils import list_to_matrix, matrix_transpose, xor_lists
|
||||
from secrets import choice
|
||||
from string import ascii_lowercase
|
||||
import bcrypt
|
||||
import hashlib
|
||||
import base64
|
||||
from src.utils import int_array_to_bytes
|
||||
|
||||
|
||||
def random_username() -> str:
|
||||
return "test_username" + "".join([choice(ascii_lowercase) for _ in range(6)])
|
||||
|
||||
|
||||
def select_keys_with_passcode_values(user_passcode: list[int], interface: list[int], attrs_per_key: int) -> list[int]:
|
||||
return [interface.index(attr) // attrs_per_key for attr in user_passcode]
|
||||
|
||||
|
||||
def keypad_view(interface: list[int], attrs_per_key: int):
|
||||
print("Keypad View")
|
||||
interface_keypad = list_to_matrix(interface, attrs_per_key)
|
||||
for idx, key_vals in enumerate(interface_keypad):
|
||||
print(f"Key {idx}: {key_vals}")
|
||||
|
||||
|
||||
def render_nkode_authentication(data: dict):
|
||||
# Set up the Jinja2 environment and template loader
|
||||
file_loader = FileSystemLoader('./docs')
|
||||
env = Environment(loader=file_loader)
|
||||
|
||||
# Load the template
|
||||
template = env.get_template('nkode_authentication_template.md')
|
||||
|
||||
print(os.getcwd())
|
||||
# Render the template with the data
|
||||
output = template.render(data)
|
||||
|
||||
# Print or save the output
|
||||
output_file = "/Users/donov/Desktop/NKode_documentation/nkode/docs/nkode_authentication.md"
|
||||
with open(output_file, 'w') as fp:
|
||||
fp.write(output)
|
||||
print("File written successfully")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
api = NKodeAPI()
|
||||
|
||||
policy = NKodePolicy(
|
||||
max_nkode_len=10,
|
||||
min_nkode_len=4,
|
||||
distinct_sets=0,
|
||||
distinct_attributes=4,
|
||||
byte_len=2,
|
||||
)
|
||||
keypad_size = KeypadSize(
|
||||
numb_of_keys=5,
|
||||
attrs_per_key=6 # aka number of sets
|
||||
)
|
||||
customer_id = api.create_new_customer(keypad_size, policy)
|
||||
customer = api.customers[customer_id]
|
||||
|
||||
set_vals = customer.attributes.set_vals
|
||||
attr_vals = customer.attributes.attr_vals
|
||||
customer_attr_view = list_to_matrix(attr_vals, keypad_size.attrs_per_key)
|
||||
|
||||
attr_keypad_view = list_to_matrix(attr_vals, keypad_size.attrs_per_key)
|
||||
attr_set_view = matrix_transpose(attr_keypad_view)
|
||||
set_attribute_dict = dict(zip(set_vals, attr_set_view))
|
||||
|
||||
session_id, signup_interface = api.generate_signup_interface(customer_id)
|
||||
signup_keypad = list_to_matrix(signup_interface, keypad_size.numb_of_keys)
|
||||
|
||||
username = random_username()
|
||||
passcode_len = 4
|
||||
user_passcode = signup_interface[:passcode_len]
|
||||
selected_keys_set = select_keys_with_passcode_values(user_passcode, signup_interface, keypad_size.numb_of_keys)
|
||||
server_side_attr = [customer.attributes.attr_vals[idx] for idx in user_passcode]
|
||||
|
||||
confirm_interface = api.set_nkode(username, customer_id, selected_keys_set, session_id)
|
||||
|
||||
confirm_keypad = list_to_matrix(confirm_interface, keypad_size.numb_of_keys)
|
||||
|
||||
selected_keys_confirm = select_keys_with_passcode_values(user_passcode, confirm_interface, keypad_size.numb_of_keys)
|
||||
|
||||
success = api.confirm_nkode(username, customer_id, selected_keys_confirm, session_id)
|
||||
assert success
|
||||
passcode_server_attr = [customer.attributes.attr_vals[idx] for idx in user_passcode]
|
||||
passcode_server_set = [customer.attributes.get_attr_set_val(attr) for attr in passcode_server_attr]
|
||||
|
||||
user_keys = customer.users[username].user_keys
|
||||
|
||||
padded_passcode_server_set = user_keys.pad_user_mask(passcode_server_set, customer.attributes.set_vals)
|
||||
|
||||
set_idx = [customer.attributes.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]
|
||||
ciphered_mask = xor_lists(mask_set_keys, padded_passcode_server_set)
|
||||
ciphered_mask = xor_lists(ciphered_mask, user_keys.mask_key)
|
||||
mask = user_keys.encode_base64_str(ciphered_mask)
|
||||
|
||||
ciphered_customer_attrs = xor_lists(customer.attributes.attr_vals, user_keys.alpha_key)
|
||||
passcode_ciphered_attrs = [ciphered_customer_attrs[idx] for idx in user_passcode]
|
||||
pad_len = customer.nkode_policy.max_nkode_len - passcode_len
|
||||
|
||||
passcode_ciphered_attrs.extend([0 for _ in range(pad_len)])
|
||||
|
||||
ciphered_code = xor_lists(passcode_ciphered_attrs, user_keys.pass_key)
|
||||
|
||||
passcode_bytes = int_array_to_bytes(ciphered_code)
|
||||
passcode_digest = base64.b64encode(hashlib.sha256(passcode_bytes).digest())
|
||||
hashed_data = bcrypt.hashpw(passcode_digest, user_keys.salt)
|
||||
code = hashed_data.decode("utf-8")
|
||||
|
||||
enciphered_nkode = EncipheredNKode(
|
||||
mask=mask,
|
||||
code=code,
|
||||
)
|
||||
"""
|
||||
USER LOGIN
|
||||
"""
|
||||
login_interface = api.get_login_interface(username, customer_id)
|
||||
login_keypad = list_to_matrix(login_interface, keypad_size.attrs_per_key)
|
||||
selected_keys_login = select_keys_with_passcode_values(user_passcode, login_interface, keypad_size.attrs_per_key)
|
||||
success = api.login(customer_id, username, selected_keys_login)
|
||||
assert success
|
||||
|
||||
"""
|
||||
VALIDATE LOGIN KEY ENTRY
|
||||
DECIPHER MASK
|
||||
"""
|
||||
|
||||
user = customer.users[username]
|
||||
set_vals = customer.attributes.set_vals
|
||||
user_keys = user.user_keys
|
||||
user_mask = user.enciphered_passcode.mask
|
||||
decoded_mask = user_keys.decode_base64_str(user_mask)
|
||||
deciphered_mask = xor_lists(decoded_mask, user_keys.mask_key)
|
||||
set_key_rand_component = xor_lists(set_vals, user_keys.set_key)
|
||||
login_passcode_sets = []
|
||||
for set_cipher in deciphered_mask[:passcode_len]:
|
||||
set_idx = set_key_rand_component.index(set_cipher)
|
||||
login_passcode_sets.append(set_vals[set_idx])
|
||||
|
||||
"""
|
||||
GET PRESUMED ATTRIBUTES
|
||||
"""
|
||||
|
||||
set_vals_idx = [customer.attributes.get_set_index(set_val) for set_val in login_passcode_sets]
|
||||
|
||||
presumed_selected_attributes_idx = []
|
||||
for idx in range(passcode_len):
|
||||
key_numb = selected_keys_login[idx]
|
||||
set_idx = set_vals_idx[idx]
|
||||
selected_attr_idx = customer.users[username].user_interface.get_attr_idx_by_keynumb_setidx(key_numb, set_idx)
|
||||
presumed_selected_attributes_idx.append(selected_attr_idx)
|
||||
|
||||
"""
|
||||
RENEW KEYS
|
||||
"""
|
||||
|
||||
old_attrs = customer.attributes.attr_vals.copy()
|
||||
old_sets = customer.attributes.set_vals.copy()
|
||||
customer.attributes.renew()
|
||||
new_attrs = customer.attributes.attr_vals
|
||||
new_sets = customer.attributes.set_vals
|
||||
customer_new_attr_view = list_to_matrix(new_attrs, keypad_size.attrs_per_key)
|
||||
|
||||
"""
|
||||
RENEW USER
|
||||
"""
|
||||
attrs_xor = xor_lists(new_attrs, old_attrs)
|
||||
sets_xor = xor_lists(new_sets, old_sets)
|
||||
for user in customer.users.values():
|
||||
user.renew = True
|
||||
user.user_keys.set_key = xor_lists(user.user_keys.set_key, sets_xor)
|
||||
user.user_keys.alpha_key = xor_lists(user.user_keys.alpha_key, attrs_xor)
|
||||
|
||||
"""
|
||||
REFRESH USER KEYS
|
||||
"""
|
||||
user.user_keys = UserCipherKeys.new(
|
||||
customer.attributes.keypad_size,
|
||||
customer.attributes.set_vals,
|
||||
user.user_keys.max_nkode_len
|
||||
)
|
||||
user.enciphered_passcode = user.user_keys.encipher_nkode(presumed_selected_attributes_idx, customer.attributes)
|
||||
user.renew = False
|
||||
|
||||
# Define some data to pass to the template
|
||||
data = {
|
||||
'customer_set_vals': set_vals,
|
||||
'customer_attr_view': customer_attr_view,
|
||||
'set_attribute_dict': set_attribute_dict,
|
||||
'signup_keypad': signup_keypad,
|
||||
'username': 'test_user',
|
||||
'user_passcode': user_passcode,
|
||||
'selected_keys_set': selected_keys_set,
|
||||
'server_side_attr': server_side_attr,
|
||||
'confirm_keypad': confirm_keypad,
|
||||
'selected_keys_confirm': selected_keys_confirm,
|
||||
'user_keys': user_keys,
|
||||
'passcode_server_attr': passcode_server_attr,
|
||||
'passcode_server_set': passcode_server_set,
|
||||
'enciphered_nkode': enciphered_nkode,
|
||||
'login_keypad': login_keypad,
|
||||
'selected_login_keys': selected_keys_login,
|
||||
'login_passcode_sets': login_passcode_sets,
|
||||
'presumed_selected_attributes_idx': presumed_selected_attributes_idx,
|
||||
'customer_new_attr_view': customer_new_attr_view,
|
||||
'customer_new_set_vals': new_sets,
|
||||
|
||||
}
|
||||
render_nkode_authentication(data)
|
||||
@@ -38,7 +38,7 @@ def test_create_new_user_and_renew_keys(nkode_api, keypad_size, passocode_len):
|
||||
successful_login = nkode_api.login(customer_id, username, login_key_selection)
|
||||
assert successful_login
|
||||
|
||||
successful_renew = nkode_api.renew_keys(customer_id)
|
||||
successful_renew = nkode_api.renew_attributes(customer_id)
|
||||
assert successful_renew
|
||||
|
||||
login_interface = nkode_api.get_login_interface(username, customer_id)
|
||||
|
||||
Reference in New Issue
Block a user