From 8184b0b25161e4f049391f25781cd7d16ba982ce Mon Sep 17 00:00:00 2001 From: LePremierHomme Date: Mon, 22 Feb 2021 09:46:24 +0200 Subject: [PATCH] JSON encoding to use protobuf instead --- lib/p2p/Framer.ts | 3 ++- lib/p2p/Parser.ts | 3 ++- lib/p2p/Peer.ts | 11 +++++------ lib/p2p/packets/Packet.ts | 13 ------------- lib/p2p/packets/types/SessionInitPacket.ts | 18 ++++++++++++++++-- lib/p2p/packets/utils.ts | 8 ++++++++ npm-shrinkwrap.json | 4 +++- package.json | 2 +- 8 files changed, 37 insertions(+), 25 deletions(-) diff --git a/lib/p2p/Framer.ts b/lib/p2p/Framer.ts index 174f741..8273573 100644 --- a/lib/p2p/Framer.ts +++ b/lib/p2p/Framer.ts @@ -5,6 +5,7 @@ import { randomBytes } from '../utils/cryptoUtils'; import errors from './errors'; import OpenDEXnetwork from './Network'; import Packet from './packets/Packet'; +import { calcChecksum } from './packets/utils'; type WireMsgHeader = { magic?: number; @@ -69,7 +70,7 @@ class Framer { msg.writeUInt32LE(packet.type, 8); // checksum - msg.writeUInt32LE(packet.checksum(), 12); + msg.writeUInt32LE(calcChecksum(packetRaw), 12); // payload packetRaw.copy(msg, 16); diff --git a/lib/p2p/Parser.ts b/lib/p2p/Parser.ts index 6d5b95a..4f283d2 100644 --- a/lib/p2p/Parser.ts +++ b/lib/p2p/Parser.ts @@ -4,6 +4,7 @@ import Framer, { WireMsgHeader } from './Framer'; import { PacketType } from './packets'; import Packet, { isPacket } from './packets/Packet'; import * as packetTypes from './packets/types'; +import { calcChecksum } from './packets/utils'; interface Parser { on(event: 'packet', packet: (order: Packet) => void): this; @@ -181,7 +182,7 @@ class Parser extends EventEmitter { } const packet = packetOrPbObj; - if (header.checksum && header.checksum !== packet.checksum()) { + if (header.checksum && header.checksum !== calcChecksum(payload)) { throw errors.PARSER_DATA_INTEGRITY_ERR(`${PacketType[header.type]} ${JSON.stringify(packet)}`); } diff --git a/lib/p2p/Peer.ts b/lib/p2p/Peer.ts index a9914d0..6f83e81 100644 --- a/lib/p2p/Peer.ts +++ b/lib/p2p/Peer.ts @@ -1,7 +1,6 @@ import assert from 'assert'; import { createECDH, createHash } from 'crypto'; import { EventEmitter } from 'events'; -import stringify from 'json-stable-stringify'; import net, { Socket } from 'net'; import secp256k1 from 'secp256k1'; import { SocksClient, SocksClientOptions } from 'socks'; @@ -886,7 +885,7 @@ class Peer extends EventEmitter { expectedNodePubKey?: string, ) => { const body = packet.body!; - const { sign, ...bodyWithoutSign } = body; + const { sign, ...innerBody } = body; /** The pub key of the node that sent the init packet. */ const sourceNodePubKey = body.nodePubKey; /** The pub key of the node that the init packet is intended for. */ @@ -906,7 +905,7 @@ class Peer extends EventEmitter { } // verify that the msg was signed by the peer - const msg = stringify(bodyWithoutSign); + const msg = packets.SessionInitPacket.serializeInnerBody(innerBody); const msgHash = createHash('sha256').update(msg).digest(); const verified = secp256k1.verify(msgHash, Buffer.from(sign, 'hex'), Buffer.from(sourceNodePubKey, 'hex')); @@ -1057,7 +1056,7 @@ class Peer extends EventEmitter { ownVersion: string; expectedNodePubKey: string; }): packets.SessionInitPacket => { - let body: any = { + const innerBody: any = { ephemeralPubKey, version: ownVersion, peerPubKey: expectedNodePubKey, @@ -1065,11 +1064,11 @@ class Peer extends EventEmitter { nodeState: ownNodeState, }; - const msg = stringify(body); + const msg = packets.SessionInitPacket.serializeInnerBody(innerBody); const msgHash = createHash('sha256').update(msg).digest(); const { signature } = secp256k1.sign(msgHash, ownNodeKey.privKey); - body = { ...body, sign: signature.toString('hex') }; + const body = { ...innerBody, sign: signature.toString('hex') }; return new packets.SessionInitPacket(body); }; diff --git a/lib/p2p/packets/Packet.ts b/lib/p2p/packets/Packet.ts index 98494e7..0a7485b 100644 --- a/lib/p2p/packets/Packet.ts +++ b/lib/p2p/packets/Packet.ts @@ -1,6 +1,4 @@ -import { createHash } from 'crypto'; import uuidv1 from 'uuid/v1'; -import stringify from 'json-stable-stringify'; import PacketType from './PacketType'; type PacketHeader = { @@ -91,10 +89,6 @@ abstract class Packet implements PacketInterface { public abstract serialize(): Uint8Array; - public toJSON = () => { - return stringify({ header: this.header, body: this.body }); - }; - /** * Serialize this packet to binary Buffer. * @returns Buffer representation of the packet @@ -102,13 +96,6 @@ abstract class Packet implements PacketInterface { public toRaw = (): Buffer => { return Buffer.from(this.serialize().buffer as ArrayBuffer); }; - - /** - * Calculating the packet checksum using its JSON representation hash first 4 bytes. - */ - public checksum = (): number => { - return createHash('sha256').update(this.toJSON()).digest().readUInt32LE(0); - }; } function isPacket(val: any): val is Packet { diff --git a/lib/p2p/packets/types/SessionInitPacket.ts b/lib/p2p/packets/types/SessionInitPacket.ts index 68ee8bc..80fb057 100644 --- a/lib/p2p/packets/types/SessionInitPacket.ts +++ b/lib/p2p/packets/types/SessionInitPacket.ts @@ -4,8 +4,7 @@ import { NodeState } from '../../types'; import * as pb from '../../../proto/xudp2p_pb'; import { validateNodeState, convertNodeState, serializeNodeState } from '../utils'; -export type SessionInitPacketBody = { - sign: string; +export type InnerBody = { ephemeralPubKey: string; /** The node pub key of the peer we are connecting to. */ peerPubKey: string; @@ -17,6 +16,10 @@ export type SessionInitPacketBody = { nodePubKey: string; }; +export type SessionInitPacketBody = InnerBody & { + sign: string; +}; + class SessionInitPacket extends Packet { public get type(): PacketType { return PacketType.SessionInit; @@ -61,6 +64,17 @@ class SessionInitPacket extends Packet { }); }; + public static serializeInnerBody = (body: InnerBody): Uint8Array => { + const msg = new pb.SessionInitPacket(); + msg.setPeerPubKey(body.peerPubKey); + msg.setEphemeralPubKey(body.ephemeralPubKey); + msg.setVersion(body.version); + msg.setNodePubKey(body.nodePubKey); + msg.setNodeState(serializeNodeState(body.nodeState)); + + return msg.serializeBinary(); + }; + public serialize = (): Uint8Array => { const msg = new pb.SessionInitPacket(); msg.setId(this.header.id); diff --git a/lib/p2p/packets/utils.ts b/lib/p2p/packets/utils.ts index c144525..a0bff55 100644 --- a/lib/p2p/packets/utils.ts +++ b/lib/p2p/packets/utils.ts @@ -1,3 +1,4 @@ +import { createHash } from 'crypto'; import * as pb from '../../proto/xudp2p_pb'; import { removeUndefinedProps, convertKvpArrayToKvps, setObjectToMap } from '../../utils/utils'; import { NodeState } from '../types'; @@ -67,3 +68,10 @@ export const serializeNodeState = (nodeState: NodeState): pb.NodeState => { } return pbNodeState; }; + +/** + * Calculate checksum using the bytes sha256-hash first 4 bytes. + */ +export const calcChecksum = (bytes: Uint8Array): number => { + return createHash('sha256').update(bytes).digest().readUInt32LE(0); +}; diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index f2e3ec5..336b456 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -11977,6 +11977,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", + "dev": true, "requires": { "jsonify": "~0.0.0" } @@ -12012,7 +12013,8 @@ "jsonify": { "version": "0.0.0", "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", - "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=" + "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=", + "dev": true }, "jsonparse": { "version": "1.3.1", diff --git a/package.json b/package.json index cc161b9..0684e49 100644 --- a/package.json +++ b/package.json @@ -153,7 +153,6 @@ "fastpriorityqueue": "^0.6.3", "google-protobuf": "^3.14.0", "gulp": "^4.0.2", - "json-stable-stringify": "^1.0.1", "keccak": "^2.1.0", "moment": "^2.29.1", "node-forge": "^0.10.0", @@ -204,6 +203,7 @@ "grpc-tools": "^1.10.0", "grpc_tools_node_protoc_ts": "^5.1.0", "jest": "^26.6.3", + "json-stable-stringify": "^1.0.1", "mocha": "^8.2.1", "nodemon": "^2.0.6", "prettier": "2.2.1",