finish jinja templating

This commit is contained in:
2024-08-07 12:22:17 -05:00
parent d33767b545
commit ab43296ec2
2 changed files with 47 additions and 48 deletions

View File

@@ -1,11 +1,10 @@
# 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.
Before creating a user, a customer generates random attributes and set
values. The customers manage users. They define an nKode policy, keypad's dimensions,
attributes/sets in the keypad, and the frequency of attribute renewal.
### nKode Policy and Keypad Size
An nKode policy defines:
<ul>
@@ -13,7 +12,7 @@ An nKode policy defines:
<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>
<li>the number of bytes in an attribute and set</li>
</ul>
The keypad size defines:
@@ -22,7 +21,8 @@ The keypad size defines:
<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.
To be [dispersion](nkode_concepts.md/#dispersion-resistant-interface) resistant, the number of attributes must be greater than the number of keys.
```
api = NKodeAPI()
@@ -35,8 +35,8 @@ policy = NKodePolicy(
)
keypad_size = KeypadSize(
numb_of_keys = 5,
attrs_per_key = 6 # aka number of sets
numb_of_keys = {{ keypad_size.numb_of_keys }},
attrs_per_key = {{ keypad_size.attrs_per_key }} # aka number of sets
)
customer_id = api.create_new_customer(keypad_size, policy)
@@ -44,8 +44,9 @@ 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.
Since our customer has {{ keypad_size.numb_of_keys }} keys and {{ keypad_size.attrs_per_key }} attributes per key,
this gives a customer interface of {{ keypad_size.numb_of_attrs }} distinct attributes and {{ keypad_size.attrs_per_key }} distinct attribute sets.
Each attribute belongs to one of the {{ keypad_size.attrs_per_key }} sets. Each attribute and set value is a unique 2-byte integer in this example.
```
set_vals = customer.attributes.set_vals
@@ -78,16 +79,18 @@ Set to Attribute Map:
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
2. The user sets their nKode and sends their selection to the server
3. The user confirms their nKode. If the user's nKode matches the policy, the server creates the user.
### 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.
The user's interface must be dispersable so the server can determine the user's nkode.
The server randomly drops attribute sets until
the number of attributes equals the number of keys, making the interface dispersable.
In our case, the server randomly drops {{ keypad_size.attrs_per_key - keypad_size.numb_of_keys }} attribute {{ "sets" if keypad_size.attrs_per_key - keypad_size.numb_of_keys > 1 else "set" }}.
to give us a {{ keypad_size.numb_of_keys }} X {{ keypad_size.numb_of_keys }} keypad with possible index values ranging from 0-{{ keypad_size.numb_of_attrs - 1 }}.
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.
The user never learns what their "real" attribute is. They do not see the index value representing their nKode or
the customer server-side value.
```
session_id, signup_interface = api.generate_index_interface(customer_id)
signup_interface_keypad = list_to_matrix(signup_interface, keypad_size.attrs_per_key)
@@ -100,9 +103,10 @@ Key {{ loop.index }}: {{ key }}
### 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.
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 be associated with the same index every time the user logs in.
If users want to change anything about their interface, they must also change their nkode.
```
username = {{ username }}
user_passcode = {{ user_passcode }}
@@ -120,8 +124,9 @@ 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 submits the set interface to the server and receives 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)
@@ -135,22 +140,22 @@ Selected Keys:
{{ selected_keys_confirm }}
```
The user submits their confirm key selection and the user is created
The user submits their confirmation 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:
When a new user creates an nKode, the server caches its set and confirms the interface and the user's key selection.
On the last api.confirm_nkode, the server:
1. Deduces the users attributes
1. Deduces the user's 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
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
Steps 1-2 are straightforward. For a better idea of how they work, see pyNKode.
#### User Cipher Keys
@@ -181,7 +186,8 @@ user_keys = UserCipherKeys(
)
```
The method UserCipherKeys.encipher_nkode secures a users nKode in the database. This method is called in api.confirm_nkode
The method UserCipherKeys.encipher_nkode secures a user's nKode in the database. This method is called in api.confirm_nkode
```
class EncipheredNKode(BaseModel):
code: str
@@ -204,7 +210,6 @@ Recall:
```
# 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]
@@ -214,20 +219,14 @@ 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 }}
```
@@ -281,7 +280,7 @@ 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
- encipher, salt, and hash presumed attribute values and compare them to the users hashed code
#### Decipher Mask
Recall:
@@ -328,23 +327,22 @@ 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.
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:
The renew attributes process 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.
When the customer calls the `renew_attributes` method, the method replaces the customer's attributes and set values. All its users go through an intermediate
renewal step. The users fully renew after their first successful login. This first login refreshes their keys, salt, and hash with new values.
### Customer Renew
Old Customer attributes and set values are cached copied to variables before they are renewed.
Old Customer attributes and set values are cached and copied to variables before renewal.
```
old_sets = customer.attributes.set_vals
@@ -360,7 +358,7 @@ Customer Attributes:
{% endfor %}
```
After the renew, the customer attributes and sets are new randomly generated values.
After the renewal, the customer attributes and sets are new randomly generated values.
```
api.renew_attributes(customer_id)
@@ -379,7 +377,7 @@ Customer Attributes:
```
### Renew User
During the renew, each user goes through a temporary transition period.
During the renewal, each user goes through a temporary transition period.
```
attrs_xor = xor_lists(new_attrs, old_attrs)
sets_xor = xor_lists(new_sets, old_sets)
@@ -392,17 +390,17 @@ for user in customer.users.values():
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:
Since the customer_attr is now the new value, it gets canceled 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
Using the new customer attributes, we can validate the user's login attempt with the same hash.
##### 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
The `old_set_vals` have been replaced with the new `new_set_vals`. The deciphering process described above
remains the same.
### User Refresh