nx_quic_aead.nx source
↩ module page · 55 lines · 2633 B
1// nx_quic_aead.nx -- RUNG 5b of the sovereign QUIC transport: AEAD packet protection (RFC 9001 sec 5.3)
2// + header protection (sec 5.4). The QUIC nonce is iv XOR the left-padded packet number; the packet
3// payload is sealed with AES-128-GCM (aad = the header); the header's low first-byte bits + the packet
4// number bytes are masked with AES-ECB(hp_key, ciphertext-sample). With R5a's keys this makes a handshake
5// packet indistinguishable on the wire. Reuses the GCM module's own AES (no second cipher). No float.
6// license_tier: ORIGINAL
7import "nx_aes128_gcm.nx"
8
9// QUIC AEAD nonce (RFC 9001 sec 5.3): the 62-bit packet number, left-padded to 12 bytes, XOR the iv.
10func quic_nonce(iv12: *u8, pn: i64, nonce_out: *u8) -> i64 {
11 var i: i64 = 0
12 while i < 12 { nonce_out[i] = iv12[i]; i = i + 1 }
13 var p: i64 = pn
14 var j: i64 = 11
15 while j >= 4 {
16 nonce_out[j] = ((nonce_out[j] as i64) ^ (p & 0xff)) as u8
17 p = p >> 8
18 j = j - 1
19 }
20 return 0
21}
22
23// header-protection mask = AES-ECB(hp_key, 16-byte ciphertext sample). caller uses mask[0] + mask[1..pn_len].
24func quic_hp_mask(hp_key: *u8, sample: *u8, mask_out: *u8) -> i64 {
25 let sched: *u8 = sys_mmap(176)
26 aes128_expand_key(hp_key, sched)
27 aes128_encrypt_block(sample, sched, mask_out)
28 return 0
29}
30
31// seal the payload: nonce(iv,pn) then AES-128-GCM(key, nonce, aad=header, pt) -> ct_out + tag16_out.
32func quic_seal(key: *u8, iv: *u8, pn: i64, aad: *u8, aad_len: i64, pt: *u8, pt_len: i64, ct_out: *u8, tag_out: *u8) -> i64 {
33 let nonce: *u8 = sys_mmap(12)
34 quic_nonce(iv, pn, nonce)
35 return nx_aes128_gcm_seal(key, nonce, aad, aad_len, pt, pt_len, ct_out, tag_out)
36}
37// open: nonce(iv,pn) then AES-128-GCM-open. returns the underlying open rc (0 = tag verified).
38func quic_open(key: *u8, iv: *u8, pn: i64, aad: *u8, aad_len: i64, ct: *u8, ct_len: i64, tag: *u8, pt_out: *u8) -> i64 {
39 let nonce: *u8 = sys_mmap(12)
40 quic_nonce(iv, pn, nonce)
41 return nx_aes128_gcm_open(key, nonce, aad, aad_len, ct, ct_len, tag, pt_out)
42}
43
44// apply OR remove header protection (XOR is symmetric). long_hdr=1 -> mask low 4 bits of first byte (0x0f);
45// short header masks 5 bits (0x1f). pn bytes get mask[1..pn_len].
46func quic_hp_apply(hdr: *u8, pn_off: i64, pn_len: i64, mask: *u8, long_hdr: i64) -> i64 {
47 var lowmask: i64 = 0x1f
48 if long_hdr == 1 { lowmask = 0x0f }
49 hdr[0] = ((hdr[0] as i64) ^ ((mask[0] as i64) & lowmask)) as u8
50 var i: i64 = 0
51 while i < pn_len { hdr[pn_off + i] = ((hdr[pn_off + i] as i64) ^ (mask[1 + i] as i64)) as u8; i = i + 1 }
52 return 0
53}
54
55func main() -> i64 { return 0 }