code wiki / (root) / nx_aes128_gcm_kat_test.nx

nx_aes128_gcm_kat_test.nx source

↩ module page · 137 lines · 5278 B

1// nx_aes128_gcm_kat_test.nx -- NIST SP 800-38D Test Case 2 + 2// round-trip (seal then open) on a synthetic AAD. 3// 4// Test Case 2: 5// K = 00000000000000000000000000000000 6// IV = 000000000000000000000000 7// AAD = (empty) 8// P = 00000000000000000000000000000000 (16-byte all-zero pt) 9// -> C = 0388dace60b6a392f328c2b971b2fe78 10// T = ab6e47d42cec13bdf53a67b21257bddf 11// 12// expect_exit: 0. 13// license_tier: ORIGINAL 14 15import "nx_syscalls.nx" 16import "nx_aes128_gcm.nx" 17 18func main() -> i64 { 19 let key: *u8 = sys_mmap(16) 20 let iv: *u8 = sys_mmap(12) 21 let pt: *u8 = sys_mmap(16) 22 var i: i64 = 0 23 while i < 16 { key[i] = 0; pt[i] = 0; i = i + 1 } 24 i = 0 25 while i < 12 { iv[i] = 0; i = i + 1 } 26 let aad: *u8 = sys_mmap(8) // empty (len=0) 27 28 let ct: *u8 = sys_mmap(16) 29 let tag: *u8 = sys_mmap(16) 30 nx_aes128_gcm_seal(key, iv, aad, 0, pt, 16, ct, tag) 31 32 // Expected C = 0388dace60b6a392f328c2b971b2fe78 33 let exp_ct: *u8 = sys_mmap(16) 34 exp_ct[0]=0x03; exp_ct[1]=0x88; exp_ct[2]=0xda; exp_ct[3]=0xce 35 exp_ct[4]=0x60; exp_ct[5]=0xb6; exp_ct[6]=0xa3; exp_ct[7]=0x92 36 exp_ct[8]=0xf3; exp_ct[9]=0x28; exp_ct[10]=0xc2; exp_ct[11]=0xb9 37 exp_ct[12]=0x71; exp_ct[13]=0xb2; exp_ct[14]=0xfe; exp_ct[15]=0x78 38 i = 0 39 while i < 16 { 40 if (ct[i] & 0xff) != (exp_ct[i] & 0xff) { return 10 + i } 41 i = i + 1 42 } 43 44 // Expected T = ab6e47d42cec13bdf53a67b21257bddf 45 let exp_tag: *u8 = sys_mmap(16) 46 exp_tag[0]=0xab; exp_tag[1]=0x6e; exp_tag[2]=0x47; exp_tag[3]=0xd4 47 exp_tag[4]=0x2c; exp_tag[5]=0xec; exp_tag[6]=0x13; exp_tag[7]=0xbd 48 exp_tag[8]=0xf5; exp_tag[9]=0x3a; exp_tag[10]=0x67; exp_tag[11]=0xb2 49 exp_tag[12]=0x12; exp_tag[13]=0x57; exp_tag[14]=0xbd; exp_tag[15]=0xdf 50 i = 0 51 while i < 16 { 52 if (tag[i] & 0xff) != (exp_tag[i] & 0xff) { return 30 + i } 53 i = i + 1 54 } 55 56 // Round-trip: open(ct, tag) -> pt 57 let pt2: *u8 = sys_mmap(16) 58 let ov: i64 = nx_aes128_gcm_open(key, iv, aad, 0, ct, 16, tag, pt2) 59 if ov != 0 { return 50 } 60 i = 0 61 while i < 16 { 62 if (pt2[i] & 0xff) != (pt[i] & 0xff) { return 60 + i } 63 i = i + 1 64 } 65 66 // Negative: corrupt tag -> open must fail. 67 tag[0] = tag[0] ^ 0x01 68 let nv: i64 = nx_aes128_gcm_open(key, iv, aad, 0, ct, 16, tag, pt2) 69 if nv != (0 - 1) { return 80 } 70 71 // Round-trip with non-empty AAD (synthetic vector self-consistency). 72 tag[0] = tag[0] ^ 0x01 // restore tag (unused below) 73 let aad2: *u8 = sys_mmap(16) 74 var j: i64 = 0 75 while j < 13 { aad2[j] = (0xa0 + j) as u8; j = j + 1 } 76 let pt3: *u8 = sys_mmap(32) 77 j = 0 78 while j < 24 { pt3[j] = (0x40 + j) as u8; j = j + 1 } 79 let ct3: *u8 = sys_mmap(32) 80 let tag3: *u8 = sys_mmap(16) 81 nx_aes128_gcm_seal(key, iv, aad2, 13, pt3, 24, ct3, tag3) 82 let pt3o: *u8 = sys_mmap(32) 83 let rv: i64 = nx_aes128_gcm_open(key, iv, aad2, 13, ct3, 24, tag3, pt3o) 84 if rv != 0 { return 100 } 85 j = 0 86 while j < 24 { 87 if (pt3o[j] & 0xff) != (pt3[j] & 0xff) { return 110 + j } 88 j = j + 1 89 } 90 91 // --- 4-WAY AGGREGATION PATH validation: multi-block seal->open round-trips. 92 // open() re-derives the tag via the UNTOUCHED reference (Horner) GHASH, so a 93 // successful open cross-checks the seal's aggregated ciphertext AND tag bit-for-bit 94 // against the independent reference. Two lengths: 95 // 64 bytes -> exactly one 4-block aggregation group (no leftover, no tail) 96 // 100 bytes -> one group + 2 leftover single blocks + a 4-byte ragged tail 97 // both with a 20-byte (multi-block) AAD. --- 98 let m_aad: *u8 = sys_mmap(20) 99 j = 0 100 while j < 20 { m_aad[j] = (0x80 + j) as u8; j = j + 1 } 101 102 // 64-byte pure-group case 103 let g_pt: *u8 = sys_mmap(64) 104 j = 0 105 while j < 64 { g_pt[j] = (0x11 + j * 5) as u8; j = j + 1 } 106 let g_ct: *u8 = sys_mmap(64) 107 let g_tag: *u8 = sys_mmap(16) 108 nx_aes128_gcm_seal(key, iv, m_aad, 20, g_pt, 64, g_ct, g_tag) 109 let g_out: *u8 = sys_mmap(64) 110 if nx_aes128_gcm_open(key, iv, m_aad, 20, g_ct, 64, g_tag, g_out) != 0 { return 200 } 111 j = 0 112 while j < 64 { if (g_out[j] & 0xff) != (g_pt[j] & 0xff) { return 201 } j = j + 1 } 113 114 // 100-byte group + leftover + tail case 115 let b_pt: *u8 = sys_mmap(100) 116 j = 0 117 while j < 100 { b_pt[j] = (0x2b + j * 7) as u8; j = j + 1 } 118 let b_ct: *u8 = sys_mmap(100) 119 let b_tag: *u8 = sys_mmap(16) 120 nx_aes128_gcm_seal(key, iv, m_aad, 20, b_pt, 100, b_ct, b_tag) 121 let b_out: *u8 = sys_mmap(100) 122 if nx_aes128_gcm_open(key, iv, m_aad, 20, b_ct, 100, b_tag, b_out) != 0 { return 210 } 123 j = 0 124 while j < 100 { if (b_out[j] & 0xff) != (b_pt[j] & 0xff) { return 211 } j = j + 1 } 125 126 // Negative control on the aggregated path: flipping one AAD bit must break auth. 127 m_aad[0] = m_aad[0] ^ 0x01 128 if nx_aes128_gcm_open(key, iv, m_aad, 20, b_ct, 100, b_tag, b_out) != (0 - 1) { return 220 } 129 m_aad[0] = m_aad[0] ^ 0x01 130 131 let msg: *u8 = sys_mmap(32) 132 msg[0]=0x47; msg[1]=0x43; msg[2]=0x4D; msg[3]=0x4B // "GCMK" 133 msg[4]=0x41; msg[5]=0x54; msg[6]=0x3D; msg[7]=0x4F // "AT=O" 134 msg[8]=0x4B; msg[9]=0x0A // "K\n" 135 sys_write(1, msg, 10) 136 return 0 137}