more encryption stuff, lots of progress

This commit is contained in:
mhsjlw 2016-06-16 07:11:22 -04:00
commit 26dca46471
4 changed files with 123 additions and 57 deletions

View file

@ -11,7 +11,7 @@ if(process.argv.length !=4) {
var server = pmp.createServer({
host: process.argv[2],
port: parseInt(process.argv[3]),
name: 'MCPE;Minecraft: PE Server;70 70;0.14.3;0;20'
name: 'MCPE;Minecraft: PE Server;81 81;0.15.0;0;20'
});
server.on('connection', function(client) {

25
jwt.js

File diff suppressed because one or more lines are too long

View file

@ -17,10 +17,12 @@
],
"license": "MIT",
"dependencies": {
"asn1": "^0.2.3",
"bn.js": "^4.11.4",
"jwt-simple": "^0.5.0",
"prismarine-nbt": "^1.0.0",
"protodef": "^1.2.0",
"raknet": "^1.7.3",
"raknet": "^1.7.4",
"uuid-1345": "^0.99.6"
},
"devDependencies": {},

View file

@ -4,14 +4,33 @@ const zlib = require('zlib');
const ProtoDef = require('protodef').ProtoDef;
const jwt = require('jwt-simple');
const crypto = require('crypto');
const Ber = require('asn1').Ber;
// const BN = require('bn.js');
const batchProto = new ProtoDef();
batchProto.addTypes(require("./datatypes/minecraft"));
batchProto.addType("insideBatch",["endOfArray",{"type":["buffer",{"countType":"i32"}]}]);
batchProto.addType("insideBatch", ["endOfArray", {
"type": ["buffer", {
"countType": "i32"
}]
}]);
const dataProto = new ProtoDef();
dataProto.addType("data_chain", [ "container", [ { "name":"chain", "type":[ "pstring", { "countType":"li32" } ] }, { "name":"clientData", "type":[ "pstring", { "countType":"li32" } ] } ] ]);
dataProto.addType("data_chain", ["container", [{
"name": "chain",
"type": ["pstring", {
"countType": "li32"
}]
}, {
"name": "clientData",
"type": ["pstring", {
"countType": "li32"
}]
}]]);
const secret = 'MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE8ELkixyLcwlZryUQcu1TvPOmI2B7vX83ndnWRUaXm74wFfa5f/lwQNTfrLVHa2PmenpGI6JhIMUJaWZrjmMj90NoKNFSNBuKdm8rYiXsfaz3K36x/1U26HpG0ZxK/V1V';
const PUBLIC_KEY = 'MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE8ELkixyLcwlZryUQcu1TvPOmI2B7vX83ndnWRUaXm74wFfa5f/lwQNTfrLVHa2PmenpGI6JhIMUJaWZrjmMj90NoKNFSNBuKdm8rYiXsfaz3K36x/1U26HpG0ZxK/V1V';
var encryptionEnabled = false;
var sendCounter = 0;
function createServer(options) {
options = options || {};
@ -22,8 +41,8 @@ function createServer(options) {
19132;
var host = options.host || '0.0.0.0';
options.customPackets=require("../data/protocol");
options.customTypes=require("./datatypes/minecraft");
options.customPackets = require("../data/protocol");
options.customTypes = require("./datatypes/minecraft");
var server = raknet.createServer(options);
server.name = options.name || "Minecraft Server";
@ -31,8 +50,8 @@ function createServer(options) {
server.maxPlayers = options['max-players'] || 20;
server.playerCount = 0;
server.on("connection", function (client) {
client.on("mcpe",packet => client.emit(packet.name,packet.params));
server.on("connection", function(client) {
client.on("mcpe", packet => client.emit(packet.name, packet.params));
client.on("game_login", packet => {
var body = packet.body;
@ -44,7 +63,7 @@ function createServer(options) {
var chain1 = parsed.data.chain.chain[0];
var chain2 = parsed.data.chain.chain[1].replace('\n', '');
var decode1 = jwt.decode(chain1, secret, 'ES384');
var decode1 = jwt.decode(chain1, PUBLIC_KEY, 'ES384');
var nextKey1 = decode1.identityPublicKey;
var decode2 = jwt.decode(chain2, nextKey1, 'ES384');
@ -57,41 +76,111 @@ function createServer(options) {
client.identity = decode2.extraData.identity;
client.displayName = decode2.extraData.displayName;
client.XUID = decode2.extraData.XUID;
client.emit('login', {displayName: client.displayName, randomId: client.randomId, skinData: client.skinData, skinId: client.skinId, identity: client.identity, XUID: client.XUID})
client.ecdh = crypto.createECDH('secp192k1');
// console.log(nextKey2);
// client.secret = client.ecdh.computeSecret(nextKey2, 'base64');
// console.log(client.edch.getPublicKey('base64'));
var reader = new Ber.Reader(new Buffer(nextKey2, "base64"));
reader.readSequence();
reader.readSequence();
reader.readOID();
reader.readOID();
var pubKey = new Buffer(reader.readString(Ber.BitString, true)).slice(1);
var ec = crypto.createECDH('secp384r1');
ec.generateKeys();
client.sharedSecret = ec.computeSecret(pubKey);
client.secretKeyBytes = crypto.createHash('sha256').update(client.sharedSecret + "SO SECRET VERY SECURE").digest('binary');
// console.log(client.secretKeyBytes.length); => 32
client.writeMCPE('server_to_client_handshake', {
publicKey: client.edch.getPublicKey('base64'),
serverToken: "SO SECRET VERY SECURE"
publicKey: ec.getPublicKey('base64'),
serverToken: "SO SECRET VERY SECURE" // obviously, this is super secure (it's not, change it)
});
encryptionEnabled = true;
customPackets['types']['encapsulated_packet'][1][1]['type'][1]['fields']['mcpe']='restBuffer'; client.encapsulatedPacketParser.proto.addTypes(merge(require('raknet').protocol,customPackets).types);
client.emit('login', {
displayName: client.displayName,
randomId: client.randomId,
skinData: client.skinData,
skinId: client.skinId,
identity: client.identity,
XUID: client.XUID
});
});
client.writeMCPE = (name,packet) => {
client.writeEncapsulated("mcpe",{
name:name,
params:packet
});
client.writeMCPE = (name, packet) => {
if (!encryptionEnabled) {
client.writeEncapsulated("mcpe", {
name: name,
params: packet
});
} else {
sendCounter += 1;
// sendCounter.add(1);
// client.writeEncapsulated("mcpe", {
// name: name,
// params: packet
// });
}
};
client.writeBatch=function(packets) {
const payload=zlib.deflateSync(batchProto.createPacketBuffer("insideBatch",
packets.map(packet =>
client.encapsulatedPacketSerializer.createPacketBuffer(packet).slice(1))));
client.writeMCPE("batch",{
payload:payload
});
client.writeBatch = function(packets) {
if (!encryptionEnabled) {
const payload = zlib.deflateSync(batchProto.createPacketBuffer("insideBatch",
packets.map(packet =>
client.encapsulatedPacketSerializer.createPacketBuffer(packet).slice(1))));
client.writeMCPE("batch", {
payload: payload
});
} else {
sendCounter += 1;
// sendCounter.add(1);
// const payload = zlib.deflateSync(batchProto.createPacketBuffer("insideBatch",
// packets.map(packet =>
// client.encapsulatedPacketSerializer.createPacketBuffer(packet).slice(1))));
//
// client.writeMCPE("batch", {
// payload: payload
// });
}
};
client.on('batch', function(packet) {
var buf = zlib.inflateSync(packet.payload);
var packets=batchProto.parsePacketBuffer("insideBatch",buf).data;
packets.forEach(packet => client.readEncapsulatedPacket(Buffer.concat([new Buffer([0xfe]),packet])));
var packets = batchProto.parsePacketBuffer("insideBatch", buf).data;
if (!encryptionEnabled) {
packets.forEach(packet => client.readEncapsulatedPacket(Buffer.concat([new Buffer([0xfe]), packet])));
} else {
sendCounter += 1;
// sendCounter.add(1);
// packets.forEach(packet => client.readEncapsulatedPacket(Buffer.concat([new Buffer([0xfe]),packet])));
}
});
});
return server;
}
module.exports = createServer;
// http://stackoverflow.com/questions/19236327/nodejs-sha256-password-encryption
var AES = {};
AES.decrypt = function(cryptkey, iv, encryptdata) {
encryptdata = new Buffer(encryptdata, 'base64').toString('binary');
var decipher = crypto.createDecipheriv('aes-256-cbc', cryptkey, iv),
decoded = decipher.update(encryptdata, 'binary', 'utf8');
decoded += decipher.final('utf8');
return decoded;
}
AES.encrypt = function(cryptkey, iv, cleardata) {
var encipher = crypto.createCipheriv('aes-256-cbc', cryptkey, iv),
encryptdata = encipher.update(cleardata, 'utf8', 'binary');
encryptdata += encipher.final('binary');
encode_encryptdata = new Buffer(encryptdata, 'binary').toString('base64');
return encode_encryptdata;
}