code wiki / _hdl_build / nx_doc_crypto_gate.nx

nx_doc_crypto_gate.nx source

↩ module page · 107 lines · 6816 B

1// nx_doc_crypto_gate.nx -- MEASURED hermetic gate for encryption-at-rest (nx_doc_crypto). Fresh nonce domain per 2// run (sys_now_realtime_sec) so it never depends on prior state. Proves the AEAD envelope + crypto-shred: 3// T1 round-trip : doc_encrypt -> doc_decrypt returns the plaintext BYTE-IDENTICAL 4// T2 tamper : a flipped ciphertext byte -> doc_decrypt FAILS (Poly1305 tag reject) 5// T3 wrong tenant : a different domain's DEK -> doc_decrypt FAILS (per-tenant isolation) 6// T4 crypto-shred : after crypto_shred, doc_decrypt FAILS (DEK destroyed) while the ciphertext bytes survive 7// Print pass=N/4 + GREEN/RED, append knowledge/status/dp_crypto_gate.log. STANDALONE -- no daemon touched. 8// (Diagnostic note: nx_chacha20_poly1305_decrypt writes a single 'A' to STDERR on its first call -- scratch-alloc 9// marker in the shipped AEAD; it does not affect stdout or the verdict.) license_tier: ORIGINAL 10import "nx_doc_crypto.nx" // dek_gen / doc_encrypt / doc_decrypt / crypto_shred (+ AEAD/csprng/syscalls transitively) 11 12func g_puts(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 } 13func g_num(v: i64) -> i64 { 14 let bb: *u8 = sys_mmap(28); var m: i64 = v; if m < 0 { m = 0 - m; sys_write(1, "-" as *u8, 1) } 15 let t: *u8 = sys_mmap(28); var k: i64 = 0; if m == 0 { t[0] = 48 as u8; k = 1 } 16 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 } 17 var i: i64 = 0; while i < k { bb[i] = t[k - 1 - i]; i = i + 1 } sys_write(1, bb, k); return 0 18} 19func g_w(fd: i64, s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(fd, s, n); return 0 } 20func g_wn(fd: i64, v: i64) -> i64 { 21 let bb: *u8 = sys_mmap(28); var m: i64 = v; if m < 0 { m = 0 - m } 22 let t: *u8 = sys_mmap(28); var k: i64 = 0; if m == 0 { t[0] = 48 as u8; k = 1 } 23 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 } 24 var i: i64 = 0; while i < k { bb[i] = t[k - 1 - i]; i = i + 1 } sys_write(fd, bb, k); return 0 25} 26func g_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n } 27func g_cat(out: *u8, o: i64, s: *u8) -> i64 { var i: i64 = 0; while s[i] != (0 as u8) { out[o] = s[i]; o = o + 1; i = i + 1 } return o } 28func g_catnum(out: *u8, o: i64, v: i64) -> i64 { 29 if v == 0 { out[o] = 48 as u8; return o + 1 } 30 var m: i64 = v; let t: *u8 = sys_mmap(28); var k: i64 = 0 31 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 } 32 var i: i64 = 0; while i < k { out[o] = t[k - 1 - i]; o = o + 1; i = i + 1 } return o 33} 34func g_eqbytes(a: *u8, b: *u8, n: i64) -> i64 { var i: i64 = 0; while i < n { if a[i] != b[i] { return 0 } i = i + 1 } return 1 } 35 36func main() -> i64 { 37 g_puts("=== DP CRYPTO GATE (encryption-at-rest: ChaCha20-Poly1305 envelope + crypto-shred) ===\n" as *u8) 38 // fresh per-run tenant domains 39 let nonce: i64 = sys_now_realtime_sec() 40 let domA: *u8 = sys_mmap(64) 41 var da: i64 = g_cat(domA, 0, "dpcryptoa" as *u8); da = g_catnum(domA, da, nonce); domA[da] = 0 as u8 42 let domB: *u8 = sys_mmap(64) 43 var db: i64 = g_cat(domB, 0, "dpcryptob" as *u8); db = g_catnum(domB, db, nonce); domB[db] = 0 as u8 44 45 let pt: *u8 = "ENC-AT-REST FIXTURE: confidential client record -- protected health information sample bytes." as *u8 46 let ptlen: i64 = g_slen(pt) 47 48 // provision tenant A's DEK and seal the document 49 let ga: i64 = dek_gen(domA) 50 let ct: *u8 = sys_mmap(ptlen + 64) 51 let ctlen: i64 = doc_encrypt(domA, pt, ptlen, ct) 52 53 var pass: i64 = 0 54 55 // T1: round-trip byte-identical 56 let pt2: *u8 = sys_mmap(ptlen + 64) 57 let n1: i64 = doc_decrypt(domA, ct, ctlen, pt2) 58 var t1: i64 = 0 59 if ga == 0 { if ctlen == 12 + ptlen + 16 { if n1 == ptlen { if g_eqbytes(pt2, pt, ptlen) == 1 { t1 = 1 } } } } 60 pass = pass + t1 61 g_puts(" T1 encrypt->decrypt round-trips (ctlen=" as *u8); g_num(ctlen); g_puts(" ptlen=" as *u8); g_num(n1); g_puts(" identical=" as *u8); g_num(g_eqbytes(pt2, pt, ptlen)); g_puts("): " as *u8) 62 if t1 == 1 { g_puts("PASS\n" as *u8) } else { g_puts("FAIL\n" as *u8) } 63 64 // T2: tampered ciphertext -> AEAD rejects 65 let ctT: *u8 = sys_mmap(ptlen + 64) 66 var c: i64 = 0 67 while c < ctlen { ctT[c] = ct[c]; c = c + 1 } 68 let b0: i64 = ctT[12] as i64 // first ciphertext-body byte (after the 12-byte nonce) 69 ctT[12] = ((b0 + 1) & 0xff) as u8 // flip it deterministically (no XOR operator needed) 70 let pt3: *u8 = sys_mmap(ptlen + 64) 71 let n2: i64 = doc_decrypt(domA, ctT, ctlen, pt3) 72 var t2: i64 = 0; if n2 < 0 { t2 = 1 } pass = pass + t2 73 g_puts(" T2 tampered ciphertext -> decrypt FAILS (rc=" as *u8); g_num(n2); g_puts(", expect <0): " as *u8) 74 if t2 == 1 { g_puts("PASS\n" as *u8) } else { g_puts("FAIL\n" as *u8) } 75 76 // T3: wrong tenant DEK -> AEAD rejects (per-tenant isolation) 77 dek_gen(domB) 78 let pt4: *u8 = sys_mmap(ptlen + 64) 79 let n3: i64 = doc_decrypt(domB, ct, ctlen, pt4) 80 var t3: i64 = 0; if n3 < 0 { t3 = 1 } pass = pass + t3 81 g_puts(" T3 wrong-tenant DEK -> decrypt FAILS (rc=" as *u8); g_num(n3); g_puts(", expect <0): " as *u8) 82 if t3 == 1 { g_puts("PASS\n" as *u8) } else { g_puts("FAIL\n" as *u8) } 83 84 // T4: crypto-shred -> decrypt FAILS (DEK gone) while ciphertext bytes survive 85 let save: *u8 = sys_mmap(32) 86 var s: i64 = 0 87 while s < 16 { save[s] = ct[s]; s = s + 1 } 88 let sh: i64 = crypto_shred(domA) 89 let pt5: *u8 = sys_mmap(ptlen + 64) 90 let n4: i64 = doc_decrypt(domA, ct, ctlen, pt5) 91 let ct_survives: i64 = g_eqbytes(ct, save, 16) 92 var t4: i64 = 0; if sh == 0 { if n4 < 0 { if ct_survives == 1 { t4 = 1 } } } pass = pass + t4 93 g_puts(" T4 crypto-shred -> decrypt FAILS + ciphertext survives (shred=" as *u8); g_num(sh); g_puts(" decrypt=" as *u8); g_num(n4); g_puts(" ct_survives=" as *u8); g_num(ct_survives); g_puts("): " as *u8) 94 if t4 == 1 { g_puts("PASS\n" as *u8) } else { g_puts("FAIL\n" as *u8) } 95 96 g_puts("----\nDP-CRYPTO rows=4 pass=" as *u8); g_num(pass); g_puts("\n" as *u8) 97 let lg: i64 = sys_openat_append("knowledge/status/dp_crypto_gate.log" as *u8, 0x1a4) 98 if lg >= 0 { 99 g_w(lg, "DP-CRYPTO roundtrip=" as *u8); g_wn(lg, t1); g_w(lg, " tamper_reject=" as *u8); g_wn(lg, t2) 100 g_w(lg, " tenant_isolation=" as *u8); g_wn(lg, t3); g_w(lg, " crypto_shred=" as *u8); g_wn(lg, t4) 101 g_w(lg, " rows=4 pass=" as *u8); g_wn(lg, pass) 102 if pass == 4 { g_w(lg, " verdict=GREEN\n" as *u8) } else { g_w(lg, " verdict=RED\n" as *u8) } 103 sys_close(lg) 104 } 105 if pass == 4 { g_puts("DP-CRYPTO GREEN (AEAD-at-rest round-trips, rejects tamper + wrong-tenant, crypto-shred destroys access -- measured)\n" as *u8); sys_exit(0); return 0 } 106 g_puts("DP-CRYPTO RED\n" as *u8); sys_exit(1); return 1 107}