code wiki / _hdl_build / nx_tor_relay_gate.nx

nx_tor_relay_gate.nx source

↩ module page · 139 lines · 10537 B

1// nx_tor_relay_gate.nx -- STRUCTURAL gate for Tor circuit/onion cells (tor-spec sec.5.1/5.1.2/6.1). Wraps a 2// REAL Phase-1 ntor onion skin (nx_tor_ntor) into CREATE2; exercises CREATED2, the RELAY cell + running 3// digest + recognized field, single- and two-hop AES-128-CTR onion (de)cryption, and EXTEND2/EXTENDED2. 4// No live Tor (zero external calls); anon_is_anonymizing() stays 0. license_tier: ORIGINAL expect_exit: 0 5import "nx_syscalls.nx" 6import "nx_tor_cell.nx" 7import "nx_tor_relay.nx" 8import "nx_x25519_ephemeral.nx" 9import "nx_tor_ntor.nx" 10 11func g_w(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } 12func g_n(v: i64) -> i64 { var m: i64=v; if m<0{g_w("-" 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} let o:*u8=sys_mmap(24); var i:i64=0; while i<k{o[i]=t[k-1-i];i=i+1} sys_write(1,o,k); return 0 } 13func g_fw(fd: i64, s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(fd,s,n); return 0 } 14func g_fn(fd: i64, v: i64) -> i64 { var m: i64=v; 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} let o:*u8=sys_mmap(24); var i:i64=0; while i<k{o[i]=t[k-1-i];i=i+1} sys_write(fd,o,k); return 0 } 15func g_row(id: *u8, ok: i64, pass: *i64, tot: *i64) -> i64 { tot[0]=tot[0]+1; g_w(" " as *u8); g_w(id); if ok==1 { g_w(": OK\n" as *u8); pass[0]=pass[0]+1 } else { g_w(": FAIL\n" as *u8) } return 0 } 16func g_eq(a: *u8, b: *u8, n: i64) -> i64 { var i: i64=0; while i<n { if a[i]!=b[i] { return 0 } i=i+1 } return 1 } 17 18func main() -> i64 { 19 let pass: *i64 = sys_mmap(8) as *i64; pass[0]=0 20 let tot: *i64 = sys_mmap(8) as *i64; tot[0]=0 21 g_w("=== NX-TOR-RELAY GATE (CREATE2/CREATED2 + RELAY digest/onion + EXTEND2, structural) ===\n" as *u8) 22 23 // ---- build a REAL Phase-1 ntor skin + Y|AUTH ---- 24 let id: *u8 = sys_mmap(20); var ii: i64=0; while ii<20 { id[ii]=ii as u8; ii=ii+1 } 25 let bpriv: *u8 = sys_mmap(32) 26 bpriv[0]=0x5d;bpriv[1]=0xab;bpriv[2]=0x08;bpriv[3]=0x7e;bpriv[4]=0x62;bpriv[5]=0x4a;bpriv[6]=0x8a;bpriv[7]=0x4b;bpriv[8]=0x79;bpriv[9]=0xe1;bpriv[10]=0x7f;bpriv[11]=0x8b;bpriv[12]=0x83;bpriv[13]=0x80;bpriv[14]=0x0e;bpriv[15]=0xe6;bpriv[16]=0x6f;bpriv[17]=0x3b;bpriv[18]=0xb1;bpriv[19]=0x29;bpriv[20]=0x26;bpriv[21]=0x18;bpriv[22]=0xb6;bpriv[23]=0xfd;bpriv[24]=0x1c;bpriv[25]=0x2f;bpriv[26]=0x8b;bpriv[27]=0x27;bpriv[28]=0xff;bpriv[29]=0x88;bpriv[30]=0xe0;bpriv[31]=0xeb 27 let bpub: *u8 = sys_mmap(32); x25519_keypair_public(bpriv, bpub) 28 let xpriv: *u8 = sys_mmap(32) 29 xpriv[0]=0x77;xpriv[1]=0x07;xpriv[2]=0x6d;xpriv[3]=0x0a;xpriv[4]=0x73;xpriv[5]=0x18;xpriv[6]=0xa5;xpriv[7]=0x7d;xpriv[8]=0x3c;xpriv[9]=0x16;xpriv[10]=0xc1;xpriv[11]=0x72;xpriv[12]=0x51;xpriv[13]=0xb2;xpriv[14]=0x66;xpriv[15]=0x45;xpriv[16]=0xdf;xpriv[17]=0x4c;xpriv[18]=0x2f;xpriv[19]=0x87;xpriv[20]=0xeb;xpriv[21]=0xc0;xpriv[22]=0x99;xpriv[23]=0x2a;xpriv[24]=0xb1;xpriv[25]=0x77;xpriv[26]=0xfb;xpriv[27]=0xa5;xpriv[28]=0x1d;xpriv[29]=0xb9;xpriv[30]=0x2c;xpriv[31]=0x2a 30 let ypriv: *u8 = sys_mmap(32); var yi: i64=0; while yi<32 { ypriv[yi]=(0x40+yi) as u8; yi=yi+1 } 31 let xpub: *u8 = sys_mmap(32); let skin: *u8 = sys_mmap(128) 32 let skinlen: i64 = ntor_client_init(id, bpub, xpriv, xpub, skin) // 84 = ID|B|X 33 let ypub: *u8 = sys_mmap(32); let auth: *u8 = sys_mmap(32); let keys: *u8 = sys_mmap(96) 34 ntor_server_respond(id, bpub, bpriv, xpub, ypriv, ypub, auth, keys) 35 let yauth: *u8 = sys_mmap(64); var qi: i64=0; while qi<32 { yauth[qi]=ypub[qi]; qi=qi+1 } qi=0; while qi<32 { yauth[32+qi]=auth[qi]; qi=qi+1 } 36 37 // RR1 CREATE2 wraps the ntor skin: HTYPE=0x0002, HLEN=0x0054(84) 38 let c2: *u8 = sys_mmap(600); let c2len: i64 = tor_build_create2(TOR_HTYPE_NTOR, skin, skinlen, c2) 39 var rr1: i64=1 40 if skinlen!=84 { rr1=0 } 41 if (c2[0]&0xff)!=0x00 { rr1=0 } if (c2[1]&0xff)!=0x02 { rr1=0 } // HTYPE ntor 42 if (c2[2]&0xff)!=0x00 { rr1=0 } if (c2[3]&0xff)!=0x54 { rr1=0 } // HLEN 84 43 if c2len!=88 { rr1=0 } 44 if g_eq((c2 as i64 + 4) as *u8, skin, 84)!=1 { rr1=0 } 45 let ht: *i64 = sys_mmap(8) as *i64; let hl: *i64 = sys_mmap(8) as *i64; let ho: *i64 = sys_mmap(8) as *i64 46 if tor_parse_create2(c2, c2len, ht, hl, ho)!=0 { rr1=0 } 47 if ht[0]!=2 { rr1=0 } if hl[0]!=84 { rr1=0 } if ho[0]!=4 { rr1=0 } 48 // full fixed cell (cmd=CREATE2=10, CircID 4) -> 514B 49 let cell: *u8 = sys_mmap(600); let clen: i64 = tc_build_fixed(1, TCELL_CREATE2, c2, c2len, 4, cell) 50 if clen!=514 { rr1=0 } if (cell[4]&0xff)!=10 { rr1=0 } 51 g_row("RR1 CREATE2 wraps real ntor skin (HTYPE=2 HLEN=84) + 514B fixed cell + parse" as *u8, rr1, pass, tot) 52 53 // RR2 CREATED2 wraps Y|AUTH (64): HLEN=0x0040 54 let cd: *u8 = sys_mmap(128); let cdlen: i64 = tor_build_created2(yauth, 64, cd) 55 var rr2: i64=1 56 if (cd[0]&0xff)!=0x00 { rr2=0 } if (cd[1]&0xff)!=0x40 { rr2=0 } if cdlen!=66 { rr2=0 } 57 let hl2: *i64 = sys_mmap(8) as *i64; let ho2: *i64 = sys_mmap(8) as *i64 58 if tor_parse_created2(cd, cdlen, hl2, ho2)!=0 { rr2=0 } if hl2[0]!=64 { rr2=0 } 59 if g_eq((cd as i64 + ho2[0]) as *u8, yauth, 64)!=1 { rr2=0 } 60 g_row("RR2 CREATED2 wraps ntor Y|AUTH (HLEN=64) + parse round-trip" as *u8, rr2, pass, tot) 61 62 // RR3 RELAY cell build + digest recognized 63 let df: *u8 = sys_mmap(20); var di: i64=0; while di<20 { df[di]=(0x33+di) as u8; di=di+1 } 64 let data: *u8 = "NISHI-RELAY" as *u8 65 let P: *u8 = sys_mmap(600); tor_relay_build(TOR_RELAY_DATA, 1, data, 11, df, P) 66 var rr3: i64=1 67 if (P[0]&0xff)!=2 { rr3=0 } // relay_cmd = RELAY_DATA 68 if tc_get_u16(P, 1)!=0 { rr3=0 } // Recognized = 0 69 if tc_get_u16(P, 3)!=1 { rr3=0 } // StreamID = 1 70 if tc_get_u16(P, 9)!=11 { rr3=0 } // Length = 11 71 if g_eq((P as i64 + 11) as *u8, data, 11)!=1 { rr3=0 } 72 if tor_relay_recognized(P, df)!=1 { rr3=0 } // digest verifies 73 g_row("RR3 RELAY cell build + running-digest recognized (cmd/streamid/len/data)" as *u8, rr3, pass, tot) 74 75 // RR4 single-hop onion round-trip 76 let k1: *u8 = sys_mmap(16); var ki: i64=0; while ki<16 { k1[ki]=0x11 as u8; ki=ki+1 } 77 let enc1: *u8 = sys_mmap(600); tor_onion_crypt(k1, P, enc1) 78 let dec1: *u8 = sys_mmap(600); tor_onion_crypt(k1, enc1, dec1) 79 var rr4: i64=1 80 if tor_relay_recognized(enc1, df)!=0 { rr4=0 } // encrypted -> NOT recognized 81 if g_eq(dec1, P, 509)!=1 { rr4=0 } // decrypt recovers 82 if tor_relay_recognized(dec1, df)!=1 { rr4=0 } // decrypted -> recognized 83 g_row("RR4 single-hop onion round-trip (enc hides recognized; dec restores it)" as *u8, rr4, pass, tot) 84 85 // RR5 two-hop layered onion: OP sends onion(k1, onion(k2, P)) 86 let k2: *u8 = sys_mmap(16); ki=0; while ki<16 { k2[ki]=0x22 as u8; ki=ki+1 } 87 let inner: *u8 = sys_mmap(600); tor_onion_crypt(k2, P, inner) // layer for hop2 88 let outer: *u8 = sys_mmap(600); tor_onion_crypt(k1, inner, outer) // layer for hop1 (what OP sends) 89 let h1: *u8 = sys_mmap(600); tor_onion_crypt(k1, outer, h1) // hop1 peels its layer -> == inner 90 let h2: *u8 = sys_mmap(600); tor_onion_crypt(k2, h1, h2) // hop2 peels its layer -> == P 91 var rr5: i64=1 92 if g_eq(h1, inner, 509)!=1 { rr5=0 } 93 if tor_relay_recognized(h1, df)!=0 { rr5=0 } // hop1: still encrypted -> forward 94 if g_eq(h2, P, 509)!=1 { rr5=0 } 95 if tor_relay_recognized(h2, df)!=1 { rr5=0 } // hop2: target -> recognized 96 g_row("RR5 two-hop layered onion (hop1 forwards, hop2 recognizes) + AES-CTR peel" as *u8, rr5, pass, tot) 97 98 // RR6 EXTEND2 build (2 link specs: IPv4 + legacy ID) + nested ntor skin 99 let specs: *u8 = sys_mmap(64); var so: i64=0 100 let ip: *u8 = sys_mmap(4); ip[0]=0x7f; ip[1]=0x00; ip[2]=0x00; ip[3]=0x01 101 so = so + tor_ls_ipv4(ip, 9001, (specs as i64 + so) as *u8) 102 so = so + tor_ls_legacy_id(id, (specs as i64 + so) as *u8) 103 let ex: *u8 = sys_mmap(600); let exlen: i64 = tor_build_extend2(2, specs, so, TOR_HTYPE_NTOR, skin, 84, ex) 104 var rr6: i64=1 105 if (ex[0]&0xff)!=2 { rr6=0 } // NSPEC = 2 106 if (ex[1]&0xff)!=0 { rr6=0 } if (ex[2]&0xff)!=6 { rr6=0 } // first spec: type 0 (IPv4), len 6 107 let en: *i64 = sys_mmap(8) as *i64; let eht: *i64 = sys_mmap(8) as *i64; let ehl: *i64 = sys_mmap(8) as *i64; let eho: *i64 = sys_mmap(8) as *i64 108 if tor_parse_extend2(ex, exlen, en, eht, ehl, eho)!=0 { rr6=0 } 109 if en[0]!=2 { rr6=0 } if eht[0]!=2 { rr6=0 } if ehl[0]!=84 { rr6=0 } 110 if g_eq((ex as i64 + eho[0]) as *u8, skin, 84)!=1 { rr6=0 } // nested skin recovered 111 g_row("RR6 EXTEND2 build/parse (2 link-specs + nested ntor skin for next hop)" as *u8, rr6, pass, tot) 112 113 // RR7 EXTENDED2 (CREATED2 format) round-trip 114 let e2: *u8 = sys_mmap(128); let e2len: i64 = tor_build_created2(yauth, 64, e2) 115 let ehl2: *i64 = sys_mmap(8) as *i64; let eho2: *i64 = sys_mmap(8) as *i64 116 var rr7: i64=0; if tor_parse_created2(e2, e2len, ehl2, eho2)==0 { if ehl2[0]==64 { if g_eq((e2 as i64+eho2[0]) as *u8, yauth, 64)==1 { rr7=1 } } } 117 g_row("RR7 EXTENDED2 (HLEN|Y|AUTH) round-trip" as *u8, rr7, pass, tot) 118 119 // RR8 negative: tamper a data byte -> digest fails recognized 120 let Pt: *u8 = sys_mmap(600); var pj: i64=0; while pj<509 { Pt[pj]=P[pj]; pj=pj+1 } 121 Pt[11] = (Pt[11] ^ 1) as u8 122 var rr8: i64=0; if tor_relay_recognized(Pt, df)==0 { rr8=1 } 123 g_row("RR8 tampered RELAY data -> digest mismatch -> NOT recognized" as *u8, rr8, pass, tot) 124 125 // RR9 negative: recognized field != 0 -> not recognized 126 let Pr: *u8 = sys_mmap(600); pj=0; while pj<509 { Pr[pj]=P[pj]; pj=pj+1 } 127 tc_put_u16(Pr, 1, 1) // Recognized = 0x0001 128 var rr9: i64=0; if tor_relay_recognized(Pr, df)==0 { rr9=1 } 129 g_row("RR9 Recognized field != 0 -> NOT recognized" as *u8, rr9, pass, tot) 130 131 g_w("TOR-RELAY-GATE rows=" as *u8); g_n(tot[0]); g_w(" pass=" as *u8); g_n(pass[0]) 132 if pass[0]==tot[0] { 133 g_w(" verdict=GREEN\n" as *u8) 134 let lg: i64 = sys_openat_append("knowledge/status/tor_relay_gate.log" as *u8, 0x1a4) 135 if lg>=0 { g_fw(lg, "TOR-RELAY-GATE pass=" as *u8); g_fn(lg, pass[0]); g_fw(lg, "/" as *u8); g_fn(lg, tot[0]); g_fw(lg, " verdict=GREEN scope=CREATE2/CREATED2/RELAY-digest/onion-AES-CTR/EXTEND2-structural(NOT-live-tor) epoch=" as *u8); g_fn(lg, sys_now_realtime_sec()); g_fw(lg, "\n" as *u8); sys_close(lg) } 136 sys_exit(0); return 0 137 } 138 g_w(" verdict=RED\n" as *u8); sys_exit(1); return 1 139}