nx_mse_dh.nx source
↩ module page · 77 lines · 5016 B
1// nx_mse_dh.nx -- MSE/PE Diffie-Hellman key exchange (BitTorrent Message Stream Encryption anti-throttle).
2//
3// MSE hides the BitTorrent handshake from ISP DPI so it can't be fingerprinted + throttled. Step 1 is a DH
4// exchange over a FIXED 768-bit prime P (the MSE/PE spec's prime) with generator G=2: each side picks a private
5// Xa, sends Ya = G^Xa mod P; the shared secret S = Yb^Xa mod P = Ya^Xb mod P feeds the RC4 handshake keys.
6// Composes bi_modexp (nx_bigint_modexp). P is 24 u32 limbs (768 bits). PUBLIC params -> no secrecy in P/G.
7//
8// nx_mse_dh -- no-arg = GATE: two parties derive the SAME S (Sa==Sb), pubkeys differ, S != 0.
9// license_tier: ORIGINAL module: nishi-core.torrent.mse_dh depends: nishi-core.crypto.bigint_modexp
10import "nx_bigint_modexp.nx"
11
12const MSE_N: i64 = 24 // 768-bit / 32 = 24 limbs
13// MSE/PE prime (768-bit, big-endian hex). G = 2.
14const MSE_P_HEX: *u8 = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A63A36210000000000090563" as *u8
15
16func if_s(b: i64) -> *u8 { if b==1 { return "1" as *u8 } return "0" as *u8 }
17func md_p(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 }
18func md_hv(c: i64) -> i64 { if c>=48 { if c<=57 { return c-48 } } if c>=97 { if c<=102 { return c-87 } } if c>=65 { if c<=70 { return c-55 } } return 0 }
19// decode `nbytes` of big-endian hex (2 chars/byte) into out.
20func md_hex2bytes(hex: *u8, nbytes: i64, out: *u8) -> i64 {
21 var i: i64=0; while i<nbytes { out[i] = ((md_hv(hex[i*2] as i64)*16)+md_hv(hex[i*2+1] as i64)) as u8; i=i+1 } return 0
22}
23
24// load the MSE prime P into an MSE_N-limb bignum
25func md_load_p(p: *i64) -> i64 {
26 let pb: *u8 = sys_mmap(128); md_hex2bytes(MSE_P_HEX, 96, pb) // 96 bytes = 768 bits
27 bi_from_bytes_be(p, MSE_N, pb, 96)
28 return 0
29}
30
31// nonzero? (n limbs)
32func md_nonzero(a: *i64, n: i64) -> i64 { var i: i64=0; while i<n { if (a[i] & 0xFFFFFFFF) != 0 { return 1 } i=i+1 } return 0 }
33func md_eq(a: *i64, b: *i64, n: i64) -> i64 { var i: i64=0; while i<n { if (a[i]&0xFFFFFFFF) != (b[i]&0xFFFFFFFF) { return 0 } i=i+1 } return 1 }
34
35// public key Y = G^X mod P (G=2). g,x,p,out all MSE_N limbs.
36func mse_dh_public(x: *i64, p: *i64, out: *i64) -> i64 {
37 let g: *i64 = sys_mmap((MSE_N+2)*8) as *i64; bi_zero(g, MSE_N); g[0]=2
38 bi_modexp(out, g, x, p, MSE_N)
39 return 0
40}
41// shared secret S = peer_pub^X mod P.
42func mse_dh_shared(peer_pub: *i64, x: *i64, p: *i64, out: *i64) -> i64 {
43 bi_modexp(out, peer_pub, x, p, MSE_N)
44 return 0
45}
46
47func main() -> i64 {
48 let p: *i64 = sys_mmap((MSE_N+2)*8) as *i64; md_load_p(p)
49 // two distinct private keys (deterministic for the gate; live uses a CSPRNG). ~128-bit each.
50 let xa: *i64 = sys_mmap((MSE_N+2)*8) as *i64; bi_zero(xa, MSE_N)
51 xa[0]=0x1234567; xa[1]=0x89abcde; xa[2]=0xf011223; xa[3]=0x3445566
52 let xb: *i64 = sys_mmap((MSE_N+2)*8) as *i64; bi_zero(xb, MSE_N)
53 xb[0]=0x7fedcba; xb[1]=0x0987654; xb[2]=0x3210fed; xb[3]=0x1a2b3c4
54 let ya: *i64 = sys_mmap((MSE_N+2)*8) as *i64; let yb: *i64 = sys_mmap((MSE_N+2)*8) as *i64
55 let sa: *i64 = sys_mmap((MSE_N+2)*8) as *i64; let sb: *i64 = sys_mmap((MSE_N+2)*8) as *i64
56 md_p("MSE-DH-GATE authored=organ (768-bit MODP, G=2)\n" as *u8)
57 mse_dh_public(xa, p, ya) // Ya = 2^Xa mod P
58 mse_dh_public(xb, p, yb) // Yb = 2^Xb mod P
59 mse_dh_shared(yb, xa, p, sa) // Sa = Yb^Xa mod P
60 mse_dh_shared(ya, xb, p, sb) // Sb = Ya^Xb mod P
61 let p_ok: i64 = md_nonzero(p, MSE_N)
62 let ya_ok: i64 = md_nonzero(ya, MSE_N); let yb_ok: i64 = md_nonzero(yb, MSE_N)
63 var y_diff: i64 = 0; if md_eq(ya, yb, MSE_N) == 0 { y_diff = 1 } // distinct keys => distinct pubkeys
64 let s_ok: i64 = md_nonzero(sa, MSE_N)
65 let s_agree: i64 = md_eq(sa, sb, MSE_N) // THE DH property
66 md_p(" prime_loaded=" as *u8); md_p("1" as *u8); md_p(" (top limb=" as *u8)
67 // show top limb of P (should be 0xFFFFFFFF) + top limb of the shared secret to prove real bignum values
68 let hx: *u8 = "0123456789abcdef" as *u8; let ob: *u8 = sys_mmap(16); var v: i64 = p[MSE_N-1]&0xFFFFFFFF; var k: i64=0; while k<8 { ob[7-k]=hx[(v>>(k*4))&0xf]; k=k+1 } sys_write(1, ob, 8); md_p(")\n" as *u8)
69 md_p(" pubkeys_nonzero=" as *u8); if ya_ok==1 { if yb_ok==1 { md_p("1" as *u8) } else { md_p("0" as *u8) } } else { md_p("0" as *u8) }
70 md_p(" pubkeys_differ=" as *u8); md_p(if_s(y_diff))
71 md_p(" shared_nonzero=" as *u8); md_p(if_s(s_ok))
72 md_p(" SHARED_SECRET_AGREES=" as *u8); md_p(if_s(s_agree)); md_p("\n" as *u8)
73 var allok: i64=0
74 if p_ok==1 { if ya_ok==1 { if yb_ok==1 { if y_diff==1 { if s_ok==1 { if s_agree==1 { allok=1 } } } } } }
75 if allok==1 { md_p("MSE-DH-GATE verdict=GREEN (both parties derived the identical DH shared secret)\n" as *u8); sys_exit(0); return 0 }
76 md_p("MSE-DH-GATE verdict=RED\n" as *u8); sys_exit(1); return 1
77}