diff --git a/docs/encipher_decipher_nkode.md b/docs/encipher_decipher_nkode.md new file mode 100644 index 0000000..08c5808 --- /dev/null +++ b/docs/encipher_decipher_nkode.md @@ -0,0 +1,152 @@ +# Encipher and Decipher nKode + +### Customer Policy +- max nkode length: 10 +- number of keys: 6 +- properties per key: 9 +- total number of properties: 54 + +### Customer Cipher +- property key: [50817 32783 33745 35836 30092 4212 15938 64571 58354 41241 3649 38852 + 37860 47294 10501 43278 9946 60484 34443 38446 57997 32874 49251 58321 + 15849 40891 43566 53732 31357 5248 22060 15762 23773 10428 22850 7975 + 11108 23454 32723 40871 6994 35130 41638 13889 6569 20765 56191 37770 + 4448 37031 30452 43080 24525 44717] +- position key: [25392 13634 17753 25555 61290 50870 49934 53104 9796] + + +--- + +### User Cipher +- property key: [35724 37130 47630 20125 52673 62248 61979 44917 17470 11483 20317 56084 + 34699 49571 32249 15009 43246 57623 21032 62384 61961 34049 1963 5370 + 1121 47700 26633 59166 16526 38173 56846 41594 54438 8714 46049 25028 + 38681 2017 39749 42164 38277 19216 23760 35115 23020 18954 26604 50262 + 21588 62239 30226 58722 12644 39141] +- passcode key: [51522 14440 21036 1484 4829 51359 61560 41543 23848 29080] +- combined position key: [14972 5803 54986 46940 19674 32943 38431 42194 29083] +- mask key: [15948 8251 52095 4511 25902 21701 15340 4458 15137 44295] + +#### Combined Postion Key +```mermaid +block-beta + columns 2 + user_pos["user position key:\n[22860 9193 37779 54415 41904 17945 21777 27554 22495]"] + customer_pos["customer position key:\n[25392 13634 17753 25555 61290 50870 49934 53104 9796]"] + space:2 + xor(("XOR")):2 + user_pos --> xor + customer_pos --> xor + space:2 + comb_pos["combined position key\n[14972 5803 54986 46940 19674 32943 38431 42194 29083]"]:2 + xor --> comb_pos +``` + +### User Keypad +- keypad: +- user passcode indices: [22, 6, 38, 21] + +### nKode Cipher + +#### Passcode Hash +```mermaid +block-beta +columns 2 + cprop["customer_property_key\n[50817 32783 33745 35836 30092 4212 15938 64571 58354 41241 3649 38852 + 37860 47294 10501 43278 9946 60484 34443 38446 57997 32874 49251 58321 + 15849 40891 43566 53732 31357 5248 22060 15762 23773 10428 22850 7975 + 11108 23454 32723 40871 6994 35130 41638 13889 6569 20765 56191 37770 + 4448 37031 30452 43080 24525 44717]"] + uprop["user_property_key\n[35724 37130 47630 20125 52673 62248 61979 44917 17470 11483 20317 56084 + 34699 49571 32249 15009 43246 57623 21032 62384 61961 34049 1963 5370 + 1121 47700 26633 59166 16526 38173 56846 41594 54438 8714 46049 25028 + 38681 2017 39749 42164 38277 19216 23760 35115 23020 18954 26604 50262 + 21588 62239 30226 58722 12644 39141]"] + space:2 + xor1(("XOR")):2 + cprop --> xor1 + uprop --> xor1 + space:2 + prop["combined_property_key\n[19725 4357 14815 50529 47181 58204 52313 21326 42956 36290 16668 19664 + 5231 31005 21756 37807 36404 3411 54435 26014 4228 1387 51144 63275 + 14728 9711 49703 14074 15091 33181 34850 40936 34939 2742 60067 32483 + 48253 23679 58518 15123 36567 49706 65142 49002 16453 6935 48275 22492 + 17716 25528 230 19754 28329 13896]"] + xor1 --> prop + pass["user_passcode_indices\n[22, 6, 38, 21]"] + space:2 + sel(("select\properties")):2 + pass --> sel + prop --> sel + space:2 + passcode["user passcode properties:\n[51144 52313 58518 1387]"]:2 + sel --> passcode + space:2 + pad["zero pad to\nmax nkode length: 10"]:2 + passcode -->pad + space:2 + paddedpasscode["padded passcode:\n[51144 52313 58518 1387 0 0 0 0 0 0]"] + pad --> paddedpasscode + passkey["passcode key:\n[51522 14440 21036 1484 4829 51359 61560 41543 23848 29080]"] + space:2 + xor2(("XOR")):2 + passkey --> xor2 + paddedpasscode --> xor2 + space:2 + cipheredpass["ciphered passcode:\n[ 3722 62513 46778 167 4829 51359 61560 41543 23848 29080]"]:2 + xor2 --> cipheredpass + space:2 + hash(("hash")):2 + cipheredpass --> hash + space:2 + cipheredhashed["hashed ciphered passcode:\n$2b$12$AQRZP88momhTaKGYaPzdiuBybg7V49SiZ8y9PQMoT0plZrEsbYO.K"]:2 + hash --> cipheredhashed +``` + +#### Mask Encipher +```mermaid +block-beta + columns 3 + passcode_idx["passcode indices:\n[22, 6, 38, 21]"] + comb_pos["combined position key:\n[14972 5803 54986 46940 19674 32943 38431 42194 29083]"] + cust_pos["customer position key:\n[25392 13634 17753 25555 61290 50870 49934 53104 9796]"] + + space:3 + propidx(["Get Position Idx:\nmap each to element mod props_per_key"]) + passcode_idx-->propidx + space:1 + xor1(("XOR")) + comb_pos --> xor1 + cust_pos --> xor1 + + space:3 + passcode_position_idx["passcode poition indices:\n[4, 6, 2, 3]"] + propidx --> passcode_position_idx + + space:5 + pad1(("Pad with\nrandom indices")) + passcode_position_idx --> pad1 + + space:5 + posidx["Padded Passcode Position Indices:\n[4, 6, 2, 3, 7, 1, 8, 0, 5, 4]"] + pad1 --> posidx + space:1 + user_pos["user position key:\n[22860 9193 37779 54415 41904 17945 21777 27554 22495]"] + xor1 --> user_pos + + space:4 + sel(("select positions")) + user_pos --> sel + posidx --> sel + space:5 + passcode_pos["passcode positions:\n[41904 21777 37779 54415 27554 9193 22495 22860 17945 41904]"] + sel --> passcode_pos + mask_key["mask key\n[15948 8251 52095 4511 25902 21701 15340 4458 15137 44295]"] + space:4 + xor2(("XOR")) + mask_key --> xor2 + passcode_pos --> xor2 + space:5 + mask["enciphered mask:\n [40444 29994 22764 50448 3724 30508 27699 18470 32056 3767]"] + xor2 --> mask +``` diff --git a/docs/scripts/render_diagrams_md.py b/docs/scripts/render_diagrams_md.py index 69cd0fe..fea929d 100644 --- a/docs/scripts/render_diagrams_md.py +++ b/docs/scripts/render_diagrams_md.py @@ -51,7 +51,6 @@ if __name__ == "__main__": selected_keys_confirm = select_keys_with_passcode_values(passcode_property_indices, confirm_keypad, keypad_size.numb_of_keys) ordered_confirm_icons = emojis[confirm_keypad] - print(f"Selected Keys\n{selected_keys_confirm}") success = api.confirm_nkode(customer_id, selected_keys_confirm, signup_session_id) context = { "email": "user@example.com", diff --git a/docs/scripts/render_encipher_decipher_diagrams.py b/docs/scripts/render_encipher_decipher_diagrams.py new file mode 100644 index 0000000..88e5ee3 --- /dev/null +++ b/docs/scripts/render_encipher_decipher_diagrams.py @@ -0,0 +1,79 @@ +import base64 +import hashlib +from pathlib import Path + +import bcrypt +import numpy as np +from secrets import choice +from string import ascii_lowercase +from docs.scripts.utils import render_markdown_template, emojis +from src.models import NKodePolicy, KeypadSize +from src.nkode_api import NKodeAPI +from src.utils import select_keys_with_passcode_values + +if __name__ == "__main__": + api = NKodeAPI() + + 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 + ) + customer_id = api.create_new_customer(keypad_size, policy) + customer = api.get_customer(customer_id) + username = "test_username" + "".join([choice(ascii_lowercase) for _ in range(6)]) + signup_session_id, set_signup_keypad = api.generate_signup_keypad(customer_id, username) + ordered_set_icons = emojis[set_signup_keypad] + passcode_len = 4 + passcode_property_indices = np.random.choice(set_signup_keypad.reshape(-1), size=passcode_len, + replace=False).tolist() + selected_keys_set = select_keys_with_passcode_values(passcode_property_indices, set_signup_keypad, + keypad_size.numb_of_keys) + confirm_keypad = api.set_nkode(customer_id, selected_keys_set, signup_session_id) + selected_keys_confirm = select_keys_with_passcode_values(passcode_property_indices, confirm_keypad, + keypad_size.numb_of_keys) + ordered_confirm_icons = emojis[confirm_keypad] + success = api.confirm_nkode(customer_id, selected_keys_confirm, signup_session_id) + user = api.customers[customer_id].users[username] + combined_prop_key = user.cipher.property_key ^ customer.cipher.property_key + user_passcode = combined_prop_key[passcode_property_indices] + pad_len = customer.nkode_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.cipher.pass_key + passcode_prehash = base64.b64encode(hashlib.sha256(ciphered_passcode.tobytes()).digest()) + passcode_hash = bcrypt.hashpw(passcode_prehash, bcrypt.gensalt(rounds=12)).decode("utf-8") + + padded_passcode_position_indices = customer.cipher.get_passcode_position_indices_padded( + list(passcode_property_indices), customer.nkode_policy.max_nkode_len) + user_position_key = user.cipher.combined_position_key ^ customer.cipher.position_key + ordered_user_position_key = user_position_key[padded_passcode_position_indices] + mask = ordered_user_position_key ^ user.cipher.mask_key + encoded_mask = user.cipher.encode_base64_str(mask) + context = { + "max_nkode_len": policy.max_nkode_len, + "numb_of_keys": keypad_size.numb_of_keys, + "props_per_key": keypad_size.props_per_key, + "customer_property_key": customer.cipher.property_key, + "customer_position_key": customer.cipher.position_key, + "user_property_key": user.cipher.property_key, + "pass_key": user.cipher.pass_key, + "combined_position_key": user.cipher.combined_position_key, + "user_position_key": user_position_key, + "mask_key": user.cipher.mask_key, + "user_passcode_idxs": passcode_property_indices, + "combined_property_key": combined_prop_key, + "user_passcode_props": user_passcode, + "padded_passcode": padded_passcode, + "ciphered_passcode": ciphered_passcode, + "code": passcode_hash, + "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": mask, + } + render_markdown_template(Path("../templates/encipher_decipher_nkode.template.md"), Path("../encipher_decipher_nkode.md"), context) \ No newline at end of file diff --git a/docs/templates/encipher_decipher_nkode.template.md b/docs/templates/encipher_decipher_nkode.template.md index 3619d3e..e3bb878 100644 --- a/docs/templates/encipher_decipher_nkode.template.md +++ b/docs/templates/encipher_decipher_nkode.template.md @@ -1,128 +1,173 @@ # Encipher and Decipher nKode -### Customer Policy +## Customer 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 }} -### Customer Cipher +## Customer Cipher - property key: {{ customer_property_key }} - position key: {{ customer_position_key }} --- -### User Cipher +## User Cipher - property key: {{ user_property_key }} - passcode key: {{ pass_key }} - combined position key: {{ combined_position_key }} - mask key: {{ mask_key }} -#### Combined Postion Key +### Combined Postion Key ```mermaid block-beta columns 2 - user_pos["user postion key:\n{{user_postion_key}}"] - customer_pos["customer postion key:\n{{customer_position_key}}"] + user_pos["user position key:\n{{user_position_key}}"] + customer_pos["customer position key:\n{{customer_position_key}}"] space:2 xor(("XOR")):2 user_pos --> xor customer_pos --> xor space:2 - comb_pos["combined postion key\n{{combined_postion_key}}"]:2 + comb_pos["combined position key\n{{combined_position_key}}"]:2 xor --> comb_pos ``` -### User Keypad +## User Keypad - keypad: {{ user_keypad}} -- user passcode indicies: {{ user_passcode_idxs}} +- user passcode indices: {{ user_passcode_idxs}} -### nKode Cipher +## nKode Cipher -#### Passcode Hash +### Passcode Hash ```mermaid block-beta -columns 2 - cprop["customer_property_key\n{{customer_property_key}}"] - uprop["user_property_key\n{{user_property_key}}"] - space:2 - xor1(("XOR")):2 - cprop --> xor1 - uprop --> xor1 - space:2 - prop["combined_properity_key\n{{combined_property_key}}"] - xor1 --> prop - pass["user_passcode_indicies\n{{user_passcode_idxs}}"] - space:2 - sel(("select\nproperites")):2 - pass --> sel - prop --> sel - space:2 - passcode["passcode vals:\n{{passcode_vals}}"]: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 + columns 2 + cprop["customer_property_key\n{{customer_property_key}}"] + uprop["user_property_key\n{{user_property_key}}"] + space:2 + xor1(("XOR")):2 + cprop --> xor1 + uprop --> xor1 + space:2 + prop["combined_property_key\n{{combined_property_key}}"] + xor1 --> prop + 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 +### Mask Encipher ```mermaid block-beta - columns 3 - passcode_idx["passcode indicies:\n{{user_passcode_idxs}}"] - comb_pos["combined position key"] - cust_pos["customer position key"] + columns 3 + passcode_idx["passcode indices:\n{{user_passcode_idxs}}"] + comb_pos["combined position key:\n{{combined_position_key}}"] + cust_pos["customer position key:\n{{customer_position_key}}"] + + space:3 + propidx(["Get Position Idx:\nmap each to element mod props_per_key"]) + passcode_idx-->propidx + space:1 + xor1(("XOR")) + comb_pos --> xor1 + cust_pos --> xor1 + + space:3 + passcode_position_idx["passcode poition indices:\n{{passcode_position_idxs}}"] + propidx --> passcode_position_idx + + space:5 + pad1(("Pad with\nrandom indices")) + passcode_position_idx --> pad1 + + space:5 + posidx["Padded Passcode Position Indices:\n{{pad_user_passcode_idxs}}"] + pad1 --> posidx + space:1 + user_pos["user position key:\n{{user_position_key}}"] + xor1 --> user_pos + + space:4 + sel(("select positions")) + user_pos --> sel + posidx --> sel + space:5 + passcode_pos["ordered user passcode positions:\n{{ordered_user_position_key}}"] + sel --> passcode_pos + mask_key["mask key\n{{mask_key}}"] + space:4 + xor2(("XOR")) + mask_key --> xor2 + passcode_pos --> xor2 + space:5 + mask["enciphered mask:\n {{mask}}"] + xor2 --> mask +``` - space:3 - pad1(("Pad with\nrandom indices")) - space:1 - xor1(("XOR")) - comb_pos --> xor1 - cust_pos --> xor1 - passcode_idx --> pad1 - space:3 - padded_passcode_idx["padded passcode indices:\n{{pad_user_passcode_idxs}}"] - pad1 --> padded_passcode_idx - space:5 - propidx(["Get Postion Idx:\nmap each to\nelement mod props_per_key"]) - padded_passcode_idx --> propidx - space:5 - posidx["Passcode Position Indices:\n{{passcode_pos_idx}}"] - propidx --> posidx - space:1 - user_pos["user position key"] - xor1 --> user_pos - space:4 - sel(("select\npositions")) - user_pos --> sel - posidx --> sel - space:5 - passcode_pos["passcode positions:\n{{ordered_user_position_key}}"] - sel --> passcode_pos - mask_key["mask key\n{{mask_key}}"] - space:4 - xor2(("XOR")) - mask_key --> xor2 - passcode_pos --> xor2 - space:5 - mask["enciphered mask:\n {{mask}}"] - xor2 --> mask -``` \ No newline at end of file +### Validate nKode + +```mermaid +block-beta + columns 4 + selected_keys["selected keys:\n{{selected_keys}}"] + login_keypad["login keypad:\n{{login_keypad}}"] + mask["enciphered mask:\n {{mask}}"] + mask_key["mask key:\n{{mask_key}}"] + space:6 + + user_position_key["user position key:\n{{user_position_key}}"] + passcode_pos["ordered user passcode positions:\n{{ordered_user_position_key}}"] + space:4 + + space:2 + get_passcode_idxs(("recover passcode\nposition indices")) + space:7 + + passcode_pos_idxs["padded passcode position indices:\n{{pad_user_passcode_idxs}}"] + space:5 + + get_presumed_idxs(("recover passcode\nproperty indices")) + space:7 + + passcode_prop_idxs["presumed passcode property indices:\n{{user_passcode_idxs}}"] + space:7 + + sel(("select\nproperties")) + space:1 + prop["combined_property_key\n{{combined_property_key}}"] + space:5 + passcode_prop["presumed passcode properties:\n{{user_passcode_props}}"] + space:1 + cipheredhashed["hashed ciphered passcode:\n{{code}}"] + space:6 + + comp(("compare")) + +```