code wiki / _hdl_build / nx_dr_encrypt_gate.nx
nx_dr_encrypt_gate.nx source
↩ module page · 54 lines · 3394 B
1import "nx_gate_gn.nx"
2// nx_dr_encrypt_gate.nx -- exceed-gate for CAP-DR-ENCRYPT. Proves encryption-at-rest: seal->open round-trips
3// byte-exact, the ciphertext is NOT plaintext (confidentiality), a single-byte tamper is REJECTED (auth), and a
4// wrong key is REJECTED (the plaintext is never emitted). This is what a plain cp to /mnt/d cannot do.
5// Sovereign: nx_syscalls + nx_sha256 + nx_chacha20_poly1305. expect_exit: 0
6import "nx_syscalls.nx"
7import "nx_sha256.nx"
8import "nx_chacha20_poly1305.nx"
9import "nx_gate_verdict.nx"
10
11func gp(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 }
12func g_eq(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 }
13
14func main(argc: i64, argv: *i64) -> i64 {
15 gp("=== nx_dr_encrypt_gate (encryption-at-rest: round-trip / confidential / tamper+wrongkey rejected) ===\n" as *u8)
16 var pass: i64=0; var fail: i64=0
17
18 let key: *u8 = sys_mmap(32); sha256_digest("my dr archive passphrase" as *u8, 24, key)
19 let pt: *u8 = "accounts: elderwesto = operator level 3 SECRET" as *u8
20 let n: i64 = 46
21 let dig: *u8 = sys_mmap(64); sha256_digest(pt, n, dig) // convergent nonce source
22 let ct: *u8 = sys_mmap(n + 16); let tag: *u8 = sys_mmap(32)
23 nx_chacha20_poly1305_encrypt(key, dig, "" as *u8, 0, pt, n, ct, tag)
24
25 // T1 round-trip
26 let pt2: *u8 = sys_mmap(n + 16)
27 let v1: i64 = nx_chacha20_poly1305_decrypt(key, dig, "" as *u8, 0, ct, n, tag, pt2)
28 if v1 == NX_AEAD_VERDICT_OK { if g_eq(pt, pt2, n) == 1 { pass=pass+1; gp(" T1 seal->open round-trip byte-exact PASS\n" as *u8) } else { fail=fail+1; gp(" T1 FAIL bytes\n" as *u8) } } else { fail=fail+1; gp(" T1 FAIL verdict\n" as *u8) }
29
30 // T2 confidentiality: ciphertext differs from plaintext
31 if g_eq(pt, ct, n) == 0 { pass=pass+1; gp(" T2 ciphertext != plaintext (confidential) PASS\n" as *u8) } else { fail=fail+1; gp(" T2 FAIL plaintext leaked\n" as *u8) }
32
33 // T3 tamper the ciphertext -> rejected
34 ct[0] = (ct[0] as i64 ^ 1) as u8
35 let v3: i64 = nx_chacha20_poly1305_decrypt(key, dig, "" as *u8, 0, ct, n, tag, pt2)
36 if v3 != NX_AEAD_VERDICT_OK { pass=pass+1; gp(" T3 single-byte ciphertext tamper -> REJECTED PASS\n" as *u8) } else { fail=fail+1; gp(" T3 FAIL tamper accepted\n" as *u8) }
37 ct[0] = (ct[0] as i64 ^ 1) as u8 // restore
38
39 // T4 wrong key -> rejected
40 let key2: *u8 = sys_mmap(32); sha256_digest("WRONG passphrase" as *u8, 16, key2)
41 let v4: i64 = nx_chacha20_poly1305_decrypt(key2, dig, "" as *u8, 0, ct, n, tag, pt2)
42 if v4 != NX_AEAD_VERDICT_OK { pass=pass+1; gp(" T4 wrong key -> REJECTED (plaintext never emitted) PASS\n" as *u8) } else { fail=fail+1; gp(" T4 FAIL wrong key accepted\n" as *u8) }
43
44 gp("RESULT pass=" as *u8); gn(pass); gp(" fail=" as *u8); gn(fail)
45 // MIGRATED onto nx_gate_verdict by nx_gate_dry_apply (D001, minimal form): every check
46 // row above is untouched, so the PASS/FAIL vector cannot change; only the hand-rolled
47 // verdict emission is replaced by the ONE shared base class. Proven by nx_gate_migrate verify.
48 let ctr__dry: *i64 = gv_ctr()
49 ctr__dry[0] = pass
50 ctr__dry[1] = pass + fail
51 let rc__dry: i64 = gv_verdict("DR-ENCRYPT-GATE" as *u8, ctr__dry, "AEAD encryption-at-rest -- exceeds a plaintext cp)" as *u8)
52 sys_exit(rc__dry)
53 return rc__dry
54}