full encrypted convo to splash
This commit is contained in:
@@ -1,21 +0,0 @@
|
|||||||
<!--- *=* Copyright 1996-99 WebTV Networks, Inc. All rights reserved. --->
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<display nooptions nostatus skipback clearback fontsize=medium>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body bgcolor="#000000" text="#449944">
|
|
||||||
<bgsound src="file://ROM/Sounds/Splash.mid">
|
|
||||||
|
|
||||||
<center>
|
|
||||||
<spacer type=block height=98 width=21>
|
|
||||||
<br>
|
|
||||||
<img src="file://rom/images/splash_logo_msn.gif">
|
|
||||||
<br><br><br>
|
|
||||||
<p><br>
|
|
||||||
<p><br>
|
|
||||||
|
|
||||||
|
|
||||||
</center>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
16
hacktv_updsrv/ServiceVault/htv-update/updatemenu.txt
Normal file
16
hacktv_updsrv/ServiceVault/htv-update/updatemenu.txt
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
200 OK
|
||||||
|
Connection: Keep-Alive
|
||||||
|
wtv-expire-all: wtv-home:/splash
|
||||||
|
Content-type: text/html
|
||||||
|
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<DISPLAY showwhencomplete noscroll>
|
||||||
|
</head>
|
||||||
|
<body bgcolor="black" link="gold" vlink="gold" alink="gold" text="gold">
|
||||||
|
|
||||||
|
<a href="htv-update:/update">Check for HackTV Updates</a><br>
|
||||||
|
<a href="wtv-home:/unlock">Unlock Full Client (Options, Goto, etc)</a><br>
|
||||||
|
<a href="wtv-home:/splash">Splash test</a>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -6,12 +6,13 @@ if (socket_session_data[socket.id].ssid != null && !sec_session[socket_session_d
|
|||||||
|
|
||||||
headers = `200 OK
|
headers = `200 OK
|
||||||
Connection: Close
|
Connection: Close
|
||||||
wtv-initial-key: ` + sec_session[socket_session_data[socket.id].ssid].challenge_key.toString(CryptoJS.enc.Base64) + `
|
wtv-initial-key: ` + issueWTVInitialKey(socket) + `
|
||||||
Content-Type: text/tellyscript
|
Content-Type: text/html
|
||||||
wtv-service: reset
|
wtv-service: reset
|
||||||
wtv-service: name=wtv-1800 host=` + pubip + ` port=1615 connections=1
|
wtv-service: name=wtv-* host=` + pubip + ` port=`+port+` flags=0x00000007
|
||||||
wtv-service: name=wtv-head-waiter host=` + pubip + ` port=1615 flags=0x04 flags=0x00000001 connections=1
|
wtv-service: name=wtv-head-waiter host=` + pubip + ` port=`+port+` flags=0x04 flags=0x00000001 connections=1
|
||||||
wtv-service: name=htv-update host=` + pubip + ` port=1615 flags=0x04
|
wtv-service: name=wtv-flashrom host=` + pubip + ` port=`+port+` flags=0x00000040
|
||||||
|
wtv-service: name=htv-update host=` + pubip + ` port=`+port+` flags=0x04
|
||||||
wtv-boot-url: wtv-head-waiter:/login?
|
wtv-boot-url: wtv-head-waiter:/login?
|
||||||
wtv-visit: wtv-head-waiter:/login?
|
wtv-visit: wtv-head-waiter:/login?
|
||||||
wtv-client-time-zone: GMT -0000
|
wtv-client-time-zone: GMT -0000
|
||||||
@@ -19,12 +20,12 @@ wtv-client-time-dst-rule: GMT
|
|||||||
wtv-client-date: `+strftime("%a, %d %b %Y %H:%M:%S", new Date(new Date().toUTCString()))+` GMT`;
|
wtv-client-date: `+strftime("%a, %d %b %Y %H:%M:%S", new Date(new Date().toUTCString()))+` GMT`;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
var romtype = socket_session_data[socket.id].romtype;
|
var romtype = socket_session_data[socket.id].romtype;
|
||||||
|
|
||||||
switch (romtype) {
|
switch (romtype) {
|
||||||
case "US-LC2-disk-0MB-8MB":
|
case "US-LC2-disk-0MB-8MB":
|
||||||
data = fs.readFileSync(__dirname + "/ServiceDeps/LC2/artemis_18006138199.tok").buffer;
|
data = getFile("LC2/artemis_18004653537.tok",true);
|
||||||
//data = fs.readFileSync(__dirname + "/ServiceDeps/LC2/LC2.tok").buffer;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@@ -32,3 +33,5 @@ switch (romtype) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*/
|
||||||
|
data='';
|
||||||
@@ -1,3 +1,8 @@
|
|||||||
|
var gourl = "wtv-1800:/offer-open-isp-suggest?";
|
||||||
|
if (initial_headers['wtv-ticket']) {
|
||||||
|
gourl = "wtv-head-waiter:/login-stage-two?";
|
||||||
|
}
|
||||||
|
|
||||||
headers = `200 OK
|
headers = `200 OK
|
||||||
Connection: Keep-Alive
|
Connection: Keep-Alive
|
||||||
wtv-open-isp-disabled: false
|
wtv-open-isp-disabled: false
|
||||||
|
|||||||
9
hacktv_updsrv/ServiceVault/wtv-1800/test.js
Normal file
9
hacktv_updsrv/ServiceVault/wtv-1800/test.js
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
var wtv = new WTVNetworkSecurity();
|
||||||
|
var test = CryptoJS.enc.Utf8.parse("this is a test");
|
||||||
|
var test2 = wtv.wordArrayToUint8Array(test);
|
||||||
|
var test3 = CryptoJS.lib.WordArray.create(test2);
|
||||||
|
headers = `200 OK
|
||||||
|
Connection: Close
|
||||||
|
Content-type: text/plain`
|
||||||
|
|
||||||
|
data = test3.toString(CryptoJS.enc.Utf8);
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
var challenge_response, challenge_header = '';
|
||||||
|
var gourl;
|
||||||
|
|
||||||
|
if (socket_session_data[socket.id].ssid !== null) {
|
||||||
|
if (initial_headers['wtv-ticket']) {
|
||||||
|
if (initial_headers['wtv-ticket'].length > 8) {
|
||||||
|
DecodeTicket(initial_headers['wtv-ticket']);
|
||||||
|
sec_session[socket_session_data[socket.id].ssid].ticket_b64 = initial_headers['wtv-ticket'];
|
||||||
|
//socket_session_data[socket.id].secure == true;
|
||||||
|
}
|
||||||
|
} else if (sec_session[socket_session_data[socket.id].ssid].ticket_b64 == null) {
|
||||||
|
// TODO: client should have a ticket and send it back by now, if not we should handle this correctly
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
headers = `200 OK
|
||||||
|
Connection: Keep-Alive
|
||||||
|
wtv-encrypted: true
|
||||||
|
wtv-ticket: `+sec_session[socket_session_data[socket.id].ssid].ticket_b64+`
|
||||||
|
wtv-expire-all: htv-
|
||||||
|
wtv-visit: wtv-home:/splash?
|
||||||
|
Content-Type: text/html
|
||||||
|
`;
|
||||||
@@ -5,18 +5,21 @@ if (socket_session_data[socket.id].ssid !== null) {
|
|||||||
if (sec_session[socket_session_data[socket.id].ssid].ticket_b64 == null) {
|
if (sec_session[socket_session_data[socket.id].ssid].ticket_b64 == null) {
|
||||||
if (initial_headers['wtv-ticket']) {
|
if (initial_headers['wtv-ticket']) {
|
||||||
if (initial_headers['wtv-ticket'].length > 8) {
|
if (initial_headers['wtv-ticket'].length > 8) {
|
||||||
DecodeTicket(initial_headers['wtv-ticket']);
|
sec_session[socket_session_data[socket.id].ssid].DecodeTicket(initial_headers['wtv-ticket']);
|
||||||
sec_session[socket_session_data[socket.id].ssid].ticket_b64 = initial_headers['wtv-ticket'];
|
sec_session[socket_session_data[socket.id].ssid].ticket_b64 = initial_headers['wtv-ticket'];
|
||||||
socket_session_data[socket.id].secure == true;
|
//socket_session_data[socket.id].secure = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
challenge_response = sec_session[socket_session_data[socket.id].ssid].challenge_response;
|
challenge_response = sec_session[socket_session_data[socket.id].ssid].challenge_response;
|
||||||
var client_challenge_response = initial_headers['wtv-challenge-response'] || null;
|
var client_challenge_response = initial_headers['wtv-challenge-response'] || null;
|
||||||
if (challenge_response && client_challenge_response) {
|
if (challenge_response && client_challenge_response) {
|
||||||
if (challenge_response.toString(CryptoJS.enc.Base64).substring(0,85) == client_challenge_response.substring(0,85)) {
|
//if (challenge_response.toString(CryptoJS.enc.Base64).substring(0,85) == client_challenge_response.substring(0,85)) {
|
||||||
|
if (challenge_response.toString(CryptoJS.enc.Base64) == client_challenge_response) {
|
||||||
console.log(" * wtv-challenge-response success for "+socket_session_data[socket.id].ssid);
|
console.log(" * wtv-challenge-response success for "+socket_session_data[socket.id].ssid);
|
||||||
|
if (zdebug) console.log("Response Expected:",challenge_response.toString(CryptoJS.enc.Base64));
|
||||||
|
if (zdebug) console.log("Response Received:",client_challenge_response)
|
||||||
sec_session[socket_session_data[socket.id].ssid].PrepareTicket();
|
sec_session[socket_session_data[socket.id].ssid].PrepareTicket();
|
||||||
socket_session_data[socket.id].secure == true;
|
//socket_session_data[socket.id].secure = true;
|
||||||
} else {
|
} else {
|
||||||
gourl = "wtv-head-waiter:/login?reissue_challenge=true";
|
gourl = "wtv-head-waiter:/login?reissue_challenge=true";
|
||||||
}
|
}
|
||||||
@@ -35,11 +38,58 @@ wtv-visit: `+gourl+`
|
|||||||
Content-type: text/html`;
|
Content-type: text/html`;
|
||||||
data = '';
|
data = '';
|
||||||
} else {
|
} else {
|
||||||
|
var nickname = 'HackTVUsr_'+Math.floor(Math.random() * 100000);
|
||||||
headers = `200 OK
|
headers = `200 OK
|
||||||
Connection: Keep-Alive
|
Connection: Keep-Alive
|
||||||
wtv-encrypted: true
|
wtv-encrypted: true
|
||||||
wtv-ticket: `+sec_session[socket_session_data[socket.id].ssid].ticket_b64+`
|
wtv-ticket: `+sec_session[socket_session_data[socket.id].ssid].ticket_b64+`
|
||||||
|
wtv-client-time-zone: GMT -0000
|
||||||
|
wtv-client-date: `+strftime("%a, %d %b %Y %H:%M:%S", new Date(new Date().toUTCString()))+` GMT
|
||||||
|
wtv-country: US
|
||||||
|
wtv-language-header: en-US,en
|
||||||
|
wtv-tv-zipcode: 90210
|
||||||
|
wtv-visit: client:closeallpanels
|
||||||
|
wtv-messagewatch-checktimeoffset: off
|
||||||
|
wtv-expire-all: client:closeallpanels
|
||||||
|
wtv-input-timeout: 14400
|
||||||
|
wtv-connection-timeout: 90
|
||||||
|
wtv-fader-timeout: 900
|
||||||
|
wtv-ssl-log-url: wtv-log:/log
|
||||||
|
wtv-smartcard-inserted-message: Contacting service
|
||||||
|
user-id: 1`+Math.floor(Math.random() * 1000000000000000000)+`
|
||||||
|
wtv-transition-override: off
|
||||||
|
wtv-bypass-proxy: true
|
||||||
|
wtv-allow-dsc: true
|
||||||
|
wtv-messenger-enable: 0
|
||||||
|
wtv-noback-all: wtv-
|
||||||
|
wtv-service: reset
|
||||||
|
wtv-service: name=wtv-1800 host=` + pubip + ` port=` + port + ` connections=1
|
||||||
|
wtv-service: name=wtv-head-waiter host=` + pubip + ` port=` + port + ` flags=0x04 flags=0x00000001 connections=1
|
||||||
|
wtv-service: name=htv-update host=` + pubip + ` port=` + port + ` connections=3
|
||||||
|
wtv-service: name=wtv-log host=` + pubip + ` port=` + port + ` connections=1
|
||||||
|
wtv-service: name=wtv-home host=` + pubip + ` port=` + port + ` flags=0x00000010
|
||||||
|
wtv-boot-url: wtv-1800:/preregister
|
||||||
|
wtv-user-name: `+nickname+`
|
||||||
|
wtv-human-name: `+nickname+`
|
||||||
|
wtv-irc-nick: `+nickname+`
|
||||||
|
wtv-home-url: htv-update:/update?
|
||||||
|
wtv-domain: wtv.zefie.com
|
||||||
|
wtv-inactive-timeout: 0
|
||||||
|
wtv-connection-timeout: 90
|
||||||
|
wtv-show-time-enabled: true
|
||||||
|
wtv-fader-timeout: 900
|
||||||
|
wtv-tourist-enabled: true
|
||||||
|
wtv-boot-url: wtv-head-waiter:/login
|
||||||
|
wtv-connection-timeout: 180
|
||||||
|
wtv-ssl-timeout: 240
|
||||||
|
wtv-login-timeout: 7200
|
||||||
|
wtv-open-isp-disabled: false
|
||||||
|
wtv-log-url: wtv-log:/log
|
||||||
|
wtv-demo-mode: 0
|
||||||
|
wtv-wink-deferrer-retries: 3
|
||||||
|
wtv-offline-mail-enable: true
|
||||||
|
wtv-visit: wtv-head-waiter:/finalize-security?
|
||||||
Content-Type: text/html`;
|
Content-Type: text/html`;
|
||||||
|
|
||||||
data = "hehe! stage two! <a href='wtv-head-waiter:/finalize-security'>test</a>";
|
data = '';
|
||||||
}
|
}
|
||||||
@@ -1,12 +1,13 @@
|
|||||||
var initialChallenge, challenge_response, challenge_header = '';
|
var challenge_response, challenge_header = '';
|
||||||
var gourl = "wtv-head-waiter:/login-stage-two?";
|
|
||||||
|
|
||||||
if (socket_session_data[socket.id].ssid !== null) {
|
if (socket_session_data[socket.id].ssid !== null) {
|
||||||
if (sec_session[socket_session_data[socket.id].ssid].ticket_b64 == null) {
|
|
||||||
if (initial_headers['wtv-ticket']) {
|
if (initial_headers['wtv-ticket']) {
|
||||||
|
if (sec_session[socket_session_data[socket.id].ssid].ticket_b64 == null) {
|
||||||
if (initial_headers['wtv-ticket'].length > 8) {
|
if (initial_headers['wtv-ticket'].length > 8) {
|
||||||
DecodeTicket(initial_headers['wtv-ticket']);
|
sec_session[socket_session_data[socket.id].ssid].DecodeTicket(initial_headers['wtv-ticket']);
|
||||||
sec_session[socket_session_data[socket.id].ssid].ticket_b64 = initial_headers['wtv-ticket'];
|
sec_session[socket_session_data[socket.id].ssid].ticket_b64 = initial_headers['wtv-ticket'];
|
||||||
|
//socket_session_data[socket.id].secure = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
challenge_response = sec_session[socket_session_data[socket.id].ssid].challenge_response;
|
challenge_response = sec_session[socket_session_data[socket.id].ssid].challenge_response;
|
||||||
@@ -15,60 +16,43 @@ if (socket_session_data[socket.id].ssid !== null) {
|
|||||||
if (challenge_response.toString(CryptoJS.enc.Base64).substring(0,85) == client_challenge_response.substring(0,85)) {
|
if (challenge_response.toString(CryptoJS.enc.Base64).substring(0,85) == client_challenge_response.substring(0,85)) {
|
||||||
console.log(" * wtv-challenge-response success for "+socket_session_data[socket.id].ssid);
|
console.log(" * wtv-challenge-response success for "+socket_session_data[socket.id].ssid);
|
||||||
sec_session[socket_session_data[socket.id].ssid].PrepareTicket();
|
sec_session[socket_session_data[socket.id].ssid].PrepareTicket();
|
||||||
|
//socket_session_data[socket.id].secure = true;
|
||||||
} else {
|
} else {
|
||||||
challenge_header = "wtv-challenge: "+sec_session[socket_session_data[socket.id].ssid].IssueChallenge();
|
challenge_header = "wtv-challenge: "+issueWTVChallenge(socket);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
challenge_header = "wtv-challenge: "+sec_session[socket_session_data[socket.id].ssid].IssueChallenge();
|
challenge_header = "wtv-challenge: "+issueWTVChallenge(socket);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sec_session[socket_session_data[socket.id].ssid].ticket_b64) {
|
if (initial_headers) {
|
||||||
headers = `200 OK
|
var cookiedata = {};
|
||||||
Connection: Keep-Alive
|
Object.keys(initial_headers).forEach(function (k) {
|
||||||
wtv-encrypted: true
|
switch (k) {
|
||||||
wtv-ticket: `+sec_session[socket_session_data[socket.id].ssid].ticket_b64+`
|
case "wtv-capability-flags":
|
||||||
wtv-client-time-zone: GMT -0000
|
case "wtv-system-version":
|
||||||
wtv-client-date: `+strftime("%a, %d %b %Y %H:%M:%S", new Date(new Date().toUTCString()))+` GMT
|
case "wtv-client-rom-type":
|
||||||
wtv-country: US
|
case "wtv-client-bootrom-version":
|
||||||
wtv-language-header: en-US,en
|
case "wtv-system-chipversion":
|
||||||
wtv-visit: client:closeallpanels
|
case "wtv-system-sysconfig":
|
||||||
wtv-expire-all: client:closeallpanels
|
case "wtv-system-cpuspeed":
|
||||||
wtv-noback-all: wtv-
|
cookiedata[k] = initial_headers[k];
|
||||||
wtv-service: reset
|
break;
|
||||||
wtv-service: name=wtv-1800 host=` + pubip + ` port=1615 connections=1
|
}
|
||||||
wtv-service: name=wtv-head-waiter host=` + pubip + ` port=1615 flags=0x04 flags=0x00000001 connections=1
|
});
|
||||||
wtv-service: name=htv-update host=` + pubip + ` port=1615 flags=0x04
|
cookie_dat[socket_session_data[socket.id].ssid] = CryptoJS.enc.Utf8.parse(JSON.stringify(cookiedata)).toString(CryptoJS.enc.Base64);
|
||||||
wtv-boot-url: wtv-head-waiter:/login?
|
}
|
||||||
wtv-input-timeout: 14400
|
|
||||||
wtv-connection-timeout: 90
|
|
||||||
wtv-fader-timeout: 900
|
|
||||||
wtv-ssl-log-url: wtv-log:/log
|
|
||||||
wtv-bypass-proxy: true
|
|
||||||
wtv-allow-dsc: true
|
|
||||||
wtv-messenger-enable: 0
|
|
||||||
wtv-nameserver: 1.1.1.1
|
|
||||||
wtv-phone-log-url: wtv-log:/log
|
|
||||||
wtv-visit: wtv-head-waiter:/login-stage-two?
|
|
||||||
Content-type: text/html`
|
|
||||||
|
|
||||||
data = '';
|
|
||||||
//data = fs.readFileSync(__dirname + "/ServiceDeps/splash.html");
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
headers = `200 OK
|
headers = `200 OK
|
||||||
Connection: Keep-Alive
|
Connection: Keep-Alive
|
||||||
Expires: Wed, 09 Oct 1991 22:00:00 GMT
|
Expires: Wed, 09 Oct 1991 22:00:00 GMT
|
||||||
wtv-expire-all: wtv-head-waiter:
|
wtv-expire-all: wtv-head-waiter:
|
||||||
wtv-service: name=wtv-log host=` + pubip + ` port=1615 connections=1
|
wtv-service: name=wtv-log host=` + pubip + ` port=`+port+` connections=1
|
||||||
wtv-log-url: wtv-log:/log
|
wtv-log-url: wtv-log:/log
|
||||||
`+challenge_header+`
|
`+challenge_header+`
|
||||||
wtv-relogin-url: wtv-1800:/preregister?relogin=true
|
wtv-relogin-url: wtv-1800:/preregister?relogin=true
|
||||||
wtv-reconnect-url: wtv-1800:/preregister?reconnect=true
|
wtv-reconnect-url: wtv-1800:/preregister?reconnect=true
|
||||||
wtv-visit: `+gourl+`
|
wtv-visit: wtv-head-waiter:/login-stage-two?
|
||||||
Content-type: text/html`;
|
Content-type: text/html`;
|
||||||
data = '';
|
data = '';
|
||||||
}
|
|
||||||
24
hacktv_updsrv/ServiceVault/wtv-home/splash.txt
Normal file
24
hacktv_updsrv/ServiceVault/wtv-home/splash.txt
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
200 OK
|
||||||
|
Connection: Keep-Alive
|
||||||
|
wtv-expire-all: htv-
|
||||||
|
Content-type: text/html
|
||||||
|
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<display nooptions nostatus skipback clearback fontsize=medium>
|
||||||
|
<meta
|
||||||
|
http-equiv=refresh
|
||||||
|
content="5; url=htv-update:/updatemenu"
|
||||||
|
>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body bgcolor="#000000" text="#449944">
|
||||||
|
<bgsound src="file://ROM/Sounds/Splash.mid">
|
||||||
|
<center>
|
||||||
|
<img src="file://Disk/Browser/DiskFlash/HTMLs/hacktv.gif">
|
||||||
|
<br>
|
||||||
|
<spacer type=block height=98 width=21>
|
||||||
|
<br>
|
||||||
|
</center>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -1,10 +1,8 @@
|
|||||||
console.log(initial_headers);
|
// dummy page, we could handle the logs here.
|
||||||
|
|
||||||
headers = `200 OK
|
headers = `200 OK
|
||||||
Connection: Keep-Alive
|
Connection: Keep-Alive
|
||||||
Expires: `+strftime("%a, %d %b %Y %H:%M:%S", new Date((new Date().toUTCString()) + 10))+` GMT
|
Content-length: 0`;
|
||||||
Content-length: 0
|
|
||||||
Content-type: text/html`;
|
|
||||||
|
|
||||||
data = '';
|
data = '';
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ const strftime = require('strftime');
|
|||||||
const net = require('net');
|
const net = require('net');
|
||||||
const CryptoJS = require('crypto-js');
|
const CryptoJS = require('crypto-js');
|
||||||
const mime = require('mime-types');
|
const mime = require('mime-types');
|
||||||
var str2ab = require('string-to-arraybuffer')
|
|
||||||
var WTVNetworkSecurity = require('./wtvsec.js');
|
var WTVNetworkSecurity = require('./wtvsec.js');
|
||||||
|
|
||||||
var zdebug = true;
|
var zdebug = true;
|
||||||
@@ -17,8 +16,14 @@ var pubip = "192.168.11.8";
|
|||||||
var port = 1615;
|
var port = 1615;
|
||||||
|
|
||||||
var sec_session = new Array();
|
var sec_session = new Array();
|
||||||
|
var cookie_dat = new Array();
|
||||||
|
var socket_buffer = new Array();
|
||||||
var socket_session_data = new Array();
|
var socket_session_data = new Array();
|
||||||
|
|
||||||
|
var overrides = new Array();
|
||||||
|
//overrides['initial_key'] = "CC5rWmRUE0o=";
|
||||||
|
//overrides['challenge'] = "0kjyqIYAu0ziFBbSERN6DGaZ6S0fT+DBUCtpHCJ4lpuM7CbXdAm+x83BIDoJYztd1Z+5KFZ7ghmb3LJCT/6mhWUYkqqKOyfPRW8ZIdbICK/CV+Kxm8EUjRXZSk/97tsmFpH3hcCJ7C2TBw+TX38uQQ==";
|
||||||
|
|
||||||
function getPublicIP() {
|
function getPublicIP() {
|
||||||
var options = {
|
var options = {
|
||||||
host: 'www.planeptune.org',
|
host: 'www.planeptune.org',
|
||||||
@@ -35,6 +40,39 @@ function getPublicIP() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getFile(path, deps = false) {
|
||||||
|
var dir = null;
|
||||||
|
if (deps) dir = __dirname + "/ServiceDeps/";
|
||||||
|
else dir = __dirname + "/ServiceVault/";
|
||||||
|
if (fs.lstatSync(dir + path).isFile()) {
|
||||||
|
return fs.readFileSync(dir + path, {
|
||||||
|
encoding: null,
|
||||||
|
flags: 'r'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function issueWTVInitialKey(socket) {
|
||||||
|
if (overrides['initial_key']) {
|
||||||
|
sec_session[socket_session_data[socket.id].ssid].initial_shared_key = CryptoJS.enc.Base64.parse(overrides['initial_key']);
|
||||||
|
sec_session[socket_session_data[socket.id].ssid].current_shared_key = CryptoJS.enc.Base64.parse(overrides['initial_key']);
|
||||||
|
sec_session[socket_session_data[socket.id].ssid].challenge_key = CryptoJS.enc.Base64.parse(overrides['initial_key']);
|
||||||
|
return overrides['initial_key'];
|
||||||
|
} else {
|
||||||
|
return sec_session[socket_session_data[socket.id].ssid].challenge_key.toString(CryptoJS.enc.Base64);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function issueWTVChallenge(socket) {
|
||||||
|
if (overrides['challenge']) {
|
||||||
|
sec_session[socket_session_data[socket.id].ssid].challenge_response = sec_session[socket_session_data[socket.id].ssid].ProcessChallenge(overrides['challenge']);
|
||||||
|
return overrides['challenge'];
|
||||||
|
} else {
|
||||||
|
return sec_session[socket_session_data[socket.id].ssid].IssueChallenge();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function doErrorPage(code) {
|
function doErrorPage(code) {
|
||||||
var headers, data = null;
|
var headers, data = null;
|
||||||
switch (code) {
|
switch (code) {
|
||||||
@@ -62,6 +100,7 @@ function doErrorPage(code) {
|
|||||||
function processPath(socket, path, initial_headers = new Array(), query = new Array()) {
|
function processPath(socket, path, initial_headers = new Array(), query = new Array()) {
|
||||||
var headers, data = null;
|
var headers, data = null;
|
||||||
var request_is_direct_file = false;
|
var request_is_direct_file = false;
|
||||||
|
path = path.replace(/\\/g, "/");
|
||||||
try {
|
try {
|
||||||
try {
|
try {
|
||||||
// try to see if the exact request exists
|
// try to see if the exact request exists
|
||||||
@@ -83,8 +122,17 @@ function processPath(socket, path, initial_headers = new Array(), query = new Ar
|
|||||||
// raw text format, entire payload expected (headers and content)
|
// raw text format, entire payload expected (headers and content)
|
||||||
console.log(" * Found " + path + ".txt to handle request (Raw TXT Mode)");
|
console.log(" * Found " + path + ".txt to handle request (Raw TXT Mode)");
|
||||||
var fdat = fs.readFileSync(path + ".txt").toString();
|
var fdat = fs.readFileSync(path + ".txt").toString();
|
||||||
headers = fdat.split("\n\n")[0];
|
if (fdat.indexOf("\n\n") > 0) {
|
||||||
data = fdat.split("\n\n")[1];
|
var fdata = fdat.split("\n\n");
|
||||||
|
headers = fdata[0];
|
||||||
|
fdata.shift();
|
||||||
|
data = fdata.join("\n");
|
||||||
|
} else if (fdat.indexOf("\r\n\r\n") > 0) {
|
||||||
|
var fdata = fdat.split("\r\n\r\n");
|
||||||
|
headers = fdata[0].replace(/\r/g, "");
|
||||||
|
fdata.shift();
|
||||||
|
data = fdata.join("\r\n");
|
||||||
|
}
|
||||||
} else if (fs.existsSync(path + ".js")) {
|
} else if (fs.existsSync(path + ".js")) {
|
||||||
// js scripting, process with vars, must set 'headers' and 'data' appropriately.
|
// js scripting, process with vars, must set 'headers' and 'data' appropriately.
|
||||||
// loaded script will have r/w access to any JavaScript vars this function does.
|
// loaded script will have r/w access to any JavaScript vars this function does.
|
||||||
@@ -164,10 +212,14 @@ function processURL(socket, initial_headers) {
|
|||||||
if (ssid == null) {
|
if (ssid == null) {
|
||||||
ssid = initial_headers['wtv-client-serial-number'];
|
ssid = initial_headers['wtv-client-serial-number'];
|
||||||
}
|
}
|
||||||
|
var reqverb = "Request";
|
||||||
|
if (initial_headers['encrypted'] || initial_headers['secure']) {
|
||||||
|
reqverb = "Encrypted " + reqverb;
|
||||||
|
}
|
||||||
if (ssid != null) {
|
if (ssid != null) {
|
||||||
console.log(" * Request for " + initial_headers['request_url'] + " from WebTV SSID " + ssid);
|
console.log(" * "+reqverb+" for " + initial_headers['request_url'] + " from WebTV SSID " + ssid);
|
||||||
} else {
|
} else {
|
||||||
console.log(" * Request for " + initial_headers['request_url']);
|
console.log(" * "+reqverb+" for " + initial_headers['request_url']);
|
||||||
}
|
}
|
||||||
// assume webtv since there is a :/ in the GET
|
// assume webtv since there is a :/ in the GET
|
||||||
var urlToPath = __dirname + "/ServiceVault/" + shortURL.split(':/')[0] + "/" + shortURL.split(':/')[1];
|
var urlToPath = __dirname + "/ServiceVault/" + shortURL.split(':/')[0] + "/" + shortURL.split(':/')[1];
|
||||||
@@ -226,11 +278,22 @@ function processURL(socket, initial_headers) {
|
|||||||
|
|
||||||
// set wtv-encrypted and put it near the top of the headers (unknown if needed)
|
// set wtv-encrypted and put it near the top of the headers (unknown if needed)
|
||||||
if (socket_session_data[socket.id].secure == true) {
|
if (socket_session_data[socket.id].secure == true) {
|
||||||
console.log(" * encrypting response to client ...")
|
var clen = null;
|
||||||
|
if (typeof data.length !== 'undefined') {
|
||||||
|
clen = data.length;
|
||||||
|
} else if (typeof data.byteLength !== 'undefined') {
|
||||||
|
clen = data.byteLength;
|
||||||
|
}
|
||||||
headers_obj['wtv-encrypted'] = true;
|
headers_obj['wtv-encrypted'] = true;
|
||||||
headers_obj = moveObjectElement('wtv-encrypted', 'Connection', headers_obj);
|
headers_obj = moveObjectElement('wtv-encrypted', 'Connection', headers_obj);
|
||||||
var enc_data = sec_session[socket_session_data[socket.id].ssid].EncryptKey2(data);
|
if (clen > 0) {
|
||||||
var test = data;
|
console.log(" * Encrypting response to client ...")
|
||||||
|
if (typeof (data) === 'string') {
|
||||||
|
data = CryptoJS.enc.Utf8.parse(data);
|
||||||
|
}
|
||||||
|
var enc_data = sec_session[socket_session_data[socket.id].ssid].Encrypt(1,data);
|
||||||
|
data = enc_data;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
headers = "";
|
headers = "";
|
||||||
@@ -252,7 +315,12 @@ function processURL(socket, initial_headers) {
|
|||||||
toClient = headers + "\n" + data;
|
toClient = headers + "\n" + data;
|
||||||
socket.write(toClient);
|
socket.write(toClient);
|
||||||
} else if (typeof data == 'object') {
|
} else if (typeof data == 'object') {
|
||||||
socket.write(new Uint8Array(concatArrayBuffer(Buffer.from(headers + "\r\n"), data)));
|
if (socket_session_data[socket.id].secure_headers == true) {
|
||||||
|
var enc_headers = sec_session[socket_session_data[socket.id].ssid].Encrypt(1,headers+"\n");
|
||||||
|
socket.write(new Uint8Array(concatArrayBuffer(enc_headers, data)));
|
||||||
|
} else {
|
||||||
|
socket.write(new Uint8Array(concatArrayBuffer(Buffer.from(headers + "\n"), data)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (headers_obj['Connection']) {
|
if (headers_obj['Connection']) {
|
||||||
if (headers_obj['Connection'].toLowerCase() == "close") {
|
if (headers_obj['Connection'].toLowerCase() == "close") {
|
||||||
@@ -297,28 +365,28 @@ function headersAreStandard(string) {
|
|||||||
// is not suffuicent. This checks for characters expected in unecrypted headers, and returns
|
// is not suffuicent. This checks for characters expected in unecrypted headers, and returns
|
||||||
// true only if every character in the string matches the regex. Once we know the string is binary
|
// true only if every character in the string matches the regex. Once we know the string is binary
|
||||||
// we can better process it with the raw base64 data in processHeaders() below.
|
// we can better process it with the raw base64 data in processHeaders() below.
|
||||||
var test = /^([A-Za-z0-9\+\/\=\-\.\ \;\:\?\&\r\n\(\)\%\<\>\_]{8,})$/.test(string);
|
var test = /^([A-Za-z0-9\+\/\=\-\.\,\ \;\:\?\&\r\n\(\)\%\<\>\_]{8,})$/.test(string);
|
||||||
if (zdebug) console.log("request is ascii: " + test);
|
if (zdebug) console.log("request is ascii: " + test);
|
||||||
if (zdebug) console.log("request as follows: " + string);
|
if (zdebug) console.log("request is SECURE ON: " + /^SECURE ON/.test(string));
|
||||||
return test;
|
return test;
|
||||||
}
|
}
|
||||||
|
|
||||||
function processHeaders(socket, data_b64, returnHeadersBeforeSecure = false) {
|
function processHeaders(socket, data_hex, returnHeadersBeforeSecure = false, encryptedRequest = false) {
|
||||||
var url = "";
|
var url = "";
|
||||||
var data = CryptoJS.enc.Latin1.stringify(CryptoJS.enc.Base64.parse(data_b64));
|
var data = CryptoJS.enc.Latin1.stringify(CryptoJS.enc.Hex.parse(data_hex));
|
||||||
|
|
||||||
var headers = new Array();
|
var headers = new Array();
|
||||||
if (typeof data === "string") {
|
if (typeof data === "string") {
|
||||||
if (data.length > 1) {
|
if (data.length > 1) {
|
||||||
if (headersAreStandard(data)) {
|
|
||||||
data = data.split("\r\n\r\n")[0];
|
data = data.split("\r\n\r\n")[0];
|
||||||
|
if (headersAreStandard(data)) {
|
||||||
data.split('\n').forEach(function (d) {
|
data.split('\n').forEach(function (d) {
|
||||||
if (d.length > 0) {
|
if (d.length > 0) {
|
||||||
if (/^SECURE ON/.test(d)) {
|
if (/^SECURE ON/.test(d)) {
|
||||||
console.log(data);
|
|
||||||
secure_mode = true;
|
secure_mode = true;
|
||||||
headers['secure'] = true;
|
headers['secure'] = true;
|
||||||
socket_session_data[socket.id].secure = true;
|
socket_session_data[socket.id].secure = true;
|
||||||
|
socket_session_data[socket.id].secure_headers = true;
|
||||||
}
|
}
|
||||||
if (d.indexOf(":") > 0 && d.indexOf(":/") == -1) {
|
if (d.indexOf(":") > 0 && d.indexOf(":/") == -1) {
|
||||||
headers[d.split(':')[0]] = (d.split(':')[1]).replace("\r", "");
|
headers[d.split(':')[0]] = (d.split(':')[1]).replace("\r", "");
|
||||||
@@ -332,10 +400,25 @@ function processHeaders(socket, data_b64, returnHeadersBeforeSecure = false) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
if (!encryptedRequest) {
|
||||||
// failed the headersAreStandard test, so we think this is a binary blob
|
// failed the headersAreStandard test, so we think this is a binary blob
|
||||||
var encdata = CryptoJS.enc.Base64.parse(data_b64);
|
if (socket_session_data[socket.id].secure != true) {
|
||||||
var decdata = sec_session[socket_session_data[socket.id].ssid].DecryptKey1(encdata);
|
// first time so reroll sessions
|
||||||
var test = decdata;
|
sec_session[socket_session_data[socket.id].ssid].SecureOn();
|
||||||
|
socket_session_data[socket.id].secure = true;
|
||||||
|
}
|
||||||
|
var enc_data = CryptoJS.enc.Hex.parse(data_hex.substring(header_length * 2));
|
||||||
|
if (enc_data.sigBytes > 0) {
|
||||||
|
var dec_data = CryptoJS.lib.WordArray.create(sec_session[socket_session_data[socket.id].ssid].Decrypt(0,enc_data));
|
||||||
|
var dec_data_text = dec_data.toString(CryptoJS.enc.Latin1);
|
||||||
|
var secure_headers = processHeaders(socket, dec_data.toString(CryptoJS.enc.Hex), true, true);
|
||||||
|
headers['encrypted'] = true;
|
||||||
|
console.log("Encrypted Request (Decrypted):", dec_data.toString(CryptoJS.enc.Latin1));
|
||||||
|
Object.keys(secure_headers).forEach(function (k, v) {
|
||||||
|
headers[k] = secure_headers[k];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (headers['wtv-client-rom-type'] != null) {
|
if (headers['wtv-client-rom-type'] != null) {
|
||||||
socket_session_data[socket.id].romtype = headers['wtv-client-rom-type'];
|
socket_session_data[socket.id].romtype = headers['wtv-client-rom-type'];
|
||||||
@@ -354,16 +437,23 @@ function processHeaders(socket, data_b64, returnHeadersBeforeSecure = false) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (headers['secure'] === true) {
|
if (headers['secure'] === true) {
|
||||||
// assume we have an ssid if we are this far
|
if (!sec_session[socket_session_data[socket.id].ssid]) {
|
||||||
sec_session[headers['wtv-client-serial-number']].SecureOn();
|
sec_session[socket_session_data[socket.id].ssid] = new WTVNetworkSecurity();
|
||||||
|
sec_session[socket_session_data[socket.id].ssid].DecodeTicket(headers['wtv-ticket']);
|
||||||
|
sec_session[socket_session_data[socket.id].ssid].ticket_b64 = headers['wtv-ticket'];
|
||||||
|
sec_session[socket_session_data[socket.id].ssid].SecureOn();
|
||||||
|
}
|
||||||
if (!headers['request_url']) {
|
if (!headers['request_url']) {
|
||||||
var header_length = data.length + 4;
|
var header_length = data.length + 4;
|
||||||
var enc_data = CryptoJS.enc.Hex.parse(CryptoJS.enc.Base64.parse(data_b64).toString(CryptoJS.enc.Hex).substring(header_length * 2));
|
var enc_data = CryptoJS.enc.Hex.parse(data_hex.substring(header_length * 2));
|
||||||
console.log(enc_data.toString(CryptoJS.enc.Hex));
|
|
||||||
if (enc_data.sigBytes > 0) {
|
if (enc_data.sigBytes > 0) {
|
||||||
var dec_data = sec_session[socket_session_data[socket.id].ssid].DecryptKey1(enc_data);
|
var dec_data = CryptoJS.lib.WordArray.create(sec_session[socket_session_data[socket.id].ssid].Decrypt(0,enc_data))
|
||||||
console.log(dec_data);
|
//var dec_data_text = dec_data.toString(CryptoJS.enc.Latin1);
|
||||||
console.log(headers);
|
var secure_headers = processHeaders(socket, dec_data.toString(CryptoJS.enc.Hex), true);
|
||||||
|
console.log("Encrypted Request (Decrypted):", secure_headers.toString(CryptoJS.enc.Latin1));
|
||||||
|
Object.keys(secure_headers).forEach(function (k,v) {
|
||||||
|
headers[k] = secure_headers[k];
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -377,13 +467,23 @@ function processHeaders(socket, data_b64, returnHeadersBeforeSecure = false) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var server = net.createServer(function (socket) {
|
var server = net.createServer(function (socket) {
|
||||||
socket.binaryType = 'arraybuffer';
|
|
||||||
socket.id = Math.floor(Math.random() * 1000);
|
socket.id = Math.floor(Math.random() * 1000);
|
||||||
socket_session_data[socket.id] = [];
|
socket_session_data[socket.id] = [];
|
||||||
socket.setEncoding('base64'); //set data encoding (either 'ascii', 'utf8', or 'base64')
|
socket.setEncoding('hex'); //set data encoding (either 'ascii', 'utf8', or 'base64')
|
||||||
|
|
||||||
socket.on('data', function (data_b64) {
|
socket.on('data', function (data_hex) {
|
||||||
processURL(this, processHeaders(this, data_b64));
|
socket.setTimeout(300);
|
||||||
|
if (socket_buffer[socket.id]) {
|
||||||
|
socket_buffer[socket.id].concat(CryptoJS.enc.Hex.parse(data_hex));
|
||||||
|
} else {
|
||||||
|
socket_buffer[socket.id] = CryptoJS.enc.Hex.parse(data_hex);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.on('timeout', function () {
|
||||||
|
socket.setTimeout(0);
|
||||||
|
processURL(this, processHeaders(this, socket_buffer[socket.id].toString(CryptoJS.enc.Hex)));
|
||||||
|
socket_buffer[socket.id] = null;
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on('error', (err, socket) => {
|
socket.on('error', (err, socket) => {
|
||||||
@@ -391,6 +491,7 @@ var server = net.createServer(function (socket) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
socket.on('end', function () {
|
socket.on('end', function () {
|
||||||
|
socket_buffer[socket.id] = null;
|
||||||
secure_mode = false;
|
secure_mode = false;
|
||||||
socket_session_data[socket.id] = null;
|
socket_session_data[socket.id] = null;
|
||||||
});
|
});
|
||||||
|
|||||||
19
hacktv_updsrv/package-lock.json
generated
19
hacktv_updsrv/package-lock.json
generated
@@ -4,11 +4,6 @@
|
|||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"atob-lite": {
|
|
||||||
"version": "2.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/atob-lite/-/atob-lite-2.0.0.tgz",
|
|
||||||
"integrity": "sha1-D+9a1G8b16hQLGVyfwNn1e5D1pY="
|
|
||||||
},
|
|
||||||
"crypto-js": {
|
"crypto-js": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.0.0.tgz",
|
||||||
@@ -19,11 +14,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/endianness/-/endianness-8.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/endianness/-/endianness-8.0.2.tgz",
|
||||||
"integrity": "sha512-IU+77+jJ7lpw2qZ3NUuqBZFy3GuioNgXUdsL1L9tooDNTaw0TgOnwNuc+8Ns+haDaTifK97QLzmOANJtI/rGvw=="
|
"integrity": "sha512-IU+77+jJ7lpw2qZ3NUuqBZFy3GuioNgXUdsL1L9tooDNTaw0TgOnwNuc+8Ns+haDaTifK97QLzmOANJtI/rGvw=="
|
||||||
},
|
},
|
||||||
"is-base64": {
|
|
||||||
"version": "0.1.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/is-base64/-/is-base64-0.1.0.tgz",
|
|
||||||
"integrity": "sha512-WRRyllsGXJM7ZN7gPTCCQ/6wNPTRDwiWdPK66l5sJzcU/oOzcIcRRf0Rux8bkpox/1yjt0F6VJRsQOIG2qz5sg=="
|
|
||||||
},
|
|
||||||
"mime-db": {
|
"mime-db": {
|
||||||
"version": "1.48.0",
|
"version": "1.48.0",
|
||||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.48.0.tgz",
|
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.48.0.tgz",
|
||||||
@@ -41,15 +31,6 @@
|
|||||||
"version": "0.10.0",
|
"version": "0.10.0",
|
||||||
"resolved": "https://registry.npmjs.org/strftime/-/strftime-0.10.0.tgz",
|
"resolved": "https://registry.npmjs.org/strftime/-/strftime-0.10.0.tgz",
|
||||||
"integrity": "sha1-s/D6QZKVICpaKJ9ta+n0kJphcZM="
|
"integrity": "sha1-s/D6QZKVICpaKJ9ta+n0kJphcZM="
|
||||||
},
|
|
||||||
"string-to-arraybuffer": {
|
|
||||||
"version": "1.0.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/string-to-arraybuffer/-/string-to-arraybuffer-1.0.2.tgz",
|
|
||||||
"integrity": "sha512-DaGZidzi93dwjQen5I2osxR9ERS/R7B1PFyufNMnzhj+fmlDQAc1DSDIJVJhgI8Oq221efIMbABUBdPHDRt43Q==",
|
|
||||||
"requires": {
|
|
||||||
"atob-lite": "^2.0.0",
|
|
||||||
"is-base64": "^0.1.0"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,6 @@
|
|||||||
"crypto-js": "^4.0.0",
|
"crypto-js": "^4.0.0",
|
||||||
"endianness": "^8.0.2",
|
"endianness": "^8.0.2",
|
||||||
"mime-types": "^2.1.31",
|
"mime-types": "^2.1.31",
|
||||||
"strftime": "^0.10.0",
|
"strftime": "^0.10.0"
|
||||||
"string-to-arraybuffer": "^1.0.2"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +1,22 @@
|
|||||||
const CryptoJS = require('crypto-js');
|
const CryptoJS = require('crypto-js');
|
||||||
const endianness = require('endianness');
|
const endianness = require('endianness');
|
||||||
|
var crypto = require('crypto');
|
||||||
|
|
||||||
class WTVNetworkSecurity {
|
class WTVNetworkSecurity {
|
||||||
initial_shared_key = null;
|
initial_shared_key = null;
|
||||||
current_shared_key = null;
|
current_shared_key = null;
|
||||||
challenge_key = null;
|
challenge_key = null;
|
||||||
|
challenge_signed_key = null;
|
||||||
|
challenge_raw = null;
|
||||||
challenge_response = null;
|
challenge_response = null;
|
||||||
ticket_b64 = null;
|
ticket_b64 = null;
|
||||||
incarnation = 1;
|
incarnation = 0;
|
||||||
session_key1 = null;
|
session_key1 = null;
|
||||||
session_key2 = null;
|
session_key2 = null;
|
||||||
hRC4_Key1 = null;
|
hRC4_Key1 = null;
|
||||||
hRC4_Key2 = null;
|
hRC4_Key2 = null;
|
||||||
|
RC4Session = new Array();
|
||||||
|
|
||||||
zdebug = true;
|
zdebug = true;
|
||||||
|
|
||||||
constructor(wtv_initial_key = CryptoJS.lib.WordArray.random(8), wtv_incarnation = 1) {
|
constructor(wtv_initial_key = CryptoJS.lib.WordArray.random(8), wtv_incarnation = 1) {
|
||||||
@@ -29,23 +34,32 @@ class WTVNetworkSecurity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
set_incarnation(wtv_incarnation) {
|
set_incarnation(wtv_incarnation) {
|
||||||
|
if (this.incarnation != wtv_incarnation) {
|
||||||
this.incarnation = wtv_incarnation;
|
this.incarnation = wtv_incarnation;
|
||||||
this.SecureOn();
|
this.SecureOn();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
increment_incarnation() {
|
increment_incarnation() {
|
||||||
this.incarnation = this.incarnation + 1;
|
this.set_incarnation(parseInt(this.incarnation) + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
DuplicateWordArray(wa) {
|
||||||
|
return CryptoJS.lib.WordArray.create(this.wordArrayToUint8Array(wa).buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
PrepareTicket() {
|
PrepareTicket() {
|
||||||
// store last challenge response in ticket
|
// store last challenge response in ticket
|
||||||
var ticket_data = this.challenge_response;
|
var ticket_data = this.challenge_raw;
|
||||||
try {
|
try {
|
||||||
var ticket_data_enc = CryptoJS.DES.encrypt(ticket_data, this.current_shared_key, {
|
var ticket_data_enc = CryptoJS.DES.encrypt(ticket_data, this.current_shared_key, {
|
||||||
mode: CryptoJS.mode.ECB,
|
mode: CryptoJS.mode.ECB,
|
||||||
padding: CryptoJS.pad.NoPadding
|
padding: CryptoJS.pad.NoPadding
|
||||||
});
|
});
|
||||||
this.ticket_b64 = this.current_shared_key.concat(ticket_data_enc.ciphertext).toString(CryptoJS.enc.Base64);
|
// create a copy of WordArray since concat modifies the original
|
||||||
|
var current_shared_key = this.DuplicateWordArray(this.current_shared_key);
|
||||||
|
var challenge_signed_key = this.DuplicateWordArray(this.challenge_signed_key);
|
||||||
|
this.ticket_b64 = current_shared_key.concat(challenge_signed_key.concat(ticket_data_enc.ciphertext)).toString(CryptoJS.enc.Base64);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log("Error encrypting ticket: " + e.toString());
|
console.log("Error encrypting ticket: " + e.toString());
|
||||||
return null;
|
return null;
|
||||||
@@ -54,8 +68,10 @@ class WTVNetworkSecurity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
DecodeTicket(ticket_b64) {
|
DecodeTicket(ticket_b64) {
|
||||||
var ticket_hex = CryptoJS.enc.Base64.parse(ticket_b64);
|
var ticket_hex = CryptoJS.enc.Base64.parse(ticket_b64).toString(CryptoJS.enc.Hex);
|
||||||
var ticket_key = CryptoJS.enc.Hex.parse(ticket_hex.substring(0, this.current_shared_key.sigBytes));
|
var ticket_key = CryptoJS.enc.Hex.parse(ticket_hex.substring(0,16));
|
||||||
|
var challenge_key = CryptoJS.enc.Hex.parse(ticket_hex.substring(16, 32));
|
||||||
|
var challenge_enc = CryptoJS.enc.Hex.parse(ticket_hex.substring(32));
|
||||||
var ticket_dec = CryptoJS.DES.decrypt(
|
var ticket_dec = CryptoJS.DES.decrypt(
|
||||||
{
|
{
|
||||||
ciphertext: challenge_enc
|
ciphertext: challenge_enc
|
||||||
@@ -63,38 +79,39 @@ class WTVNetworkSecurity {
|
|||||||
ticket_key,
|
ticket_key,
|
||||||
{
|
{
|
||||||
mode: CryptoJS.mode.ECB,
|
mode: CryptoJS.mode.ECB,
|
||||||
padding: CryptoJS.pad.ZeroPadding
|
padding: CryptoJS.pad.NoPadding
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
this.ProcessChallenge(ticket_dec);
|
this.ProcessChallenge(ticket_dec.toString(CryptoJS.enc.Base64), challenge_key);
|
||||||
|
console.log(" * Decoded session from wtv-ticket");
|
||||||
}
|
}
|
||||||
|
|
||||||
ProcessChallenge(wtv_challenge) {
|
ProcessChallenge(wtv_challenge, key = this.current_shared_key) {
|
||||||
var challenge_raw = CryptoJS.enc.Base64.parse(wtv_challenge);
|
var challenge_raw = CryptoJS.enc.Base64.parse(wtv_challenge);
|
||||||
|
|
||||||
if (challenge_raw.sigBytes > 8) {
|
if (challenge_raw.sigBytes > 8) {
|
||||||
var challenge_raw_hex = challenge_raw.toString(CryptoJS.enc.Hex);
|
var challenge_raw_hex = challenge_raw.toString(CryptoJS.enc.Hex);
|
||||||
|
var challenge_id_hex = challenge_raw_hex.substring(0, (8 * 2));
|
||||||
var challenge_enc_hex = challenge_raw_hex.substring((8*2));
|
var challenge_enc_hex = challenge_raw_hex.substring((8*2));
|
||||||
var challenge_enc = CryptoJS.enc.Hex.parse(challenge_enc_hex);
|
var challenge_enc = CryptoJS.enc.Hex.parse(challenge_enc_hex);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
var challenge_decrypted = CryptoJS.DES.decrypt(
|
var challenge_decrypted = CryptoJS.DES.decrypt(
|
||||||
{
|
{
|
||||||
ciphertext: challenge_enc
|
ciphertext: challenge_enc
|
||||||
},
|
},
|
||||||
this.current_shared_key,
|
key,
|
||||||
{
|
{
|
||||||
mode: CryptoJS.mode.ECB,
|
mode: CryptoJS.mode.ECB,
|
||||||
padding: CryptoJS.pad.ZeroPadding
|
padding: CryptoJS.pad.NoPadding
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
var challenge_dec_hex = challenge_decrypted.toString(CryptoJS.enc.Hex);
|
var challenge_dec_hex = challenge_decrypted.toString(CryptoJS.enc.Hex);
|
||||||
var challenge_md5_challenge = CryptoJS.MD5(CryptoJS.enc.Hex.parse(challenge_dec_hex.substring(0, (80 * 2))));
|
var challenge_md5_challenge = CryptoJS.MD5(CryptoJS.enc.Hex.parse(challenge_dec_hex.substring(0, (80 * 2))));
|
||||||
|
var test = challenge_dec_hex.substring((80 * 2), (96 * 2));
|
||||||
if (challenge_dec_hex.substring((80 * 2), (96 * 2)) == challenge_md5_challenge.toString(CryptoJS.enc.Hex)) {
|
var test2 = challenge_md5_challenge.toString(CryptoJS.enc.Hex);
|
||||||
|
if (test == test2) {
|
||||||
this.current_shared_key = CryptoJS.enc.Hex.parse(challenge_dec_hex.substring((72*2), (80*2)));
|
this.current_shared_key = CryptoJS.enc.Hex.parse(challenge_dec_hex.substring((72*2), (80*2)));
|
||||||
var challenge_echo = CryptoJS.enc.Hex.parse(challenge_dec_hex.substr(0, (40*2)));
|
var challenge_echo = CryptoJS.enc.Hex.parse(challenge_dec_hex.substr(0, (40*2)));
|
||||||
|
|
||||||
@@ -102,15 +119,15 @@ class WTVNetworkSecurity {
|
|||||||
this.session_key1 = CryptoJS.enc.Hex.parse(challenge_dec_hex.substring((40*2), (56*2)));
|
this.session_key1 = CryptoJS.enc.Hex.parse(challenge_dec_hex.substring((40*2), (56*2)));
|
||||||
this.session_key2 = CryptoJS.enc.Hex.parse(challenge_dec_hex.substring((56*2), (72*2)));
|
this.session_key2 = CryptoJS.enc.Hex.parse(challenge_dec_hex.substring((56*2), (72*2)));
|
||||||
|
|
||||||
var echo_encrypted = CryptoJS.DES.encrypt(CryptoJS.MD5(challenge_echo).concat(challenge_echo), this.current_shared_key, {
|
var echo_encrypted = CryptoJS.DES.encrypt(CryptoJS.MD5(challenge_echo).concat(challenge_echo).concat(CryptoJS.enc.Utf8.parse("\x08".repeat(8))), this.current_shared_key, {
|
||||||
mode: CryptoJS.mode.ECB,
|
mode: CryptoJS.mode.ECB,
|
||||||
padding: CryptoJS.pad.NoPadding
|
padding: CryptoJS.pad.NoPadding
|
||||||
});
|
});
|
||||||
|
|
||||||
// Last bytes is just extra padding
|
// Last bytes is just extra padding
|
||||||
var challenge_response = CryptoJS.enc.Hex.parse(challenge_raw_hex.substr(0, (8 * 2))).concat(echo_encrypted.ciphertext.concat(CryptoJS.enc.Utf8.parse("\x00".repeat(8))));
|
this.challenge_raw = challenge_raw;
|
||||||
|
this.challenge_key = this.current_shared_key;
|
||||||
|
var challenge_response = CryptoJS.enc.Hex.parse(challenge_raw_hex.substr(0, (8 * 2))).concat(echo_encrypted.ciphertext);
|
||||||
return challenge_response;
|
return challenge_response;
|
||||||
} else {
|
} else {
|
||||||
throw ("Couldn't solve challenge");
|
throw ("Couldn't solve challenge");
|
||||||
@@ -134,15 +151,18 @@ class WTVNetworkSecurity {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
var random_id_question_mark = CryptoJS.lib.WordArray.random(8);
|
var challenge_id = CryptoJS.lib.WordArray.random(8);
|
||||||
|
|
||||||
var echo_me = CryptoJS.lib.WordArray.random(40);
|
var echo_me = CryptoJS.lib.WordArray.random(40);
|
||||||
this.session_key1 = CryptoJS.lib.WordArray.random(16);
|
this.session_key1 = CryptoJS.lib.WordArray.random(16);
|
||||||
this.session_key2 = CryptoJS.lib.WordArray.random(16);
|
this.session_key2 = CryptoJS.lib.WordArray.random(16);
|
||||||
var new_shared_key = CryptoJS.lib.WordArray.random(8);
|
var new_shared_key = CryptoJS.lib.WordArray.random(8);
|
||||||
|
|
||||||
var challenge_puzzle = echo_me.concat(this.session_key1.concat(this.session_key2.concat(new_shared_key)));
|
var session_key1 = this.DuplicateWordArray(this.session_key1);
|
||||||
var challenge_secret = challenge_puzzle.concat(CryptoJS.MD5(challenge_puzzle).concat(CryptoJS.enc.Hex.parse("\x00".repeat(8))));
|
var session_key2 = this.DuplicateWordArray(this.session_key2);
|
||||||
|
|
||||||
|
var challenge_puzzle = echo_me.concat(session_key1.concat(session_key2.concat(new_shared_key)));
|
||||||
|
var challenge_secret = challenge_puzzle.concat(CryptoJS.MD5(challenge_puzzle).concat(CryptoJS.enc.Hex.parse("\x08".repeat(8))));
|
||||||
|
|
||||||
// Shhhh!!
|
// Shhhh!!
|
||||||
var challenge_secreted = CryptoJS.DES.encrypt(challenge_secret, this.current_shared_key, {
|
var challenge_secreted = CryptoJS.DES.encrypt(challenge_secret, this.current_shared_key, {
|
||||||
@@ -151,14 +171,11 @@ class WTVNetworkSecurity {
|
|||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
var challenge = random_id_question_mark.concat(challenge_secreted.ciphertext);
|
var challenge = challenge_id.concat(challenge_secreted.ciphertext);
|
||||||
var challenge_b64 = challenge.toString(CryptoJS.enc.Base64);
|
var challenge_b64 = challenge.toString(CryptoJS.enc.Base64);
|
||||||
|
|
||||||
// get the expected response for when client sends it
|
// get the expected response for when client sends it
|
||||||
|
this.challenge_signed_key = this.current_shared_key;
|
||||||
this.challenge_response = this.ProcessChallenge(challenge_b64);
|
this.challenge_response = this.ProcessChallenge(challenge_b64);
|
||||||
this.challenge_key = this.current_shared_key;
|
|
||||||
|
|
||||||
this.current_shared_key = new_shared_key;
|
|
||||||
return challenge_b64;
|
return challenge_b64;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -196,59 +213,77 @@ class WTVNetworkSecurity {
|
|||||||
return new Uint8Array([].concat.apply([], result));
|
return new Uint8Array([].concat.apply([], result));
|
||||||
}
|
}
|
||||||
|
|
||||||
SecureOn() {
|
|
||||||
|
SecureOn(rc4session = null) {
|
||||||
|
console.log("Generating RC4 sessions with wtv-incarnation: " + this.incarnation);
|
||||||
|
|
||||||
var buf = new Uint8Array([0xff & this.incarnation, 0xff & (this.incarnation >> 8), 0xff & (this.incarnation >> 16), 0xff & (this.incarnation >> 24)]);
|
var buf = new Uint8Array([0xff & this.incarnation, 0xff & (this.incarnation >> 8), 0xff & (this.incarnation >> 16), 0xff & (this.incarnation >> 24)]);
|
||||||
endianness(buf, 2);
|
endianness(buf, 4);
|
||||||
var md5_digest_key1 = CryptoJS.MD5(this.session_key1.concat(CryptoJS.lib.WordArray.create(buf).concat(this.session_key1)));
|
this.hRC4_Key1 = CryptoJS.MD5(this.DuplicateWordArray(this.session_key1).concat(CryptoJS.lib.WordArray.create(buf).concat(this.DuplicateWordArray(this.session_key1))));
|
||||||
|
this.hRC4_Key2 = CryptoJS.MD5(this.DuplicateWordArray(this.session_key2).concat(CryptoJS.lib.WordArray.create(buf).concat(this.DuplicateWordArray(this.session_key2))));
|
||||||
var next_incarnation = this.incarnation + 1;
|
switch (rc4session) {
|
||||||
buf = new Uint8Array([0xff & next_incarnation, 0xff & (next_incarnation >> 8), 0xff & (next_incarnation >> 16), 0xff & (next_incarnation >> 24)]);
|
case 0:
|
||||||
endianness(buf, 2);
|
this.RC4Session[0] = crypto.createCipheriv('rc4', Buffer.from(this.wordArrayToUint8Array(this.hRC4_Key1)),'');
|
||||||
var md5_digest_key2 = CryptoJS.MD5(this.session_key2.concat(CryptoJS.lib.WordArray.create(buf).concat(this.session_key2)));
|
break;
|
||||||
|
case 1:
|
||||||
|
this.RC4Session[1] = crypto.createDecipheriv('rc4', Buffer.from(this.wordArrayToUint8Array(this.hRC4_Key1)),'');
|
||||||
this.hRC4_Key1 = md5_digest_key1;
|
break;
|
||||||
this.hRC4_Key2 = md5_digest_key2;
|
case 2:
|
||||||
}
|
this.RC4Session[2] = crypto.createCipheriv('rc4', Buffer.from(this.wordArrayToUint8Array(this.hRC4_Key2)),'');
|
||||||
|
break;
|
||||||
EncryptKey1(data) {
|
case 3:
|
||||||
return Buffer.from(this.wordArrayToUint8Array(this.Encrypt(this.hRC4_Key1, CryptoJS.lib.WordArray.create(data)).ciphertext));
|
this.RC4Session[3] = crypto.createDecipheriv('rc4', Buffer.from(this.wordArrayToUint8Array(this.hRC4_Key2)),'');
|
||||||
}
|
break;
|
||||||
|
default:
|
||||||
EncryptKey2(data) {
|
this.RC4Session[0] = crypto.createCipheriv('rc4', Buffer.from(this.wordArrayToUint8Array(this.hRC4_Key1)), '');
|
||||||
return Buffer.from(this.wordArrayToUint8Array(this.Encrypt(this.hRC4_Key2, CryptoJS.lib.WordArray.create(data)).ciphertext));
|
this.RC4Session[1] = crypto.createDecipheriv('rc4', Buffer.from(this.wordArrayToUint8Array(this.hRC4_Key1)), '');
|
||||||
}
|
this.RC4Session[2] = crypto.createCipheriv('rc4', Buffer.from(this.wordArrayToUint8Array(this.hRC4_Key2)), '');
|
||||||
|
this.RC4Session[3] = crypto.createDecipheriv('rc4', Buffer.from(this.wordArrayToUint8Array(this.hRC4_Key2)), '');
|
||||||
Encrypt(key, data) {
|
break;
|
||||||
try {
|
|
||||||
if (key != null) {
|
|
||||||
return CryptoJS.RC4.encrypt(data, key, {
|
|
||||||
mode: CryptoJS.mode.ECB,
|
|
||||||
padding: CryptoJS.pad.NoPadding
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
throw ("Invalid RC4 encryption key: " + e.toString());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DecryptKey1(data) {
|
|
||||||
return Buffer.from(this.wordArrayToUint8Array(this.Decrypt(this.hRC4_Key1, data)));
|
NewRC4Session(num) {
|
||||||
|
this.SecureOn(num);
|
||||||
}
|
}
|
||||||
|
|
||||||
DecryptKey2(data) {
|
Encrypt(keynum, data) {
|
||||||
return Buffer.from(this.wordArrayToUint8Array(this.Decrypt(this.hRC4_Key2, data)));
|
var session_id;
|
||||||
|
switch (keynum) {
|
||||||
|
case 0:
|
||||||
|
session_id = 0;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
session_id = 2
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw ("Invalid key option (0 or 1 only)");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!this.RC4Session[session_id]) {
|
||||||
|
this.NewRC4Session(session_id);
|
||||||
|
}
|
||||||
|
return this.RC4Session[session_id].update(Buffer.from(this.wordArrayToUint8Array(data)));
|
||||||
}
|
}
|
||||||
|
|
||||||
Decrypt(key, data) {
|
Decrypt(keynum, data) {
|
||||||
try {
|
var session_id;
|
||||||
return CryptoJS.RC4.decrypt(data, key, {
|
switch (keynum) {
|
||||||
mode: CryptoJS.mode.ECB,
|
case 0:
|
||||||
padding: CryptoJS.pad.NoPadding
|
session_id = 1;
|
||||||
});
|
break;
|
||||||
} catch (e) {
|
case 1:
|
||||||
throw ("Invalid RC4 encryption key: " + e.toString());
|
session_id = 3;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw ("Invalid key option (0 or 1 only)");
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
if (!this.RC4Session[session_id]) {
|
||||||
|
this.NewRC4Session(session_id);
|
||||||
|
}
|
||||||
|
return this.RC4Session[session_id].update(Buffer.from(this.wordArrayToUint8Array(data)));
|
||||||
}
|
}
|
||||||
|
|
||||||
Test() {
|
Test() {
|
||||||
|
|||||||
Reference in New Issue
Block a user