nx_aes256_gcm_gate.nx source
↩ module page · 82 lines · 5958 B
1// nx_aes256_gcm_gate.nx -- SOVEREIGN KAT referee for AES-256-GCM vs NIST SP 800-38D / McGrew GCM test vectors.
2// TC14: zero key/IV, 16-byte zero PT, no AAD -> CT=cea7403d.. Tag=d0d1c8a7..
3// TC16: real key/IV + 20-byte AAD + 60-byte PT (ragged, exercises multi-block + tail) -> CT=522dc1f0.. Tag=76fc6ece..
4// T1 seal(TC14) == CT+Tag ; T2 open(TC14) recovers PT + tag OK ; T3 seal(TC16) == CT+Tag ; T4 open(TC16) recovers PT
5// T5 NEG: open(TC16) with a corrupted tag -> -1 (authentication rejects) ; T6 aes256 KAT block (FIPS-197 C.3)
6// GREEN iff 6/6. license_tier: ORIGINAL expect_exit: 0
7import "nx_syscalls.nx"
8import "nx_aes256_gcm.nx"
9import "nx_gate_verdict.nx"
10
11func gw(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 }
12func gn(v: i64) -> i64 { let b: *u8 = sys_mmap(24); var m: i64 = v; if m < 0 { gw("-" as *u8); m = 0 - m }; let t: *u8 = sys_mmap(24); var k: i64 = 0; if m == 0 { t[0] = 48 as u8; k = 1 }; while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }; var i: i64 = 0; while i < k { b[i] = t[k - 1 - i]; i = i + 1 }; sys_write(1, b, k); return 0 }
13func grow(name: *u8, ok: i64) -> i64 { if ok == 1 { gw(" PASS " as *u8) } else { gw(" FAIL " as *u8) } gw(name); gw("\n" as *u8); return ok }
14// hex nibble
15func hx(c: i64) -> i64 { if c>=48 { if c<=57 { return c-48 } } if c>=97 { if c<=102 { return c-87 } } if c>=65 { if c<=70 { return c-55 } } return 0 }
16// parse a hex string into out; returns byte count
17func h2b(s: *u8, out: *u8) -> i64 {
18 var i: i64 = 0; var o: i64 = 0
19 while s[i] != (0 as u8) { if s[i+1] == (0 as u8) { i = i + 1 } else { out[o] = ((hx(s[i] as i64) << 4) | hx(s[i+1] as i64)) as u8; o = o + 1; i = i + 2 } }
20 return o
21}
22func beq(a: *u8, b: *u8, n: i64) -> i64 { var i: i64 = 0; while i < n { if (a[i] as i64) != (b[i] as i64) { return 0 } i = i + 1 } return 1 }
23
24func main() -> i64 {
25 gw("aes256-gcm SOVEREIGN KAT gate (NIST SP800-38D / McGrew TC14 + TC16 + FIPS-197 block)\n" as *u8)
26 var pass: i64 = 0
27 let key: *u8 = sys_mmap(64); let iv: *u8 = sys_mmap(32); let pt: *u8 = sys_mmap(128); let aad: *u8 = sys_mmap(64)
28 let ct: *u8 = sys_mmap(128); let tag: *u8 = sys_mmap(32)
29 let octb: *u8 = sys_mmap(128); let otag: *u8 = sys_mmap(32); let opt: *u8 = sys_mmap(128)
30
31 // ---- TC14: zero key/iv, 16-byte zero PT, no AAD ----
32 let kn: i64 = h2b("0000000000000000000000000000000000000000000000000000000000000000" as *u8, key)
33 let vn: i64 = h2b("000000000000000000000000" as *u8, iv)
34 let pn: i64 = h2b("00000000000000000000000000000000" as *u8, pt)
35 let cn: i64 = h2b("cea7403d4d606b6e074ec5d3baf39d18" as *u8, ct)
36 let tn: i64 = h2b("d0d1c8a799996bf0265b98b5d48ab919" as *u8, tag)
37 nx_aes256_gcm_seal(key, iv, aad, 0, pt, pn, octb, otag)
38 var t1: i64 = 0; if beq(octb, ct, cn)==1 { if beq(otag, tag, 16)==1 { t1 = 1 } }
39 pass = pass + grow("T1 seal(TC14) == NIST CT + Tag\x00" as *u8, t1)
40 let r2: i64 = nx_aes256_gcm_open(key, iv, aad, 0, ct, cn, tag, opt)
41 var t2: i64 = 0; if r2==0 { if beq(opt, pt, pn)==1 { t2 = 1 } }
42 pass = pass + grow("T2 open(TC14) tag-OK + recovers PT\x00" as *u8, t2)
43
44 // ---- TC16: real key/iv + AAD + 60-byte ragged PT ----
45 h2b("feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308" as *u8, key)
46 h2b("cafebabefacedbaddecaf888" as *u8, iv)
47 let an: i64 = h2b("feedfacedeadbeeffeedfacedeadbeefabaddad2" as *u8, aad)
48 let pn2: i64 = h2b("d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39" as *u8, pt)
49 let cn2: i64 = h2b("522dc1f099567d07f47f37a32a84427d643a8cdcbfe5c0c97598a2bd2555d1aa8cb08e48590dbb3da7b08b1056828838c5f61e6393ba7a0abcc9f662" as *u8, ct)
50 h2b("76fc6ece0f4e1768cddf8853bb2d551b" as *u8, tag)
51 nx_aes256_gcm_seal(key, iv, aad, an, pt, pn2, octb, otag)
52 var t3: i64 = 0; if beq(octb, ct, cn2)==1 { if beq(otag, tag, 16)==1 { t3 = 1 } }
53 pass = pass + grow("T3 seal(TC16 +AAD +ragged 60B) == NIST CT + Tag\x00" as *u8, t3)
54 let r4: i64 = nx_aes256_gcm_open(key, iv, aad, an, ct, cn2, tag, opt)
55 var t4: i64 = 0; if r4==0 { if beq(opt, pt, pn2)==1 { t4 = 1 } }
56 pass = pass + grow("T4 open(TC16) tag-OK + recovers PT\x00" as *u8, t4)
57
58 // ---- T5 NEG: corrupt the tag -> open must reject ----
59 let badtag: *u8 = sys_mmap(32); var i: i64 = 0; while i < 16 { badtag[i] = tag[i]; i = i + 1 } badtag[0] = ((tag[0] as i64) ^ 0xff) as u8
60 let r5: i64 = nx_aes256_gcm_open(key, iv, aad, an, ct, cn2, badtag, opt)
61 pass = pass + grow("T5 NEG open(corrupt tag) -> -1 (auth rejects)\x00" as *u8, r5 == 0 - 1)
62
63 // ---- T6 FIPS-197 C.3 AES-256 block KAT ----
64 // key=000102..1f pt=00112233445566778899aabbccddeeff ct=8ea2b7ca516745bfeafc49904b496089
65 let k6: *u8 = sys_mmap(64); h2b("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f" as *u8, k6)
66 let p6: *u8 = sys_mmap(16); h2b("00112233445566778899aabbccddeeff" as *u8, p6)
67 let c6: *u8 = sys_mmap(16); h2b("8ea2b7ca516745bfeafc49904b496089" as *u8, c6)
68 let sched: *u8 = sys_mmap(240); aes256_expand_key(k6, sched)
69 let o6: *u8 = sys_mmap(16); aes256_encrypt_block(p6, sched, o6)
70 pass = pass + grow("T6 FIPS-197 C.3 AES-256 block encrypt == KAT\x00" as *u8, beq(o6, c6, 16))
71
72 gw("pass=" as *u8); gn(pass); gw("/6\n" as *u8)
73 // MIGRATED onto nx_gate_verdict by nx_gate_dry_apply (D001, minimal form): every check
74 // row above is untouched, so the PASS/FAIL vector cannot change; only the hand-rolled
75 // verdict emission is replaced by the ONE shared base class. Proven by nx_gate_migrate verify.
76 let ctr__dry: *i64 = gv_ctr()
77 ctr__dry[0] = pass
78 ctr__dry[1] = 6
79 let rc__dry: i64 = gv_verdict("AES256-GCM-GATE" as *u8, ctr__dry, "AES-256-GCM: NIST GCM TC14+TC16 seal/open + auth-reject + FIPS-197 block KAT -- full cipher coverage)" as *u8)
80 sys_exit(rc__dry)
81 return rc__dry
82}