Skip to content

Commit

Permalink
Do encryption entirely on Client
Browse files Browse the repository at this point in the history
  • Loading branch information
MacaylaMarvelous81 committed Aug 18, 2024
1 parent 5608c32 commit d066914
Show file tree
Hide file tree
Showing 2 changed files with 17 additions and 24 deletions.
9 changes: 2 additions & 7 deletions app.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import getPort, { portNumbers } from 'get-port';
import { WebSocketServer } from 'ws';
import { BrowserWindow, app, ipcMain } from 'electron';
import path from 'node:path'
import crypto from 'node:crypto';
import { Client } from './websocket/client.js';

const port = await getPort({
Expand All @@ -14,10 +13,6 @@ const wss = new WebSocketServer({
return protocols.has('com.microsoft.minecraft.wsencrypt') ? 'com.microsoft.minecraft.wsencrypt' : false;
}
});
const ecdh = crypto.createECDH('secp384r1');
ecdh.generateKeys();

const salt = crypto.randomBytes(16);

console.log(`Server started on port ${ port }`);

Expand All @@ -30,9 +25,9 @@ wss.on('connection', async (ws) => {

sendAllRenderers('connection');

const client = new Client(ws, ecdh);
const client = new Client(ws);

await client.enableEncryption(salt);
await client.enableEncryption();
client.subscribeEvent('PlayerDied');
client.subscribeEvent('ItemUsed');
client.subscribeEvent('PlayerMessage');
Expand Down
32 changes: 15 additions & 17 deletions websocket/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,25 @@ import crypto from 'node:crypto';
import { buildCommandRequest, buildSubscription } from './requests.js';
import ecKeyUtils from 'eckey-utils';

const asn1Header = Buffer.from("3076301006072a8648ce3d020106052b81040022036200", "hex");

export class Client {
static clients = [];

#ws;
#ecdh;
#publicKey;
#salt;
#commandRequests = {};
#gameEventHandlers = [];
#cipher;
#decipher;

constructor(ws, ecdh) {
constructor(ws) {
this.#ws = ws;
this.#ecdh = ecdh;
this.#ecdh = crypto.createECDH('secp384r1');
this.#publicKey = this.#ecdh.generateKeys();
this.#salt = crypto.randomBytes(16);

ws.on('message', this.#handleMessage.bind(this));

Expand All @@ -29,26 +35,18 @@ export class Client {
this.#send(JSON.stringify(buildSubscription(eventName, crypto.randomUUID())));
}

async enableEncryption(salt) {
const encodedKey = this.#ecdh.getPublicKey('base64');
const encodedSalt = salt.toString('base64');
async enableEncryption() {
const encodedKey = Buffer.concat([ asn1Header, this.#ecdh.getPublicKey() ]).toString('base64');
const encodedSalt = this.#salt.toString('base64');
const body = await this.execute(`enableencryption "${ encodedKey }" "${ encodedSalt }"`);

const pemKey = crypto.createPublicKey({
key: Buffer.from(body.publicKey, 'base64'),
type: 'spki',
format: 'der'
}).export({
type: 'spki',
format: 'pem'
});
const playerKey = ecKeyUtils.parsePem(pemKey).publicKey;
const playerKey = Buffer.from(body.publicKey, 'base64').subarray(asn1Header.length);

const sharedSecret = this.#ecdh.computeSecret(playerKey);
const secretKey = crypto.hash('sha256', Buffer.concat([ salt, sharedSecret ]), 'buffer');
const secretKey = crypto.hash('sha256', Buffer.concat([ this.#salt, sharedSecret ]), 'buffer');

this.#cipher = crypto.createCipheriv('aes-256-cfb', secretKey, secretKey.subarray(0, 16));
this.#decipher = crypto.createDecipheriv('aes-256-cfb', secretKey, secretKey.subarray(0, 16));
this.#cipher = crypto.createCipheriv('aes-256-cfb8', secretKey, secretKey.subarray(0, 16));
this.#decipher = crypto.createDecipheriv('aes-256-cfb8', secretKey, secretKey.subarray(0, 16));
this.#cipher.setAutoPadding(false);
this.#decipher.setAutoPadding(false);
}
Expand Down

0 comments on commit d066914

Please sign in to comment.