Sign packets

This commit is contained in:
jude 2023-03-04 14:19:26 +00:00
parent ab629a78b4
commit 96fe20503a
6 changed files with 80 additions and 31 deletions

View File

@ -1,4 +1,4 @@
import { generate_keypair } from "./paillier.js";
import { generate_rsa_keypair } from "./rsa.js";
import { generate_rsa_keypair, RsaPubKey } from "./rsa.js";
export { generate_keypair, generate_rsa_keypair };
export { generate_keypair, generate_rsa_keypair, RsaPubKey };

View File

@ -3,18 +3,29 @@ import { mod_exp, mod_inv } from "./math.js";
let p, q, pubKey, privKey;
class PubKey {
constructor(p, q) {
this.n = p * q;
this.e = 65537n;
export class RsaPubKey {
constructor(n, e) {
this.n = n;
this.e = e;
}
encrypt(m) {
return mod_exp(m, this.e, this.n);
}
toJSON() {
return {
n: "0x" + this.n.toString(16),
e: "0x" + this.e.toString(16),
};
}
static fromJSON(data) {
return new RsaPubKey(BigInt(data.n), BigInt(data.e));
}
}
class PrivKey {
class RsaPrivKey {
constructor(p, q) {
this.n = p * q;
this.d = mod_inv(65537n, (q - 1n) * (p - 1n));
@ -40,8 +51,8 @@ export function generate_rsa_keypair() {
q = BigInt(window.sessionStorage.getItem("rsa_q"));
}
pubKey = new PubKey(p, q);
privKey = new PrivKey(p, q);
pubKey = new RsaPubKey(p * q, 65537n);
privKey = new RsaPrivKey(p, q);
return { pubKey, privKey };
}

View File

@ -36,11 +36,11 @@ export class Game {
return Object.values(this.players).filter((p) => p.isPlaying)[0];
}
addPlayer(id, is_us) {
addPlayer(id, is_us, pubkey) {
let is_new = this.players[id] === undefined;
if (this.isWaiting()) {
this.players[id] = new Player(id, is_us);
this.players[id] = new Player(id, is_us, pubkey);
if (is_us) {
this.us = this.players[id];
}

View File

@ -26,14 +26,29 @@ document.addEventListener("DOMContentLoaded", () => {
socket.on("connect", () => {
window.console.log("Connected!");
window.console.log(`We are: ${ID}`);
socket.emit("message", Packet.createAnnounce());
game.addPlayer(ID, true);
socket.emit("message", Packet.createAnnounce(window.rsa));
game.addPlayer(ID, true, window.rsa.pubKey);
});
socket.on("message", async (data) => {
socket.on("message", async (packet) => {
let data = packet.payload;
window.console.log(data);
// todo validate signature
const sender = game.players[data.author];
if (sender === undefined) {
window.console.warn(
`Not able to verify signature on packet ${data.id} as the sender is unknown.`
);
} else {
let sig = BigInt(packet.sig);
// decrypt and compare signature
let dehash = sender.rsaPubKey.encrypt(sig).toString(16);
let hash = CryptoJS.SHA3(JSON.stringify(data)).toString();
if (dehash !== hash) {
window.console.error(`Signature invalid! Ignoring packet ${data.id}.`);
return;
}
}
switch (data.type) {
case "RANDOM":
@ -67,11 +82,11 @@ document.addEventListener("ANNOUNCE", (ev) => {
const data = ev.detail;
if (data.author === ID) return;
let is_new = game.addPlayer(data.author, false);
let is_new = game.addPlayer(data.author, false, data.rsaPubKey);
// When a new player is seen, all announce to ensure they know all players.
if (is_new) {
socket.emit("message", Packet.createAnnounce());
socket.emit("message", Packet.createAnnounce(window.rsa));
}
});

View File

@ -9,30 +9,51 @@ export class Packet {
};
}
static createAnnounce() {
static _sign(data) {
// compute hash of data
let hash = CryptoJS.SHA3(JSON.stringify(data));
let res = 0n;
for (let word32 of hash.words) {
// remove any sign
let bi = BigInt.asUintN(32, BigInt(word32));
res = (res << 32n) | bi;
}
// sign hash
let sig = window.rsa.privKey.decrypt(res);
// return new packet
return {
...this._createBase("ANNOUNCE"),
sig: "0x" + sig.toString(16),
payload: data,
};
}
static createAnnounce(rsaKeyPair) {
return this._sign({
...this._createBase("ANNOUNCE"),
rsaPubKey: rsaKeyPair.pubKey.toJSON(),
});
}
static createDisconnect() {
return this._createBase("DISCONNECT");
return this._sign(this._createBase("DISCONNECT"));
}
static createKeepAlive() {
return this._createBase("KEEPALIVE");
return this._sign(this._createBase("KEEPALIVE"));
}
static createSetReady(nowReady) {
return {
return this._sign({
...this._createBase("ACT"),
action: "READY",
ready: nowReady,
};
});
}
static createBarrierSignal() {
return this._createBase("BARRIER");
return this._sign(this._createBase("BARRIER"));
}
static createRegionClaim(region) {
@ -43,27 +64,27 @@ export class Packet {
}
static createAction(action, startRegion, endRegion, amount) {
return {
return this._sign({
...this._createBase("ACT"),
startRegion: startRegion,
endRegion: endRegion,
strength: amount,
action: action,
};
});
}
static createDefense(amount) {
return {
return this._sign({
...this._createBase("ACT"),
action: "DEFENSE",
amount: amount,
};
});
}
static createEndTurn() {
return {
return this._sign({
...this._createBase("ACT"),
action: "END",
};
});
}
}

View File

@ -1,5 +1,6 @@
import { Packet } from "./packet.js";
import { socket } from "./main.js";
import { RsaPubKey } from "../crypto/rsa.js";
// Timeout to consider a player disconnected
const TIMEOUT = 30_000;
@ -11,10 +12,11 @@ const PHASE_FORTIFY = 3;
let totalDice = 0;
export class Player {
constructor(id, local) {
constructor(id, local, pubkey) {
this.timeout = null;
this.id = id;
this.ready = false;
this.rsaPubKey = RsaPubKey.fromJSON(pubkey);
// Data which is reset every turn
this.isPlaying = false;