code wiki / (root) / nx_rc4.nx

nx_rc4.nx source

↩ module page · 74 lines · 4911 B

1// nx_rc4.nx -- RC4 stream cipher (the MSE/PE data cipher). KSA + PRGA, byte-at-a-time keystream. 2// 3// MSE/PE encrypts the peer stream with RC4 keyed from the DH shared secret + info_hash, DISCARDING the first 4// 1024 keystream bytes (drops RC4's biased prefix). This is the cipher half of the anti-throttle handshake. 5// RC4 is cryptographically weak in general -- here it is used ONLY as the wire-obfuscation MSE mandates for 6// interop with real BitTorrent peers (last-mile), NOT as a security primitive for our own data at rest. 7// 8// nx_rc4 -- no-arg = GATE (RFC/Wikipedia known-answer vectors) 9// license_tier: ORIGINAL module: nishi-core.crypto.rc4 depends: nishi-core.syscalls 10import "nx_syscalls.nx" 11const K_MAGIC_1024: i64 = 1024 12 13func r4_p(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } 14 15// Key-scheduling: init the 256-byte S-box from key. 16func rc4_ksa(S: *u8, key: *u8, keylen: i64) -> i64 { 17 var i: i64 = 0; while i < 256 { S[i] = i as u8; i = i + 1 } 18 var j: i64 = 0; i = 0 19 while i < 256 { 20 j = (j + (S[i] as i64) + (key[i % keylen] as i64)) & 0xff 21 let t: i64 = S[i] as i64; S[i] = S[j]; S[j] = t as u8 22 i = i + 1 23 } 24 return 0 25} 26// PRGA: produce one keystream byte; ij holds {i, j} across calls. 27func rc4_prga_byte(S: *u8, ij: *i64) -> i64 { 28 var i: i64 = ij[0]; var j: i64 = ij[1] 29 i = (i + 1) & 0xff 30 j = (j + (S[i] as i64)) & 0xff 31 let t: i64 = S[i] as i64; S[i] = S[j]; S[j] = t as u8 32 ij[0] = i; ij[1] = j 33 return S[((S[i] as i64) + (S[j] as i64)) & 0xff] as i64 34} 35// XOR n bytes of data with the keystream (encrypt == decrypt). 36func rc4_crypt(S: *u8, ij: *i64, data: *u8, n: i64) -> i64 { 37 var k: i64 = 0; while k < n { data[k] = ((data[k] as i64) ^ rc4_prga_byte(S, ij)) as u8; k = k + 1 } return 0 38} 39// discard n keystream bytes (MSE discards the first 1024). 40func rc4_skip(S: *u8, ij: *i64, n: i64) -> i64 { var k: i64 = 0; while k < n { rc4_prga_byte(S, ij); k = k + 1 } return 0 } 41 42func r4_hexval(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 } 43// run one KAT: key/pt (ascii), expected ct hex. returns 1 if the RC4 ciphertext matches. 44func r4_case(label: *u8, key: *u8, keylen: i64, pt: *u8, ptlen: i64, cthex: *u8, pass: *i64, tot: *i64) -> i64 { 45 let S: *u8 = sys_mmap(256); let ij: *i64 = sys_mmap(16) as *i64; ij[0]=0; ij[1]=0 46 let buf: *u8 = sys_mmap(ptlen + 8); var i: i64=0; while i<ptlen { buf[i]=pt[i]; i=i+1 } 47 rc4_ksa(S, key, keylen); rc4_crypt(S, ij, buf, ptlen) 48 var ok: i64 = 1; i = 0 49 while i < ptlen { let want: i64 = (r4_hexval(cthex[i*2] as i64)*16)+r4_hexval(cthex[i*2+1] as i64); if (buf[i] as i64) != want { ok = 0; i = ptlen } else { i = i + 1 } } 50 tot[0]=tot[0]+1; if ok==1 { pass[0]=pass[0]+1 } 51 r4_p(" [" as *u8); if ok==1 { r4_p("PASS" as *u8) } else { r4_p("FAIL" as *u8) } r4_p("] " as *u8); r4_p(label); r4_p("\n" as *u8) 52 return 0 53} 54 55func main() -> i64 { 56 let pass: *i64 = sys_mmap(8) as *i64; let tot: *i64 = sys_mmap(8) as *i64; pass[0]=0; tot[0]=0 57 r4_p("RC4-GATE authored=organ\n" as *u8) 58 r4_case("Key/Plaintext -> BBF316E8D940AF0AD3" as *u8, "Key" as *u8, 3, "Plaintext" as *u8, 9, "bbf316e8d940af0ad3" as *u8, pass, tot) 59 r4_case("Wiki/pedia -> 1021BF0420" as *u8, "Wiki" as *u8, 4, "pedia" as *u8, 5, "1021bf0420" as *u8, pass, tot) 60 r4_case("Secret/Attack at dawn -> 45A01F...9BF5" as *u8, "Secret" as *u8, 6, "Attack at dawn" as *u8, 14, "45a01f645fc35b383552544b9bf5" as *u8, pass, tot) 61 // round-trip: encrypt then decrypt with a fresh keyed state returns the plaintext (also exercises rc4_skip) 62 let S1: *u8 = sys_mmap(256); let ij1: *i64 = sys_mmap(16) as *i64; ij1[0]=0; ij1[1]=0 63 let S2: *u8 = sys_mmap(256); let ij2: *i64 = sys_mmap(16) as *i64; ij2[0]=0; ij2[1]=0 64 let key: *u8 = "mse-shared-secret" as *u8 65 let msg: *u8 = sys_mmap(32); var m: i64=0; while m<20 { msg[m]=(65+m) as u8; m=m+1 } // "ABCDE...T" 66 rc4_ksa(S1, key, 17); rc4_skip(S1, ij1, K_MAGIC_1024); rc4_crypt(S1, ij1, msg, 20) // encrypt (skip K_MAGIC_1024 like MSE) 67 rc4_ksa(S2, key, 17); rc4_skip(S2, ij2, K_MAGIC_1024); rc4_crypt(S2, ij2, msg, 20) // decrypt 68 var rt: i64=1; var q: i64=0; while q<20 { if (msg[q] as i64) != (65+q) { rt=0; q=20 } else { q=q+1 } } 69 tot[0]=tot[0]+1; if rt==1 { pass[0]=pass[0]+1 } 70 r4_p(" [" as *u8); if rt==1 { r4_p("PASS" as *u8) } else { r4_p("FAIL" as *u8) } r4_p("] round-trip w/ 1024-byte MSE skip\n" as *u8) 71 r4_p("RC4-GATE pass=" as *u8); let b: *u8=sys_mmap(8); var v: i64=pass[0]; b[0]=(48+v) as u8; sys_write(1,b,1); r4_p("/" as *u8); v=tot[0]; b[0]=(48+v) as u8; sys_write(1,b,1) 72 if pass[0]==tot[0] { r4_p(" verdict=GREEN\n" as *u8); sys_exit(0); return 0 } 73 r4_p(" verdict=RED\n" as *u8); sys_exit(1); return 1 74}