nx_mse_keys.nx source
↩ module page · 83 lines · 5666 B
1// nx_mse_keys.nx -- MSE/PE key derivation: turn the DH shared secret S + info_hash SKEY into the two RC4
2// channel keys, per the MSE spec. keyA = SHA1("keyA" | S | SKEY) drives the INITIATOR->receiver stream;
3// keyB = SHA1("keyB" | S | SKEY) drives receiver->initiator. Each RC4 stream discards its first 1024 bytes.
4// Also derives the handshake sync hashes: HASH("req1",S), HASH("req2",SKEY), HASH("req3",S). Composes
5// nx_mse_dh (DH) + nx_rc4 (cipher) + nx_sha1 (HASH). This is the crypto glue between DH and the wire handshake.
6//
7// nx_mse_keys -- no-arg = GATE: real DH secret -> keyA/keyB -> bidirectional RC4 channels round-trip; VC ok.
8// license_tier: ORIGINAL module: nishi-core.torrent.mse_keys depends: mse_dh, rc4, sha1
9import "nx_mse_dh.nx"
10import "nx_rc4.nx"
11import "nx_sha1.nx"
12const K_MAGIC_1024: i64 = 1024
13
14// derive a 20-byte MSE key = SHA1(prefix(3) | S(96) | SKEY(20)) into out20.
15func mk_derive(prefix: *u8, s_bytes: *u8, skey: *u8, out20: *u8) -> i64 {
16 let buf: *u8 = sys_mmap(160); var o: i64 = 0
17 var i: i64 = 0; while i < 4 { if prefix[i]==(0 as u8) { i=4 } else { buf[o]=prefix[i]; o=o+1; i=i+1 } } // "keyA"/"keyB"/"req1"...
18 i = 0; while i < 96 { buf[o]=s_bytes[i]; o=o+1; i=i+1 }
19 i = 0; while i < 20 { buf[o]=skey[i]; o=o+1; i=i+1 }
20 sha1(buf, o, out20)
21 return 0
22}
23// SHA1(prefix | data(dlen)) -- for req1/req3 (over S) and req2 (over SKEY).
24func mk_hash_pref(prefix: *u8, data: *u8, dlen: i64, out20: *u8) -> i64 {
25 let buf: *u8 = sys_mmap(dlen + 16); var o: i64 = 0
26 var i: i64 = 0; while i < 4 { if prefix[i]==(0 as u8) { i=4 } else { buf[o]=prefix[i]; o=o+1; i=i+1 } }
27 i = 0; while i < dlen { buf[o]=data[i]; o=o+1; i=i+1 }
28 sha1(buf, o, out20)
29 return 0
30}
31
32func mk_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 }
33
34func main() -> i64 {
35 md_p("MSE-KEYS-GATE authored=organ\n" as *u8)
36 // 1. real DH shared secret S (both sides agree; reuse mse_dh)
37 let p: *i64 = sys_mmap((MSE_N+2)*8) as *i64; md_load_p(p)
38 let xa: *i64 = sys_mmap((MSE_N+2)*8) as *i64; bi_zero(xa, MSE_N); xa[0]=0x1234567; xa[1]=0x89abcde; xa[2]=0xf011223
39 let xb: *i64 = sys_mmap((MSE_N+2)*8) as *i64; bi_zero(xb, MSE_N); xb[0]=0x7fedcba; xb[1]=0x0987654; xb[2]=0x3210fed
40 let ya: *i64 = sys_mmap((MSE_N+2)*8) as *i64; let yb: *i64 = sys_mmap((MSE_N+2)*8) as *i64
41 let sA: *i64 = sys_mmap((MSE_N+2)*8) as *i64; let sB: *i64 = sys_mmap((MSE_N+2)*8) as *i64
42 mse_dh_public(xa, p, ya); mse_dh_public(xb, p, yb)
43 mse_dh_shared(yb, xa, p, sA); mse_dh_shared(ya, xb, p, sB)
44 let s_agree: i64 = md_eq(sA, sB, MSE_N)
45 // S as 96 big-endian bytes (both sides compute the same)
46 let sbytes: *u8 = sys_mmap(128); bi_to_bytes_be(sbytes, 96, sA, MSE_N)
47 // 2. SKEY = a torrent info_hash (20 bytes, fixed for the gate)
48 let skey: *u8 = sys_mmap(24); var i: i64=0; while i<20 { skey[i]=(0x40+i) as u8; i=i+1 }
49 // 3. derive keyA / keyB
50 let keyA: *u8 = sys_mmap(24); let keyB: *u8 = sys_mmap(24)
51 mk_derive("keyA" as *u8, sbytes, skey, keyA)
52 mk_derive("keyB" as *u8, sbytes, skey, keyB)
53 var keys_differ: i64=0; if mk_eq(keyA, keyB, 20)==0 { keys_differ=1 }
54 // 4. A->B channel (keyA): A encrypts, B decrypts -> plaintext back
55 let SAe: *u8 = sys_mmap(256); let ijAe: *i64 = sys_mmap(16) as *i64; ijAe[0]=0; ijAe[1]=0
56 let SBd: *u8 = sys_mmap(256); let ijBd: *i64 = sys_mmap(16) as *i64; ijBd[0]=0; ijBd[1]=0
57 rc4_ksa(SAe, keyA, 20); rc4_skip(SAe, ijAe, K_MAGIC_1024)
58 rc4_ksa(SBd, keyA, 20); rc4_skip(SBd, ijBd, K_MAGIC_1024)
59 let msg: *u8 = sys_mmap(32); var m: i64=0; while m<16 { msg[m]=(0x61+m) as u8; m=m+1 } // "abc..."
60 let orig: *u8 = sys_mmap(32); m=0; while m<16 { orig[m]=msg[m]; m=m+1 }
61 rc4_crypt(SAe, ijAe, msg, 16) // A encrypts
62 var ct_differs: i64=0; if mk_eq(msg, orig, 16)==0 { ct_differs=1 } // ciphertext != plaintext (really encrypted)
63 rc4_crypt(SBd, ijBd, msg, 16) // B decrypts
64 let ab_ok: i64 = mk_eq(msg, orig, 16)
65 // 5. B->A channel (keyB): VC (8 zero bytes) round-trips
66 let SBe: *u8 = sys_mmap(256); let ijBe: *i64 = sys_mmap(16) as *i64; ijBe[0]=0; ijBe[1]=0
67 let SAd: *u8 = sys_mmap(256); let ijAd: *i64 = sys_mmap(16) as *i64; ijAd[0]=0; ijAd[1]=0
68 rc4_ksa(SBe, keyB, 20); rc4_skip(SBe, ijBe, K_MAGIC_1024)
69 rc4_ksa(SAd, keyB, 20); rc4_skip(SAd, ijAd, K_MAGIC_1024)
70 let vc: *u8 = sys_mmap(16); m=0; while m<8 { vc[m]=0 as u8; m=m+1 }
71 rc4_crypt(SBe, ijBe, vc, 8); rc4_crypt(SAd, ijAd, vc, 8)
72 var vc_ok: i64=1; m=0; while m<8 { if vc[m]!=(0 as u8) { vc_ok=0; m=8 } else { m=m+1 } }
73 // 6. handshake sync hashes exist + differ (req1 over S, req2 over SKEY)
74 let h1: *u8 = sys_mmap(24); let h2: *u8 = sys_mmap(24); mk_hash_pref("req1" as *u8, sbytes, 96, h1); mk_hash_pref("req2" as *u8, skey, 20, h2)
75 var hashes_ok: i64=0; if mk_eq(h1,h2,20)==0 { hashes_ok=1 }
76 md_p(" dh_agree=" as *u8); md_p(if_s(s_agree)); md_p(" keyA!=keyB=" as *u8); md_p(if_s(keys_differ))
77 md_p(" ciphertext_encrypted=" as *u8); md_p(if_s(ct_differs)); md_p(" A->B_roundtrip=" as *u8); md_p(if_s(ab_ok))
78 md_p(" VC_roundtrip=" as *u8); md_p(if_s(vc_ok)); md_p(" req_hashes=" as *u8); md_p(if_s(hashes_ok)); md_p("\n" as *u8)
79 var allok: i64=0
80 if s_agree==1 { if keys_differ==1 { if ct_differs==1 { if ab_ok==1 { if vc_ok==1 { if hashes_ok==1 { allok=1 } } } } } }
81 if allok==1 { md_p("MSE-KEYS-GATE verdict=GREEN (DH->keyA/keyB->bidirectional RC4 channels + VC + req-hashes)\n" as *u8); sys_exit(0); return 0 }
82 md_p("MSE-KEYS-GATE verdict=RED\n" as *u8); sys_exit(1); return 1
83}