nx_password_vault.nx
buildroot/runtime/nx_password_vault.nx
about
nx_password_vault.nx -- sovereign at-rest-encrypted credential store.
Per user 2026-05-16:
"get that stored in a nishi language equivalent of a password
vault so it can be called by authorized users like you".
Per cardinals:
- feedback-dont-rebuild-commodity-platform-layers: bits-up sovereign,
no 1Password / LastPass / Bitwarden / OS keychain DEPENDENCY (we
can interop later, but the canonical store is local).
- feedback-user-owns-every-bit: vault file lives where the user
puts it; primitive does no auto-load, no auto-create, no
background daemon, no telemetry.
- feedback-launching-content-must-be-one-command-easy: tooling
calls vault_get(name) and gets back a credential string.
Threat model in scope:
- Disk theft: attacker has the encrypted vault file. Must NOT
recover plaintext without the master passphrase.
- Casual snooping: file is not human-readable.
- Offline brute-force: passphrase is the weak link. v1 uses
HKDF-SHA256 (FAST kdf) which is INSUFFICIENT against offline
brute force on weak passphrases. v2 ships Argon2id integration
and migrates existing vaults.
Threat model OUT of scope (v1):
- Active malware on the host running NishiLang (it can scrape RAM)
- Side-channel attacks on the KDF
- Vault file rotated without backup before deletion
File format (binary, big-endian):
magic [8 bytes] = "NXVLT\0\0\1" (version 1)
salt [32 bytes] (random; HKDF salt)
nonce_base[12 bytes] (random; XOR'd with entry idx)
n_entries [4 bytes BE]
for each entry i in 0..n_entries:
name_len [2 bytes BE]
name [name_len bytes] (UTF-8, plaintext)
ct_len [4 bytes BE]
ct [ct_len bytes] (encrypted value)
tag [16 bytes] (Poly1305 tag)
dependencies 4 imports · 1 importers
imports: nx_syscalls.nxnx_tier.nxnx_chacha20_poly1305.nxnx_hkdf.nx
imported by: nx_vault.nx
call flow from main pre-order; caps 40 nodes / depth 6 declared; ↻ = already shown
structs
| none |
consts
| 87 | const NX_VAULT_MAGIC_LEN: nx_int = 8 |
| 88 | const NX_VAULT_SALT_LEN: nx_int = 32 |
| 89 | const NX_VAULT_NONCE_LEN: nx_int = 12 |
| 90 | const NX_VAULT_KEY_LEN: nx_int = 32 |
| 91 | const NX_VAULT_TAG_LEN: nx_int = 16 |
| 92 | const NX_VAULT_AAD_NONE: nx_int = 0 |
| 94 | const NX_VAULT_VERDICT_OK: nx_int = 0 |
| 95 | const NX_VAULT_VERDICT_TAG_MISMATCH: nx_int = 1 |
| 96 | const NX_VAULT_VERDICT_BAD_ARGS: nx_int = 2 |
functions
| 106 | func nx_vault_derive_key( |
| 131 | func nx_vault_make_per_entry_nonce( |
| 162 | func nx_vault_encrypt_entry( |
| 188 | func nx_vault_decrypt_entry( |
| 217 | func main() -> i64 |