update documentation
This commit is contained in:
207
docs/encipher_decipher_renew_nkode_v2.md
Normal file
207
docs/encipher_decipher_renew_nkode_v2.md
Normal file
@@ -0,0 +1,207 @@
|
||||
# Encipher, Decipher and Renew nKode
|
||||
|
||||
## Tenant Policy
|
||||
- max nkode length: 10
|
||||
- number of keys: 6
|
||||
- properties per key: 9
|
||||
- total number of properties: 54
|
||||
|
||||
---
|
||||
|
||||
## Deterministic CSPRNG
|
||||
- AES-CTR DRBG
|
||||
- ChaCha20
|
||||
|
||||
## User Cipher Keys
|
||||
Derive keys in memory from PRNG above:
|
||||
- property key: [ 6890 54130 42240 40467 46502 31074 10598 63689 27697 54461 21116 31999
|
||||
10698 14870 50779 48637 29314 33075 52993 42014 2837 1935 34274 63380
|
||||
36021 26329 20788 39848 7335 2619 61516 61122 39878 32506 19151 6611
|
||||
2803 10730 53682 39987 11998 42378 6081 8624 34336 15222 35632 33233
|
||||
4072 53750 54671 63845 2770 43728]
|
||||
- passcode key: [10632 49355 48031 9925 15082 24190 5137 14304 24524 16141]
|
||||
- user position key: [45632 9012 27470 28203 15901 7554 16974 54240 53827]
|
||||
- mask key: [ 8177 54825 26281 51895 8940 16695 19756 63041 7376 54396]
|
||||
|
||||
---
|
||||
|
||||
## User Keypad
|
||||
- keypad example:<br/>
|
||||
- user passcode indices: [48 12 7 36]
|
||||
|
||||
---
|
||||
|
||||
## nKode Cipher
|
||||
|
||||
### Passcode Hash
|
||||
```mermaid
|
||||
block-beta
|
||||
columns 2
|
||||
prop["user_property_key\n[ 6890 54130 42240 40467 46502 31074 10598 63689 27697 54461 21116 31999
|
||||
10698 14870 50779 48637 29314 33075 52993 42014 2837 1935 34274 63380
|
||||
36021 26329 20788 39848 7335 2619 61516 61122 39878 32506 19151 6611
|
||||
2803 10730 53682 39987 11998 42378 6081 8624 34336 15222 35632 33233
|
||||
4072 53750 54671 63845 2770 43728]"]
|
||||
pass["user_passcode_indices\n[48 12 7 36]"]
|
||||
space:2
|
||||
sel(("select\nproperties")):2
|
||||
pass --> sel
|
||||
prop --> sel
|
||||
space:2
|
||||
passcode["user passcode properties:\n[ 4072 10698 63689 2803]"]:2
|
||||
sel --> passcode
|
||||
space:2
|
||||
pad["zero pad to\nmax nkode length: 10"]:2
|
||||
passcode -->pad
|
||||
space:2
|
||||
paddedpasscode["padded passcode:\n[ 4072 10698 63689 2803 0 0 0 0 0 0]"]
|
||||
pad --> paddedpasscode
|
||||
passkey["passcode key:\n[10632 49355 48031 9925 15082 24190 5137 14304 24524 16141]"]
|
||||
space:2
|
||||
xor2(("XOR")):2
|
||||
passkey --> xor2
|
||||
paddedpasscode --> xor2
|
||||
space:2
|
||||
cipheredpass["ciphered passcode:\n[ 9824 59649 17238 11318 15082 24190 5137 14304 24524 16141]"]:2
|
||||
xor2 --> cipheredpass
|
||||
space:2
|
||||
hash(("hash")):2
|
||||
cipheredpass --> hash
|
||||
space:2
|
||||
cipheredhashed["hashed ciphered passcode:\n$2b$12$XcXlcNKMyXQziv.kQWKngO88KUcm.xrn4YRZOOhGgIyMmpMw7NPJa"]:2
|
||||
hash --> cipheredhashed
|
||||
```
|
||||
|
||||
### Mask Encipher
|
||||
```mermaid
|
||||
block-beta
|
||||
columns 2
|
||||
passcode_idx["passcode indices:\n[48 12 7 36]"]
|
||||
|
||||
space:3
|
||||
propidx(["Get Position Idx:\nmap each to element mod props_per_key"])
|
||||
passcode_idx-->propidx
|
||||
space:3
|
||||
passcode_position_idx["passcode poition indices:\n[3, 3, 7, 0]"]
|
||||
propidx --> passcode_position_idx
|
||||
|
||||
space:3
|
||||
pad1(("Pad with\nrandom indices"))
|
||||
passcode_position_idx --> pad1
|
||||
|
||||
space:3
|
||||
posidx["Padded Passcode Position Indices:\n[3, 3, 7, 0, 0, 0, 5, 8, 8, 8]"]
|
||||
pad1 --> posidx
|
||||
user_pos["user position key:\n[45632 9012 27470 28203 15901 7554 16974 54240 53827]"]
|
||||
|
||||
space:2
|
||||
sel(("select positions"))
|
||||
user_pos --> sel
|
||||
posidx --> sel
|
||||
space:3
|
||||
passcode_pos["ordered user passcode positions:\n[28203 28203 54240 45632 45632 45632 7554 53827 53827 53827]"]
|
||||
sel --> passcode_pos
|
||||
mask_key["mask key\n[ 8177 54825 26281 51895 8940 16695 19756 63041 7376 54396]"]
|
||||
space:2
|
||||
xor2(("XOR"))
|
||||
mask_key --> xor2
|
||||
passcode_pos --> xor2
|
||||
space:3
|
||||
mask["enciphered mask:\n cdq4ArVJePcB2PN3D2LrwyLN6mE="]
|
||||
xor2 --> mask
|
||||
```
|
||||
|
||||
### Validate nKode
|
||||
|
||||
```mermaid
|
||||
block-beta
|
||||
columns 3
|
||||
selected_keys["keys selected by user during login:\n[1, 3, 1, 4]"]
|
||||
login_keypad["login keypad:\nKey 0: [ 9 28 2 39 49 32 42 34 44]
|
||||
Key 1: [ 0 1 20 48 40 50 51 7 35]
|
||||
Key 2: [18 19 47 21 13 14 24 25 8]
|
||||
Key 3: [27 10 11 12 4 5 6 16 17]
|
||||
Key 4: [36 37 38 3 22 23 33 43 53]
|
||||
Key 5: [45 46 29 30 31 41 15 52 26]
|
||||
"]
|
||||
space:4
|
||||
|
||||
selectkeys(("filter keys"))
|
||||
mask["enciphered mask:\n cdq4ArVJePcB2PN3D2LrwyLN6mE="]
|
||||
mask_key["mask key:\n[ 8177 54825 26281 51895 8940 16695 19756 63041 7376 54396]"]
|
||||
space:2
|
||||
|
||||
xor1(("XOR"))
|
||||
mask --> xor1
|
||||
mask_key --> xor1
|
||||
selected_keys --> selectkeys
|
||||
login_keypad --> selectkeys
|
||||
space:3
|
||||
|
||||
ordered_keys["ordered keys:\n[[ 0 1 20 48 40 50 51 7 35]
|
||||
[27 10 11 12 4 5 6 16 17]
|
||||
[ 0 1 20 48 40 50 51 7 35]
|
||||
[36 37 38 3 22 23 33 43 53]]"]
|
||||
user_position_key["user position key:\n[45632 9012 27470 28203 15901 7554 16974 54240 53827]"]
|
||||
passcode_pos["ordered user passcode positions:\n[28203 28203 54240 45632 45632 45632 7554 53827 53827 53827]"]
|
||||
selectkeys --> ordered_keys
|
||||
xor1 --> passcode_pos
|
||||
space:8
|
||||
|
||||
get_passcode_idxs(("recover passcode\nposition indices"))
|
||||
user_position_key --> get_passcode_idxs
|
||||
passcode_pos --> get_passcode_idxs
|
||||
space:8
|
||||
|
||||
passcode_pos_idxs["padded passcode position indices:\n[3, 3, 7, 0, 0, 0, 5, 8, 8, 8]"]
|
||||
get_passcode_idxs --> passcode_pos_idxs
|
||||
space:3
|
||||
|
||||
get_presumed_idxs(("recover passcode\nproperty indices"))
|
||||
ordered_keys --> get_presumed_idxs
|
||||
passcode_pos_idxs --> get_presumed_idxs
|
||||
space:5
|
||||
|
||||
passcode_prop_idxs["presumed passcode property indices:\n[48 12 7 36]"]
|
||||
prop["user_property_key\n[ 6890 54130 42240 40467 46502 31074 10598 63689 27697 54461 21116 31999
|
||||
10698 14870 50779 48637 29314 33075 52993 42014 2837 1935 34274 63380
|
||||
36021 26329 20788 39848 7335 2619 61516 61122 39878 32506 19151 6611
|
||||
2803 10730 53682 39987 11998 42378 6081 8624 34336 15222 35632 33233
|
||||
4072 53750 54671 63845 2770 43728]"]
|
||||
cipheredhashed["hashed ciphered passcode:\n$2b$12$XcXlcNKMyXQziv.kQWKngO88KUcm.xrn4YRZOOhGgIyMmpMw7NPJa"]
|
||||
get_presumed_idxs --> passcode_prop_idxs
|
||||
space:3
|
||||
|
||||
sel(("select\nproperties"))
|
||||
passcode_prop_idxs --> sel
|
||||
prop --> sel
|
||||
space:5
|
||||
|
||||
passcode_prop["presumed passcode properties:\n[ 4072 10698 63689 2803]"]
|
||||
sel --> passcode_prop
|
||||
space:5
|
||||
|
||||
cipher(("encipher"))
|
||||
passcode_prop --> cipher
|
||||
space:5
|
||||
|
||||
cipheredpass["ciphered passcode:\n[ 9824 59649 17238 11318 15082 24190 5137 14304 24524 16141]"]
|
||||
cipher --> cipheredpass
|
||||
space:7
|
||||
|
||||
|
||||
comp{"compare"}
|
||||
cipheredpass --> comp
|
||||
cipheredhashed --> comp
|
||||
space:5
|
||||
|
||||
suc(("success"))
|
||||
comp --"Equal"--> suc
|
||||
```
|
||||
|
||||
## Renew
|
||||
A renewal happens every login
|
||||
### Nonce Renew
|
||||
With ChaCha20, we can renew the keys and hash every login with a new nonce
|
||||
### Secret Renew
|
||||
The secret is renewed less frequently. It's stored securely using a service like AWS Secrets Manager.
|
||||
69
docs/scripts/render_encipher_decipher_diagrams_v2.py
Normal file
69
docs/scripts/render_encipher_decipher_diagrams_v2.py
Normal file
@@ -0,0 +1,69 @@
|
||||
from pathlib import Path
|
||||
import numpy as np
|
||||
from docs.scripts.utils import render_markdown_template
|
||||
from src.models import NKodePolicy, KeypadSize
|
||||
from src.user_keypad import UserKeypad
|
||||
from src.nkode_cipher_v2.nkode_cipher import NKodeCipher
|
||||
from src.utils import select_keys_with_passcode_values
|
||||
|
||||
|
||||
def display_keypad(icons_array: np.ndarray, props_per_key: int) -> str:
|
||||
icons = ""
|
||||
for idx, row in enumerate(icons_array.reshape(-1, props_per_key)):
|
||||
icons += f"Key {idx}: "
|
||||
icons += str(row)
|
||||
icons += "\n"
|
||||
return icons
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
policy = NKodePolicy(
|
||||
max_nkode_len=10,
|
||||
min_nkode_len=4,
|
||||
distinct_positions=0,
|
||||
distinct_properties=4,
|
||||
)
|
||||
keypad_size = KeypadSize(
|
||||
numb_of_keys=6,
|
||||
props_per_key=9
|
||||
)
|
||||
user_keys = NKodeCipher.create(keypad_size=keypad_size, max_nkode_len=policy.max_nkode_len)
|
||||
passcode_len = 4
|
||||
|
||||
passcode_property_indices = np.random.choice([i for i in range(keypad_size.total_props)], size=passcode_len,
|
||||
replace=False)
|
||||
user_passcode = user_keys.property_key[passcode_property_indices]
|
||||
pad_len = policy.max_nkode_len - passcode_len
|
||||
padded_passcode = np.concatenate((user_passcode, np.zeros(pad_len, dtype=user_passcode.dtype)))
|
||||
ciphered_passcode = padded_passcode ^ user_keys.pass_key
|
||||
cipher = user_keys.encipher_nkode(passcode_property_indices.tolist())
|
||||
padded_passcode_position_indices = user_keys.get_passcode_position_indices_padded(
|
||||
passcode_property_indices.tolist())
|
||||
|
||||
ordered_user_position_key = user_keys.position_key[padded_passcode_position_indices]
|
||||
login_keypad = UserKeypad.create(keypad_size)
|
||||
selected_keys_login = select_keys_with_passcode_values(passcode_property_indices, login_keypad.keypad,
|
||||
keypad_size.props_per_key)
|
||||
context = {
|
||||
"max_nkode_len": policy.max_nkode_len,
|
||||
"numb_of_keys": keypad_size.numb_of_keys,
|
||||
"props_per_key": keypad_size.props_per_key,
|
||||
"user_property_key": user_keys.property_key,
|
||||
"pass_key": user_keys.pass_key,
|
||||
"user_position_key": user_keys.position_key,
|
||||
"mask_key": user_keys.mask_key,
|
||||
"user_passcode_idxs": passcode_property_indices,
|
||||
"user_passcode_props": user_passcode,
|
||||
"padded_passcode": padded_passcode,
|
||||
"ciphered_passcode": ciphered_passcode,
|
||||
"code": cipher.code,
|
||||
"passcode_position_idxs": padded_passcode_position_indices[:passcode_len],
|
||||
"pad_user_passcode_idxs": padded_passcode_position_indices,
|
||||
"ordered_user_position_key": ordered_user_position_key,
|
||||
"mask": cipher.mask,
|
||||
"login_keypad": display_keypad(login_keypad.keypad, keypad_size.props_per_key),
|
||||
"selected_keys": selected_keys_login,
|
||||
"ordered_keys": login_keypad.keypad.reshape(-1, keypad_size.props_per_key)[selected_keys_login],
|
||||
}
|
||||
render_markdown_template(Path("../templates/encipher_decipher_renew_nkode_v2.template.md"),
|
||||
Path("../encipher_decipher_renew_nkode_v2.md"), context)
|
||||
70
docs/scripts/render_zero_trust_nkode.py
Normal file
70
docs/scripts/render_zero_trust_nkode.py
Normal file
@@ -0,0 +1,70 @@
|
||||
from pathlib import Path
|
||||
import numpy as np
|
||||
from docs.scripts.utils import render_markdown_template
|
||||
from src.models import NKodePolicy, KeypadSize
|
||||
from src.user_keypad import UserKeypad
|
||||
from src.nkode_cipher_v2.nkode_cipher import NKodeCipher
|
||||
from src.utils import select_keys_with_passcode_values
|
||||
|
||||
|
||||
def display_keypad(icons_array: np.ndarray, props_per_key: int) -> str:
|
||||
icons = ""
|
||||
for idx, row in enumerate(icons_array.reshape(-1, props_per_key)):
|
||||
icons += f"Key {idx}: "
|
||||
icons += str(row)
|
||||
icons += "\n"
|
||||
return icons
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
policy = NKodePolicy(
|
||||
max_nkode_len=10,
|
||||
min_nkode_len=4,
|
||||
distinct_positions=0,
|
||||
distinct_properties=4,
|
||||
)
|
||||
keypad_size = KeypadSize(
|
||||
numb_of_keys=6,
|
||||
props_per_key=9
|
||||
)
|
||||
user_keys = NKodeCipher.create(keypad_size=keypad_size, max_nkode_len=policy.max_nkode_len)
|
||||
passcode_len = 4
|
||||
|
||||
passcode_property_indices = np.random.choice([i for i in range(keypad_size.total_props)], size=passcode_len,
|
||||
replace=False)
|
||||
user_passcode = user_keys.property_key[passcode_property_indices]
|
||||
pad_len = policy.max_nkode_len - passcode_len
|
||||
padded_passcode = np.concatenate((user_passcode, np.zeros(pad_len, dtype=user_passcode.dtype)))
|
||||
ciphered_passcode = padded_passcode ^ user_keys.pass_key
|
||||
cipher = user_keys.encipher_nkode(passcode_property_indices.tolist())
|
||||
padded_passcode_position_indices = user_keys.get_passcode_position_indices_padded(
|
||||
passcode_property_indices.tolist())
|
||||
|
||||
ordered_user_position_key = user_keys.position_key[padded_passcode_position_indices]
|
||||
login_keypad = UserKeypad.create(keypad_size)
|
||||
selected_keys_login = select_keys_with_passcode_values(passcode_property_indices, login_keypad.keypad,
|
||||
keypad_size.props_per_key)
|
||||
context = {
|
||||
"max_nkode_len": policy.max_nkode_len,
|
||||
"numb_of_keys": keypad_size.numb_of_keys,
|
||||
"props_per_key": keypad_size.props_per_key,
|
||||
"user_property_key": user_keys.property_key,
|
||||
"pass_key": user_keys.pass_key,
|
||||
"user_position_key": user_keys.position_key,
|
||||
"mask_key": user_keys.mask_key,
|
||||
"user_passcode_idxs": passcode_property_indices,
|
||||
"user_passcode_props": user_passcode,
|
||||
"padded_passcode": padded_passcode,
|
||||
"ciphered_passcode": ciphered_passcode,
|
||||
"code": cipher.code,
|
||||
"passcode_position_idxs": padded_passcode_position_indices[:passcode_len],
|
||||
"pad_user_passcode_idxs": padded_passcode_position_indices,
|
||||
"ordered_user_position_key": ordered_user_position_key,
|
||||
"mask": cipher.mask,
|
||||
"login_keypad": display_keypad(login_keypad.keypad, keypad_size.props_per_key),
|
||||
"selected_keys": selected_keys_login,
|
||||
"ordered_keys": login_keypad.keypad.reshape(-1, keypad_size.props_per_key)[selected_keys_login],
|
||||
}
|
||||
|
||||
render_markdown_template(Path("../templates/zero_trust_nkode.template.md"),
|
||||
Path("../zero_trust_nkode.md"), context)
|
||||
187
docs/templates/encipher_decipher_renew_nkode_v2.template.md
vendored
Normal file
187
docs/templates/encipher_decipher_renew_nkode_v2.template.md
vendored
Normal file
@@ -0,0 +1,187 @@
|
||||
# Encipher, Decipher and Renew nKode
|
||||
|
||||
## Tenant Policy
|
||||
- max nkode length: {{ max_nkode_len }}
|
||||
- number of keys: {{ numb_of_keys }}
|
||||
- properties per key: {{ props_per_key }}
|
||||
- total number of properties: {{ numb_of_keys * props_per_key }}
|
||||
|
||||
---
|
||||
|
||||
## Deterministic CSPRNG
|
||||
- AES-CTR DRBG
|
||||
- ChaCha20
|
||||
|
||||
## User Cipher Keys
|
||||
Derive keys in memory from PRNG above:
|
||||
- property key: {{ user_property_key }}
|
||||
- passcode key: {{ pass_key }}
|
||||
- user position key: {{ user_position_key }}
|
||||
- mask key: {{ mask_key }}
|
||||
|
||||
---
|
||||
|
||||
## User Keypad
|
||||
- keypad example:<br/>{{ login_keypad_md }}
|
||||
- user passcode indices: {{ user_passcode_idxs}}
|
||||
|
||||
---
|
||||
|
||||
## nKode Cipher
|
||||
|
||||
### Passcode Hash
|
||||
```mermaid
|
||||
block-beta
|
||||
columns 2
|
||||
prop["user_property_key\n{{user_property_key}}"]
|
||||
pass["user_passcode_indices\n{{user_passcode_idxs}}"]
|
||||
space:2
|
||||
sel(("select\nproperties")):2
|
||||
pass --> sel
|
||||
prop --> sel
|
||||
space:2
|
||||
passcode["user passcode properties:\n{{user_passcode_props}}"]:2
|
||||
sel --> passcode
|
||||
space:2
|
||||
pad["zero pad to\nmax nkode length: {{max_nkode_len}}"]:2
|
||||
passcode -->pad
|
||||
space:2
|
||||
paddedpasscode["padded passcode:\n{{padded_passcode}}"]
|
||||
pad --> paddedpasscode
|
||||
passkey["passcode key:\n{{pass_key}}"]
|
||||
space:2
|
||||
xor2(("XOR")):2
|
||||
passkey --> xor2
|
||||
paddedpasscode --> xor2
|
||||
space:2
|
||||
cipheredpass["ciphered passcode:\n{{ciphered_passcode}}"]:2
|
||||
xor2 --> cipheredpass
|
||||
space:2
|
||||
hash(("hash")):2
|
||||
cipheredpass --> hash
|
||||
space:2
|
||||
cipheredhashed["hashed ciphered passcode:\n{{code}}"]:2
|
||||
hash --> cipheredhashed
|
||||
```
|
||||
|
||||
### Mask Encipher
|
||||
```mermaid
|
||||
block-beta
|
||||
columns 2
|
||||
passcode_idx["passcode indices:\n{{user_passcode_idxs}}"]
|
||||
|
||||
space:3
|
||||
propidx(["Get Position Idx:\nmap each to element mod props_per_key"])
|
||||
passcode_idx-->propidx
|
||||
space:3
|
||||
passcode_position_idx["passcode poition indices:\n{{passcode_position_idxs}}"]
|
||||
propidx --> passcode_position_idx
|
||||
|
||||
space:3
|
||||
pad1(("Pad with\nrandom indices"))
|
||||
passcode_position_idx --> pad1
|
||||
|
||||
space:3
|
||||
posidx["Padded Passcode Position Indices:\n{{pad_user_passcode_idxs}}"]
|
||||
pad1 --> posidx
|
||||
user_pos["user position key:\n{{user_position_key}}"]
|
||||
|
||||
space:2
|
||||
sel(("select positions"))
|
||||
user_pos --> sel
|
||||
posidx --> sel
|
||||
space:3
|
||||
passcode_pos["ordered user passcode positions:\n{{ordered_user_position_key}}"]
|
||||
sel --> passcode_pos
|
||||
mask_key["mask key\n{{mask_key}}"]
|
||||
space:2
|
||||
xor2(("XOR"))
|
||||
mask_key --> xor2
|
||||
passcode_pos --> xor2
|
||||
space:3
|
||||
mask["enciphered mask:\n {{mask}}"]
|
||||
xor2 --> mask
|
||||
```
|
||||
|
||||
### Validate nKode
|
||||
|
||||
```mermaid
|
||||
block-beta
|
||||
columns 3
|
||||
selected_keys["keys selected by user during login:\n{{selected_keys}}"]
|
||||
login_keypad["login keypad:\n{{login_keypad}}"]
|
||||
space:4
|
||||
|
||||
selectkeys(("filter keys"))
|
||||
mask["enciphered mask:\n {{mask}}"]
|
||||
mask_key["mask key:\n{{mask_key}}"]
|
||||
space:2
|
||||
|
||||
xor1(("XOR"))
|
||||
mask --> xor1
|
||||
mask_key --> xor1
|
||||
selected_keys --> selectkeys
|
||||
login_keypad --> selectkeys
|
||||
space:3
|
||||
|
||||
ordered_keys["ordered keys:\n{{ordered_keys}}"]
|
||||
user_position_key["user position key:\n{{user_position_key}}"]
|
||||
passcode_pos["ordered user passcode positions:\n{{ordered_user_position_key}}"]
|
||||
selectkeys --> ordered_keys
|
||||
xor1 --> passcode_pos
|
||||
space:8
|
||||
|
||||
get_passcode_idxs(("recover passcode\nposition indices"))
|
||||
user_position_key --> get_passcode_idxs
|
||||
passcode_pos --> get_passcode_idxs
|
||||
space:8
|
||||
|
||||
passcode_pos_idxs["padded passcode position indices:\n{{pad_user_passcode_idxs}}"]
|
||||
get_passcode_idxs --> passcode_pos_idxs
|
||||
space:3
|
||||
|
||||
get_presumed_idxs(("recover passcode\nproperty indices"))
|
||||
ordered_keys --> get_presumed_idxs
|
||||
passcode_pos_idxs --> get_presumed_idxs
|
||||
space:5
|
||||
|
||||
passcode_prop_idxs["presumed passcode property indices:\n{{user_passcode_idxs}}"]
|
||||
prop["user_property_key\n{{user_property_key}}"]
|
||||
cipheredhashed["hashed ciphered passcode:\n{{code}}"]
|
||||
get_presumed_idxs --> passcode_prop_idxs
|
||||
space:3
|
||||
|
||||
sel(("select\nproperties"))
|
||||
passcode_prop_idxs --> sel
|
||||
prop --> sel
|
||||
space:5
|
||||
|
||||
passcode_prop["presumed passcode properties:\n{{user_passcode_props}}"]
|
||||
sel --> passcode_prop
|
||||
space:5
|
||||
|
||||
cipher(("encipher"))
|
||||
passcode_prop --> cipher
|
||||
space:5
|
||||
|
||||
cipheredpass["ciphered passcode:\n{{ciphered_passcode}}"]
|
||||
cipher --> cipheredpass
|
||||
space:7
|
||||
|
||||
|
||||
comp{"compare"}
|
||||
cipheredpass --> comp
|
||||
cipheredhashed --> comp
|
||||
space:5
|
||||
|
||||
suc(("success"))
|
||||
comp --"Equal"--> suc
|
||||
```
|
||||
|
||||
## Renew
|
||||
A renewal happens every login
|
||||
### Nonce Renew
|
||||
With ChaCha20, we can renew the keys and hash every login with a new nonce
|
||||
### Secret Renew
|
||||
The secret is renewed less frequently. It's stored securely using a service like AWS Secrets Manager.
|
||||
|
||||
43
docs/templates/zero_trust_nkode.template.md
vendored
Normal file
43
docs/templates/zero_trust_nkode.template.md
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
# Zero Trust nKode with aPAKE (OPAQUE)
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Client
|
||||
participant Server
|
||||
Note over Client, Server: Enrollment
|
||||
Client ->> Server: Signup Session: email
|
||||
Client ->> Client: Create 128-bit Secret Key
|
||||
Note left of Client: Request user stores Secret Key in a safe place
|
||||
Client ->> Server: OPAQUE Register with Secret Key<br/>https://github.com/facebook/opaque-ke
|
||||
Client ->> Server: OPAQUE Login with email + Secret Key
|
||||
opt Secret Key OPAQUE tunnel
|
||||
Client ->> Server: Get New Icons
|
||||
Server -->> Client: icons
|
||||
Note left of Client: Icons are stored on Client
|
||||
Note left of Client: well-known nonce: 0x1 (or any number)
|
||||
Client ->> Client: Assign random names to icons from<br/>secret_key and well known nonce
|
||||
Client ->> Server: list of random icon names
|
||||
Note right of Server: Only a client with the secret key can request these icons.<br/>Server doesn't know the owner
|
||||
loop assign icons
|
||||
Client ->> Client: Regenerate 4-6 icons until user accepts them
|
||||
end
|
||||
|
||||
Client ->> Client: Create new nonce
|
||||
Client ->> Client: ChaCha20 key derivation (pass_key, mask_key, prop_key, pos_key)
|
||||
Client ->> Client: Compute Mask
|
||||
Note left of Client: User Password is concat([list of assigned icon values])
|
||||
Client ->> Server: OPAQUE Register with User Password + nonce, mask
|
||||
end
|
||||
Note over Client, Server: Login
|
||||
Client ->> Server: OPAQUE Login with email + Secret Key
|
||||
opt Secret Key OPAQUE tunnel
|
||||
Server ->> Client: nonce, mask
|
||||
Client ->> Client: Display Keypad to User<br/>User makes key selection
|
||||
Client ->> Client: recover user password
|
||||
Client ->> Server: OPAQUE Password Login
|
||||
end
|
||||
Note over Client, Server: User Session
|
||||
opt Secret Key PAKE Key XOR nKode PAKE Key tunnel
|
||||
Client ->> Server: all communication goes through this double PAKE
|
||||
end
|
||||
```
|
||||
Reference in New Issue
Block a user