Files
pynkode/docs/encipher_decipher_renew_nkode_v2.md
2025-12-03 11:36:43 -06:00

6.4 KiB

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:
  • user passcode indices: [48 12 7 36]

nKode Cipher

Passcode Hash

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

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

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.