diff --git a/src/@types/it-pb-rpc/index.d.ts b/src/@types/it-pb-rpc/index.d.ts index 482d27e..9366760 100644 --- a/src/@types/it-pb-rpc/index.d.ts +++ b/src/@types/it-pb-rpc/index.d.ts @@ -2,8 +2,10 @@ declare module "it-pb-rpc" { import { Buffer } from "buffer"; import { Duplex } from "it-pair"; type WrappedDuplex = { - read(input: Buffer): Buffer, + read(bytes: number): Buffer, + readLP(): Buffer, write(input: Buffer): void, + writeLP(input: Buffer): void, unwrap(): Duplex } diff --git a/src/handshake.ts b/src/handshake.ts index b3eee05..f72bea9 100644 --- a/src/handshake.ts +++ b/src/handshake.ts @@ -2,7 +2,14 @@ import { bytes, bytes32 } from "./@types/basic"; import { NoiseSession, XXHandshake } from "./xx"; import { KeyPair } from "./@types/libp2p"; import { Buffer } from "buffer"; -import {createHandshakePayload, getHandshakePayload, signPayload} from "./utils"; +import { + createHandshakePayload, + decodeMessageBuffer, + encodeMessageBuffer, + getHandshakePayload, + signPayload +} from "./utils"; +import { WrappedConnection } from "./noise"; type handshakeType = "XX"; @@ -11,7 +18,7 @@ export class Handshake { private remotePublicKey: bytes; private prologue: bytes32; private staticKeys: KeyPair; - private connection: any; + private connection: WrappedConnection; private xx: XXHandshake; constructor( @@ -19,7 +26,7 @@ export class Handshake { remotePublicKey: bytes, prologue: bytes32, staticKeys: KeyPair, - connection, + connection: WrappedConnection, ) { this.type = type; this.remotePublicKey = remotePublicKey; @@ -44,10 +51,10 @@ export class Handshake { ); const message = Buffer.concat([Buffer.alloc(0), handshakePayload]); const messageBuffer = await this.xx.sendMessage(ns, message); - this.connection.writeLP(messageBuffer); + this.connection.writeLP(encodeMessageBuffer(messageBuffer)); } else { const receivedMessageBuffer = (await this.connection.readLP()).slice(); - const plaintext = await this.xx.recvMessage(ns, receivedMessageBuffer); + const plaintext = await this.xx.recvMessage(ns, decodeMessageBuffer(receivedMessageBuffer)); } return ns; @@ -57,7 +64,7 @@ export class Handshake { async exchange(isInitiator: boolean, session: NoiseSession) : Promise { if (isInitiator) { const receivedMessageBuffer = (await this.connection.readLP()).slice(); - const plaintext = await this.xx.recvMessage(session, receivedMessageBuffer); + const plaintext = await this.xx.recvMessage(session, decodeMessageBuffer(receivedMessageBuffer)); } else { // create payload as responder const signedPayload = signPayload(this.staticKeys.privateKey, getHandshakePayload(this.staticKeys.publicKey)); @@ -65,7 +72,7 @@ export class Handshake { const message = Buffer.concat([Buffer.alloc(0), handshakePayload]); const messageBuffer = await this.xx.sendMessage(session, message); - this.connection.writeLP(messageBuffer); + this.connection.writeLP(encodeMessageBuffer(messageBuffer)); } } @@ -73,10 +80,10 @@ export class Handshake { async finish(isInitiator: boolean, session: NoiseSession) : Promise { if (isInitiator) { const messageBuffer = await this.xx.sendMessage(session, Buffer.alloc(0)); - this.connection.writeLP(messageBuffer); + this.connection.writeLP(encodeMessageBuffer(messageBuffer)); } else { const receivedMessageBuffer = (await this.connection.readLP()).slice(); - const plaintext = await this.xx.recvMessage(session, receivedMessageBuffer); + const plaintext = await this.xx.recvMessage(session, decodeMessageBuffer(receivedMessageBuffer)); } } } diff --git a/src/noise.ts b/src/noise.ts index e936609..b855643 100644 --- a/src/noise.ts +++ b/src/noise.ts @@ -9,7 +9,7 @@ import { bytes } from "./@types/basic"; import { NoiseConnection, PeerId, KeyPair, SecureOutbound } from "./@types/libp2p"; import { Duplex } from "./@types/it-pair"; -type WrappedConnection = ReturnType; +export type WrappedConnection = ReturnType; export class Noise implements NoiseConnection { public protocol = "/noise"; diff --git a/src/utils.ts b/src/utils.ts index 8fe5d09..3676a59 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,9 +1,10 @@ import { x25519, ed25519 } from 'bcrypto'; import protobuf from "protobufjs"; +import { Buffer } from "buffer"; import { KeyPair } from "./@types/libp2p"; import { bytes } from "./@types/basic"; -import {Buffer} from "buffer"; +import { MessageBuffer } from "./xx"; export async function loadPayloadProto () { const payloadProtoBuf = await protobuf.load("protos/payload.proto"); @@ -58,3 +59,15 @@ function resolveEarlyDataPayload(privateKey?: bytes, earlyData?: bytes) : Object } } +export function encodeMessageBuffer(message: MessageBuffer) : bytes { + return Buffer.concat([message.ne, message.ns, message.ciphertext]); +} + +export function decodeMessageBuffer(message: bytes) : MessageBuffer { + return { + ne: message.slice(0, 32), + ns: message.slice(32, 80), + ciphertext: message.slice(80, message.length), + } +} + diff --git a/src/xx.ts b/src/xx.ts index 3b1299c..1c59e6e 100644 --- a/src/xx.ts +++ b/src/xx.ts @@ -7,7 +7,7 @@ import { KeyPair } from './@types/libp2p' import { generateKeypair } from './utils'; -interface MessageBuffer { +export interface MessageBuffer { ne: bytes32, ns: bytes, ciphertext: bytes @@ -277,6 +277,7 @@ export class XXHandshake { } private async readMessageA(hs: HandshakeState, message: MessageBuffer) : Promise { + console.log("publci key: ", message.ne) if (x25519.publicKeyVerify(message.ne)) { hs.re = message.ne; } diff --git a/test/handshake.test.ts b/test/handshake.test.ts index d79a80b..a2ad9b2 100644 --- a/test/handshake.test.ts +++ b/test/handshake.test.ts @@ -1,11 +1,39 @@ import { expect } from "chai"; -import DuplexPair from 'it-pair/duplex'; +import Duplex from 'it-pair/duplex'; +import {Buffer} from "buffer"; +import Wrap from "it-pb-rpc"; -import { Noise } from "../src"; -import {generateEd25519Keys} from "./utils"; +import {Handshake} from "../src/handshake"; +import {generateKeypair} from "../src/utils"; describe("Handshake", () => { it("should propose, exchange and finish handshake", async() => { + const duplex = Duplex(); + const connectionFrom = Wrap(duplex[0]); + const connectionTo = Wrap(duplex[1]); + const prologue = Buffer.from('/noise'); + const staticKeysInitiator = generateKeypair(); + const staticKeysResponder = generateKeypair(); + + const handshakeInitator = new Handshake('XX', staticKeysResponder.publicKey, prologue, staticKeysInitiator, connectionFrom); + const handshakeResponder = new Handshake('XX', staticKeysInitiator.publicKey, prologue, staticKeysResponder, connectionTo); + + console.log("Going to start with the handshake process...") + + const sessionInitator = await handshakeInitator.propose(true); + const sessionResponder = await handshakeResponder.propose(false); + + console.log("Propose finished") + + await handshakeInitator.exchange(true, sessionInitator); + await handshakeResponder.exchange(false, sessionResponder); + + console.log("exchange finished") + + await handshakeInitator.finish(true, sessionInitator); + await handshakeResponder.finish(false, sessionResponder); + + console.log("finish finished") }) });