code wiki / _hdl_build / nx_vault_transit.nx

nx_vault_transit.nx source

↩ module page · 60 lines · 3338 B

1// nx_vault_transit.nx -- sovereign TRANSIT engine (encryption-as-a-service): the HashiCorp Vault "transit" 2// gap from vault_capability_census.tsv. The vault holds the KEY; the caller's data passes THROUGH and is 3// NEVER stored. Versioned keyring: encrypt stamps the LATEST key version into a self-describing envelope; 4// decrypt ROUTES to the version named in the envelope (so old ciphertext still opens after key rotation); 5// rewrap re-encrypts an old-version envelope to the latest version WITHOUT returning plaintext to the caller 6// (rotate keys without re-exposing the data). REAL AES-128-GCM (composes nx_aes128_gcm = NIST SP800-38D), 7// fails-closed on tamper. Production keys are vault-sealed (nx_vault + nx_machine_key); here the keyring is 8// caller-supplied. license_tier: ORIGINAL 9import "nx_aes128_gcm.nx" 10import "nx_syscalls.nx" 11const TR_MAGIC_4096: i64 = 4096 12 13// envelope: [ver:1][iv:12][tag:16][ciphertext:ptlen] 14const TR_VER_OFF: i64 = 0 15const TR_IV_OFF: i64 = 1 16const TR_TAG_OFF: i64 = 13 17const TR_CT_OFF: i64 = 29 18 19// pointer to the 16-byte key for a 1-based version inside a contiguous keyring. 20func tr_keyptr(keyring: *u8, ver: i64) -> *u8 { return ((keyring as i64) + (ver - 1) * 16) as *u8 } 21 22// encrypt pt under the LATEST key version; write the self-describing envelope. returns envelope length. 23func tr_encrypt(keyring: *u8, latest_ver: i64, iv12: *u8, pt: *u8, pt_len: i64, env_out: *u8) -> i64 { 24 env_out[TR_VER_OFF] = latest_ver as u8 25 var i: i64 = 0 26 while i < 12 { env_out[TR_IV_OFF + i] = iv12[i]; i = i + 1 } 27 let z: *u8 = sys_mmap(16) // mmap is zero-filled -> empty AAD 28 let tag: *u8 = ((env_out as i64) + TR_TAG_OFF) as *u8 29 let ct: *u8 = ((env_out as i64) + TR_CT_OFF) as *u8 30 nx_aes128_gcm_seal(tr_keyptr(keyring, latest_ver), iv12, z, 0, pt, pt_len, ct, tag) 31 return TR_CT_OFF + pt_len 32} 33 34// decrypt: route to the envelope's key version, AES-GCM open. returns pt_len, or -1 (fails-closed). 35func tr_decrypt(keyring: *u8, key_count: i64, env: *u8, env_len: i64, pt_out: *u8) -> i64 { 36 let ver: i64 = env[TR_VER_OFF] as i64 37 if ver < 1 { return 0 - 1 } 38 if ver > key_count { return 0 - 1 } 39 let iv: *u8 = ((env as i64) + TR_IV_OFF) as *u8 40 let tag: *u8 = ((env as i64) + TR_TAG_OFF) as *u8 41 let ct: *u8 = ((env as i64) + TR_CT_OFF) as *u8 42 let ct_len: i64 = env_len - TR_CT_OFF 43 let z: *u8 = sys_mmap(16) 44 let rc: i64 = nx_aes128_gcm_open(tr_keyptr(keyring, ver), iv, z, 0, ct, ct_len, tag, pt_out) 45 if rc != 0 { return 0 - 1 } 46 return ct_len 47} 48 49// rewrap: re-encrypt an old-version envelope to the LATEST version. plaintext is decrypted INTERNALLY then 50// ZEROED; the caller receives ONLY the new ciphertext envelope (the transit rotation guarantee). returns 51// new envelope length, or -1. 52func tr_rewrap(keyring: *u8, key_count: i64, latest_ver: i64, env_in: *u8, env_in_len: i64, new_iv12: *u8, env_out: *u8) -> i64 { 53 let scratch: *u8 = sys_mmap(TR_MAGIC_4096) 54 let n: i64 = tr_decrypt(keyring, key_count, env_in, env_in_len, scratch) 55 if n < 0 { return 0 - 1 } 56 let out_len: i64 = tr_encrypt(keyring, latest_ver, new_iv12, scratch, n, env_out) 57 var i: i64 = 0 58 while i < n { scratch[i] = 0; i = i + 1 } // wipe plaintext; caller never sees it 59 return out_len 60}