nx_chacha20_poly1305_test.nx source
↩ module page · 185 lines · 7346 B
1// nx_chacha20_poly1305_test.nx -- RFC 8439 ยง2.8.2 AEAD KAT.
2//
3// Sunscreen vector (the canonical AEAD test vector):
4// Plaintext (114 bytes ASCII):
5// "Ladies and Gentlemen of the class of '99: If I could offer
6// you only one tip for the future, sunscreen would be it."
7// AAD (12 bytes): 50 51 52 53 c0 c1 c2 c3 c4 c5 c6 c7
8// Key (32 bytes): 80..9f sequential
9// Nonce (12 bytes): 07 00 00 00 40 41 42 43 44 45 46 47
10// Expected ciphertext first 32:
11// d3 1a 8d 34 64 8e 60 db 7b 86 af bc 53 ef 7e c2
12// a4 ad ed 51 29 6e 08 fe a9 e2 b5 a7 36 ee 62 d6
13// Expected tag: 1a e1 0b 59 4f 09 e2 6a 7e 90 2e cb d0 60 06 91
14//
15// Also exercises tamper detection (single-bit flip in tag and in
16// ciphertext both reject) and round-trip (decrypt restores PT).
17//
18// expect_exit: 0
19//
20// license_tier: ORIGINAL
21
22import "nx_syscalls.nx"
23import "nx_chacha20_poly1305.nx"
24
25func main() -> i64 {
26 // ---- Key: 0x80..0x9f sequential ----
27 let key: *u8 = sys_mmap(64)
28 var ki: i64 = 0
29 while ki < 32 {
30 key[ki] = 0x80 + ki
31 ki = ki + 1
32 }
33
34 // ---- Nonce (12 bytes) ----
35 let nonce: *u8 = sys_mmap(16)
36 nonce[0]=0x07; nonce[1]=0; nonce[2]=0; nonce[3]=0
37 nonce[4]=0x40; nonce[5]=0x41; nonce[6]=0x42; nonce[7]=0x43
38 nonce[8]=0x44; nonce[9]=0x45; nonce[10]=0x46; nonce[11]=0x47
39
40 // ---- AAD (12 bytes) ----
41 let aad: *u8 = sys_mmap(16)
42 aad[0]=0x50; aad[1]=0x51; aad[2]=0x52; aad[3]=0x53
43 aad[4]=0xc0; aad[5]=0xc1; aad[6]=0xc2; aad[7]=0xc3
44 aad[8]=0xc4; aad[9]=0xc5; aad[10]=0xc6; aad[11]=0xc7
45
46 // ---- Plaintext: 114-byte Sunscreen quote ----
47 let pt: *u8 = sys_mmap(256)
48 pt[0]=0x4c; pt[1]=0x61; pt[2]=0x64; pt[3]=0x69
49 pt[4]=0x65; pt[5]=0x73; pt[6]=0x20; pt[7]=0x61
50 pt[8]=0x6e; pt[9]=0x64; pt[10]=0x20; pt[11]=0x47
51 pt[12]=0x65; pt[13]=0x6e; pt[14]=0x74; pt[15]=0x6c
52 pt[16]=0x65; pt[17]=0x6d; pt[18]=0x65; pt[19]=0x6e
53 pt[20]=0x20; pt[21]=0x6f; pt[22]=0x66; pt[23]=0x20
54 pt[24]=0x74; pt[25]=0x68; pt[26]=0x65; pt[27]=0x20
55 pt[28]=0x63; pt[29]=0x6c; pt[30]=0x61; pt[31]=0x73
56 pt[32]=0x73; pt[33]=0x20; pt[34]=0x6f; pt[35]=0x66
57 pt[36]=0x20; pt[37]=0x27; pt[38]=0x39; pt[39]=0x39
58 pt[40]=0x3a; pt[41]=0x20; pt[42]=0x49; pt[43]=0x66
59 pt[44]=0x20; pt[45]=0x49; pt[46]=0x20; pt[47]=0x63
60 pt[48]=0x6f; pt[49]=0x75; pt[50]=0x6c; pt[51]=0x64
61 pt[52]=0x20; pt[53]=0x6f; pt[54]=0x66; pt[55]=0x66
62 pt[56]=0x65; pt[57]=0x72; pt[58]=0x20; pt[59]=0x79
63 pt[60]=0x6f; pt[61]=0x75; pt[62]=0x20; pt[63]=0x6f
64 pt[64]=0x6e; pt[65]=0x6c; pt[66]=0x79; pt[67]=0x20
65 pt[68]=0x6f; pt[69]=0x6e; pt[70]=0x65; pt[71]=0x20
66 pt[72]=0x74; pt[73]=0x69; pt[74]=0x70; pt[75]=0x20
67 pt[76]=0x66; pt[77]=0x6f; pt[78]=0x72; pt[79]=0x20
68 pt[80]=0x74; pt[81]=0x68; pt[82]=0x65; pt[83]=0x20
69 pt[84]=0x66; pt[85]=0x75; pt[86]=0x74; pt[87]=0x75
70 pt[88]=0x72; pt[89]=0x65; pt[90]=0x2c; pt[91]=0x20
71 pt[92]=0x73; pt[93]=0x75; pt[94]=0x6e; pt[95]=0x73
72 pt[96]=0x63; pt[97]=0x72; pt[98]=0x65; pt[99]=0x65
73 pt[100]=0x6e; pt[101]=0x20; pt[102]=0x77; pt[103]=0x6f
74 pt[104]=0x75; pt[105]=0x6c; pt[106]=0x64; pt[107]=0x20
75 pt[108]=0x62; pt[109]=0x65; pt[110]=0x20; pt[111]=0x69
76 pt[112]=0x74; pt[113]=0x2e
77
78 let ct: *u8 = sys_mmap(256)
79 let tag: *u8 = sys_mmap(32)
80 let v: i64 = nx_chacha20_poly1305_encrypt(
81 key, nonce, aad, 12, pt, 114, ct, tag
82 )
83 if v != NX_AEAD_VERDICT_OK { return 1 }
84
85 // ---- Ciphertext first 32 bytes ----
86 if (ct[0] & 0xff) != 0xd3 { return 2 }
87 if (ct[1] & 0xff) != 0x1a { return 3 }
88 if (ct[2] & 0xff) != 0x8d { return 4 }
89 if (ct[3] & 0xff) != 0x34 { return 5 }
90 if (ct[4] & 0xff) != 0x64 { return 6 }
91 if (ct[5] & 0xff) != 0x8e { return 7 }
92 if (ct[6] & 0xff) != 0x60 { return 8 }
93 if (ct[7] & 0xff) != 0xdb { return 9 }
94 if (ct[8] & 0xff) != 0x7b { return 10 }
95 if (ct[9] & 0xff) != 0x86 { return 11 }
96 if (ct[10] & 0xff) != 0xaf { return 12 }
97 if (ct[11] & 0xff) != 0xbc { return 13 }
98 if (ct[12] & 0xff) != 0x53 { return 14 }
99 if (ct[13] & 0xff) != 0xef { return 15 }
100 if (ct[14] & 0xff) != 0x7e { return 16 }
101 if (ct[15] & 0xff) != 0xc2 { return 17 }
102 if (ct[16] & 0xff) != 0xa4 { return 18 }
103 if (ct[17] & 0xff) != 0xad { return 19 }
104 if (ct[18] & 0xff) != 0xed { return 20 }
105 if (ct[19] & 0xff) != 0x51 { return 21 }
106 if (ct[20] & 0xff) != 0x29 { return 22 }
107 if (ct[21] & 0xff) != 0x6e { return 23 }
108 if (ct[22] & 0xff) != 0x08 { return 24 }
109 if (ct[23] & 0xff) != 0xfe { return 25 }
110 if (ct[24] & 0xff) != 0xa9 { return 26 }
111 if (ct[25] & 0xff) != 0xe2 { return 27 }
112 if (ct[26] & 0xff) != 0xb5 { return 28 }
113 if (ct[27] & 0xff) != 0xa7 { return 29 }
114 if (ct[28] & 0xff) != 0x36 { return 30 }
115 if (ct[29] & 0xff) != 0xee { return 31 }
116 if (ct[30] & 0xff) != 0x62 { return 32 }
117 if (ct[31] & 0xff) != 0xd6 { return 33 }
118
119 // ---- Last two ciphertext bytes (partial-final-block sanity) ----
120 if (ct[112] & 0xff) != 0x61 { return 40 }
121 if (ct[113] & 0xff) != 0x16 { return 41 }
122
123 // ---- Tag: all 16 bytes ----
124 if (tag[0] & 0xff) != 0x1a { return 50 }
125 if (tag[1] & 0xff) != 0xe1 { return 51 }
126 if (tag[2] & 0xff) != 0x0b { return 52 }
127 if (tag[3] & 0xff) != 0x59 { return 53 }
128 if (tag[4] & 0xff) != 0x4f { return 54 }
129 if (tag[5] & 0xff) != 0x09 { return 55 }
130 if (tag[6] & 0xff) != 0xe2 { return 56 }
131 if (tag[7] & 0xff) != 0x6a { return 57 }
132 if (tag[8] & 0xff) != 0x7e { return 58 }
133 if (tag[9] & 0xff) != 0x90 { return 59 }
134 if (tag[10] & 0xff) != 0x2e { return 60 }
135 if (tag[11] & 0xff) != 0xcb { return 61 }
136 if (tag[12] & 0xff) != 0xd0 { return 62 }
137 if (tag[13] & 0xff) != 0x60 { return 63 }
138 if (tag[14] & 0xff) != 0x06 { return 64 }
139 if (tag[15] & 0xff) != 0x91 { return 65 }
140
141 // ---- Round-trip: decrypt(encrypt(pt)) == pt ----
142 let pt2: *u8 = sys_mmap(256)
143 let v2: i64 = nx_chacha20_poly1305_decrypt(
144 key, nonce, aad, 12, ct, 114, tag, pt2
145 )
146 if v2 != NX_AEAD_VERDICT_OK { return 70 }
147 var r: i64 = 0
148 while r < 114 {
149 if (pt[r] & 0xff) != (pt2[r] & 0xff) { return 80 + r }
150 r = r + 1
151 }
152
153 // ---- Tampered tag (flip 1 bit) -> TAG_MISMATCH, no decrypt ----
154 let bad_tag: *u8 = sys_mmap(32)
155 var bt: i64 = 0
156 while bt < 16 {
157 bad_tag[bt] = tag[bt]
158 bt = bt + 1
159 }
160 bad_tag[5] = bad_tag[5] ^ 1
161 let v3: i64 = nx_chacha20_poly1305_decrypt(
162 key, nonce, aad, 12, ct, 114, bad_tag, pt2
163 )
164 if v3 != NX_AEAD_VERDICT_TAG_MISMATCH { return 220 }
165
166 // ---- Tampered ciphertext (flip 1 bit) -> TAG_MISMATCH ----
167 let bad_ct: *u8 = sys_mmap(256)
168 var bc: i64 = 0
169 while bc < 114 {
170 bad_ct[bc] = ct[bc]
171 bc = bc + 1
172 }
173 bad_ct[33] = bad_ct[33] ^ 0x80
174 let v4: i64 = nx_chacha20_poly1305_decrypt(
175 key, nonce, aad, 12, bad_ct, 114, tag, pt2
176 )
177 if v4 != NX_AEAD_VERDICT_TAG_MISMATCH { return 221 }
178
179 // ---- Verdict gate ----
180 if nx_aead_verdict_is_valid(NX_AEAD_VERDICT_OK) != 1 { return 230 }
181 if nx_aead_verdict_is_valid(NX_AEAD_VERDICT_N) != 0 { return 231 }
182 if nx_aead_verdict_is_valid(0 - 1) != 0 { return 232 }
183
184 return 0
185}