code wiki / _hdl_build / nx_tor_aes.nx
nx_tor_aes.nx source
↩ module page · 53 lines · 2746 B
1// nx_tor_aes.nx -- AES-128-CTR for the Tor RELAY-cell cipher (tor-spec sec.5.5). THIN wrapper over the
2// existing FIPS-197 AES-128 core (nx_aes.nx): the ONLY difference from nx_aes_ctr.nx is a FULL 128-bit
3// big-endian counter increment (OpenSSL/Tor semantics) instead of the 32-bit low-word increment -- Tor's
4// relay cipher is a CONTINUOUS keystream across many cells, so (a) the counter must carry past byte 12,
5// and (b) it must advance every block INCLUDING the last so the next call/cell resumes at the right block.
6// IV for relay use = 16 zero bytes; the per-hop key Kf/Kb comes from the ntor KDF (Phase 1).
7//
8// Reuses aes128_expand_key + aes128_encrypt_block; no new cipher. Gated vs NIST SP 800-38A F.5.1/F.5.2.
9// license_tier: ORIGINAL
10import "nx_syscalls.nx"
11import "nx_aes.nx" // aes128_expand_key, aes128_encrypt_block, AES_BLOCK, AES_EXP_LEN
12
13// Full 128-bit big-endian counter increment (carries across the whole block; OpenSSL AES-CTR semantics).
14func tor_ctr_inc128(ctr: *u8) -> i64 {
15 var i: i64 = 15
16 while i >= 0 {
17 let b: i64 = (ctr[i] as i64) & 0xff
18 if b == 255 { ctr[i] = 0 as u8; i = i - 1 } else { ctr[i] = (b + 1) as u8; return 0 }
19 }
20 return 0 // full wrap 0xff..ff -> 0x00..00 (2^128 blocks; never reached in practice)
21}
22
23// AES-128-CTR crypt (symmetric: encrypt == decrypt). sched = 176-byte expanded key; ctr16 = 16-byte counter
24// block, ADVANCED IN PLACE so a subsequent call continues the same keystream (the Tor relay pattern).
25func tor_aes128_ctr_crypt(sched: *u8, ctr16: *u8, in_buf: *u8, in_len: i64, out_buf: *u8) -> i64 {
26 if in_len <= 0 { return 0 }
27 let ks: *u8 = sys_mmap(32)
28 var off: i64 = 0
29 while off < in_len {
30 aes128_encrypt_block(ctr16, sched, ks)
31 var take: i64 = in_len - off
32 if take > AES_BLOCK { take = AES_BLOCK }
33 var i: i64 = 0
34 while i < take {
35 let pin: *u8 = (in_buf as i64 + off + i) as *u8
36 let pout: *u8 = (out_buf as i64 + off + i) as *u8
37 pout[0] = (((pin[0] as i64) & 0xff) ^ ((ks[i] as i64) & 0xff)) as u8
38 i = i + 1
39 }
40 off = off + take
41 tor_ctr_inc128(ctr16) // advance EVERY block (incl. partial/last) -- continuous-stream correctness
42 }
43 return in_len
44}
45
46// Convenience one-shot: expand key16, seed a fresh counter from iv16, crypt. Tor relay use: iv16 = 16 zeros.
47func tor_aes128_ctr(key16: *u8, iv16: *u8, in_buf: *u8, in_len: i64, out_buf: *u8) -> i64 {
48 let sched: *u8 = sys_mmap(AES_EXP_LEN + 16)
49 aes128_expand_key(key16, sched)
50 let ctr: *u8 = sys_mmap(16)
51 var i: i64 = 0; while i < 16 { ctr[i] = iv16[i]; i = i + 1 }
52 return tor_aes128_ctr_crypt(sched, ctr, in_buf, in_len, out_buf)
53}