Last active
August 29, 2015 14:01
-
-
Save 19h/f3b4b197a40aeb663341 to your computer and use it in GitHub Desktop.
End to end encrypted TCP-based RPC server and client. (for training DiffieHellman and CipherIV with our intern @wtr7) — Tested with io.js 1.2.0 on OS X Yosemite (10.10.3).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
["crypto", "net"].forEach(function (m) { global[m] = require(m) }) | |
var api = { | |
key: Buffer([ | |
0x01, 0xB9, 0x43, 0xE4, 0x8B, 0xBD, 0x33, 0x91, 0xF1, 0xE1, 0x25, 0x32, 0xEC, 0x3B, 0xD3, 0x36, | |
0x5B, 0xB9, 0x5B, 0x96, 0xD9, 0xA0, 0xF5, 0x22, 0x54, 0x31, 0x99, 0xF8, 0xB5, 0xBF, 0x4E, 0xE3 | |
]), | |
iv: Buffer([ | |
0x4d, 0x4e, 0x34, 0x58, 0x37, 0x66, 0x61, 0x43, 0x4f, 0x52, 0x34, 0x50, 0x45, 0x43, 0x38, 0x4b | |
]), | |
/* token */ | |
api_token: Buffer( | |
"bk7CPdtaEvO7WwJrSpPtvQ7Oi/0=" | |
), | |
/* csum */ | |
api_challenge: Buffer([ | |
0x30, 0x81, 0xc4, 0x7e, 0x26, 0xaf, 0x18, 0x45, 0x80, 0x4c, 0xab, 0xb8, 0x3c, 0x3d, 0x27, 0x04, | |
0x6d, 0x48, 0x78, 0x40, 0xd1, 0xb8, 0xa1, 0x71, 0xe2, 0xb6, 0x5e, 0xfc, 0x2a, 0x48, 0x80, 0x38 | |
]), | |
dec: function(data, key, iv) { | |
var decipher = crypto.createDecipheriv('camellia-256-cfb8', key || this.key, iv || this.iv); | |
return Buffer.concat([ | |
decipher.update(data), | |
decipher.final() | |
]); | |
}, | |
enc: function(data, key, iv) { | |
var encipher = crypto.createCipheriv('camellia-256-cfb8', key || this.key, iv || this.iv); | |
return Buffer.concat([ | |
encipher.update(data), | |
encipher.final() | |
]); | |
}, | |
dHellman: crypto.getDiffieHellman('modp16') | |
} | |
api.dHellman.generateKeys(); | |
var client = net.connect({ | |
host: "127.0.0.1", | |
port: 0xFFFE | |
}); | |
/* auth: */ | |
var auth = Buffer([ 0x78, 0x70, 0x61, /* key */ /*, 0x78, 0x70, 0x61, */ /* csum */ ]); | |
var queue = (function () { | |
var stack = {}; var sexpiry = {}; | |
return { | |
fire: function (id, data, error) { | |
if (stack[id]) { | |
stack[id](error, data); | |
delete stack[id]; | |
} | |
if (sexpiry[id]) { | |
clearTimeout(sexpiry[id]); | |
delete sexpiry[id]; | |
} | |
}, | |
add: function (cb, expiry) { | |
var id = crypto.randomBytes(32).toString("hex") | |
stack[id] = cb; | |
if (expiry) { | |
sexpiry[id] = setTimeout(function () { | |
delete stack[id]; | |
}, expiry); | |
} | |
return id; | |
} | |
} | |
})(); | |
var publicKey, secret; | |
client.on("connect", function () { | |
var handshake = Buffer.concat([ | |
auth, api.api_token, | |
auth, api.api_challenge | |
]); | |
client.write(handshake) | |
var authed; | |
client.on("data", function (chunk) { | |
if ( !authed ) | |
if ( chunk[0] === 0xc8 ) { | |
authed = true; | |
return client.write(Buffer.concat([Buffer([55]), api.dHellman.getPublicKey()])); | |
} else | |
// bad request. must ACK the handshake and respond 0xc8 | |
client.end(); | |
if ( !publicKey ) { | |
if ( chunk[0] === 55 ) { | |
publicKey = chunk.slice(1, chunk.length); | |
secret = api.dHellman.computeSecret(publicKey).slice(0, 32); | |
} | |
} | |
try { | |
chunk = api.dec(chunk, secret); | |
chunk = JSON.parse(chunk.toString()); | |
queue.fire(chunk.id, chunk.result, chunk["error"]); | |
} catch(e) {} | |
}); | |
}) | |
client.rwrite = function (data) { | |
this.write(api.enc(JSON.stringify(data), secret)); | |
} | |
setTimeout(function () { | |
// somewhere over the rainbow | |
var id = queue.add(function (err, result) { | |
console.log("Response:", result); | |
}); | |
// write payload to socket | |
client.rwrite({ | |
method: "time", | |
id: id | |
}); | |
}, 5000) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
["crypto", "net"].forEach(function (m) { global[m] = require(m) }) | |
// crypto | |
var api = Object.create({ | |
key: Buffer([ | |
0x01, 0xB9, 0x43, 0xE4, 0x8B, 0xBD, 0x33, 0x91, 0xF1, 0xE1, 0x25, 0x32, 0xEC, 0x3B, 0xD3, 0x36, | |
0x5B, 0xB9, 0x5B, 0x96, 0xD9, 0xA0, 0xF5, 0x22, 0x54, 0x31, 0x99, 0xF8, 0xB5, 0xBF, 0x4E, 0xE3 | |
]), | |
iv: Buffer([ | |
0x4d, 0x4e, 0x34, 0x58, 0x37, 0x66, 0x61, 0x43, 0x4f, 0x52, 0x34, 0x50, 0x45, 0x43, 0x38, 0x4b | |
]), | |
pKey: Buffer([ | |
0x26, 0xce, 0xa1, 0xe5, 0x5a, 0xd3, 0x7f, 0x94, 0x77, 0x66, 0xcd, 0x94, 0x76, 0xfd, 0xc7, 0x85, | |
0xe3, 0x58, 0x19, 0x35, 0x9d, 0x84, 0xb0, 0xab, 0x9f, 0x2a, 0x7b, 0xc9, 0x70, 0x96, 0xaa, 0xa0 | |
]), | |
pIv: Buffer([ | |
0x8e, 0x0c, 0x9d, 0x7e, 0x9c, 0x2e, 0xf6, 0x7d, 0xf1, 0xad, 0x04, 0xe8, 0xad, 0x10, 0x0f, 0xe5 | |
]), | |
dec: function(data, key, iv) { | |
var decipher = crypto.createDecipheriv('camellia-256-cfb8', key || this.key, iv || this.iv); | |
return Buffer.concat([ | |
decipher.update(data), | |
decipher.final() | |
]); | |
}, | |
enc: function(data, key, iv) { | |
var encipher = crypto.createCipheriv('camellia-256-cfb8', key || this.key, iv || this.iv); | |
return Buffer.concat([ | |
encipher.update(data), | |
encipher.final() | |
]); | |
}, | |
dHellman: crypto.getDiffieHellman('modp16'), | |
verifyToken: function (token, csum) { | |
!Buffer.isBuffer(token) && (token = Buffer(token)); | |
try { | |
var rc = this.dec(csum, this.pKey, this.pIv), i = 0; | |
while ( i++ ) | |
if ( rc[i] !== token[i] ) | |
return false; | |
return true; | |
} catch(e) { | |
return false; | |
} | |
}, | |
generateToken: function () { | |
var token = crypto.randomBytes(20).toString("base64").substr(0, 32); | |
return { | |
token: token, | |
csum: this.enc(token, this.pKey, this.pIv) | |
} | |
} | |
}); | |
api.dHellman.generateKeys(); | |
var methods = { | |
time: function () { | |
return Date.now() | |
} | |
} | |
net.createServer(function (sock) { | |
var me = { | |
token: void 0, | |
csum: void 0, | |
publicKey: void 0, | |
secret: void 0 | |
}; | |
sock.on("data", function (chunk) { | |
if ( !me.token ) { | |
// got auth request | |
if ( chunk[0] === 0x78 && chunk[1] === 0x70 && chunk[2] === 0x61 ) { | |
var i = 3; | |
while(i++ && chunk[i]) | |
if ( chunk[i] === 0x78 && chunk[i + 1] === 0x70 && chunk[i + 2] === 0x61 ) { | |
var token = chunk.slice(3, i), csum = chunk.slice(i + 3); | |
if (api.verifyToken(token, csum)) { | |
me.token = token, | |
me.csum = csum; | |
return sock.write(Buffer([200])); | |
} else { | |
return sock.end(); | |
} | |
} | |
} | |
sock.end(); | |
} | |
if ( !me.publicKey ) { | |
if ( chunk[0] === 55 ) { | |
sock.write(Buffer.concat([Buffer([55]), api.dHellman.getPublicKey()])); | |
me.publicKey = chunk.slice(1, chunk.length); | |
me.secret = api.dHellman.computeSecret(me.publicKey).slice(0, 32); | |
return; | |
} | |
return; | |
} | |
try { | |
chunk = api.dec(chunk, me.secret); | |
chunk = JSON.parse(chunk.toString()); | |
if ( !chunk.id ) | |
return; | |
if ( methods[chunk.method] ) { | |
sock.write(api.enc(JSON.stringify({ | |
id: chunk.id, | |
result: methods[chunk.method]() | |
}), me.secret)); | |
} else { | |
sock.write(api.enc(JSON.stringify({ | |
id: chunk.id, | |
result: 0, | |
error: 1 | |
}), me.secret)); | |
} | |
} catch(e) {} | |
}); | |
}).listen(0xFFFE); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment