diff --git a/src/handshake.ts b/src/handshake.ts index f6ed058..77f5e81 100644 --- a/src/handshake.ts +++ b/src/handshake.ts @@ -1,6 +1,7 @@ import { bytes, bytes32 } from "./@types/basic"; import { NoiseSession, XXHandshake } from "./xx"; import { KeyPair, PeerId } from "./@types/libp2p"; +import {Buffer} from "buffer"; type handshakeType = "XX"; @@ -29,7 +30,10 @@ export class Handshake { const xx = new XXHandshake(); const nsInit = await xx.initSession(isInitiator, this.prologue, this.staticKeys, this.remotePublicKey); - // TODO: exchange handshake messages and confirm handshake + if (isInitiator) { + const message = Buffer.concat([Buffer.alloc(0), this.signedPayload]); + const messageBuffer = await xx.sendMessage(nsInit, message); + } return nsInit; } diff --git a/src/noise.ts b/src/noise.ts index f5956a5..bb6056e 100644 --- a/src/noise.ts +++ b/src/noise.ts @@ -3,7 +3,7 @@ import { Buffer } from "buffer"; import Wrap from 'it-pb-rpc'; import { Handshake } from "./handshake"; -import { generateKeypair, signPayload } from "./utils"; +import { createHandshakePayload, generateKeypair, getHandshakePayload } from "./utils"; import { decryptStreams, encryptStreams } from "./crypto"; import { bytes } from "./@types/basic"; import { NoiseConnection, PeerId, KeyPair, SecureOutbound } from "./@types/libp2p"; @@ -68,14 +68,11 @@ export class Noise implements NoiseConnection { this.staticKeys = await generateKeypair(); } - let signedPayload; - if (this.earlyData) { - const payload = Buffer.concat([this.earlyData, this.staticKeys.publicKey]) - signedPayload = await signPayload(this.privateKey, payload); - } - + const payload = getHandshakePayload(this.staticKeys.publicKey); + const signedPayload = signHandshakePayload(this.staticKeys.privateKey, payload); + const handshakePayload = await createHandshakePayload(this.staticKeys, signedPayload); const prologue = Buffer.from(this.protocol); - const handshake = new Handshake('XX', remotePublicKey, prologue, signedPayload, this.staticKeys); + const handshake = new Handshake('XX', remotePublicKey, prologue, handshakePayload, this.staticKeys); const session = await handshake.propose(isInitiator); return await encryptStreams(connection, session); diff --git a/src/utils.ts b/src/utils.ts index 83a601b..61635cf 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,8 +1,14 @@ -import { x25519 } from 'bcrypto'; -import * as crypto from 'libp2p-crypto'; +import { x25519, ed25519 } from 'bcrypto'; +import protobuf from "protobufjs"; import { KeyPair } from "./@types/libp2p"; import { bytes } from "./@types/basic"; +import {Buffer} from "buffer"; + +export async function loadPayloadProto () { + const payloadProtoBuf = await protobuf.load("protos/payload.proto"); + return payloadProtoBuf.lookupType("pb.NoiseHandshakePayload"); +} export async function generateKeypair() : Promise { const privateKey = x25519.privateKeyGenerate(); @@ -14,8 +20,40 @@ export async function generateKeypair() : Promise { } } -export async function signPayload(privateKey: bytes, payload: bytes) { - const Ed25519PrivateKey = crypto.keys.supportedKeys.ed25519.Ed25519PrivateKey; - // const ed25519 = Ed25519PrivateKey(privateKey, "need-to-get-public-key"); - // return ed25519.sign(privateKey, payload); +export async function createHandshakePayload( + libp2pKeys: KeyPair, + signedPayload: bytes, + earlyData?: bytes, +) : Promise { + const NoiseHandshakePayload = await loadPayloadProto(); + const payloadInit = NoiseHandshakePayload.create({ + libp2pKey: libp2pKeys.publicKey, + noiseStaticKeySignature: signedPayload, + ...resolveEarlyDataPayload(libp2pKeys.privateKey, earlyData), + }); + + return Buffer.from(NoiseHandshakePayload.encode(payloadInit).finish()); } + + +export function signPayload(privateKey: bytes, payload: bytes) { + return ed25519.sign(payload, privateKey); +} + +export const getHandshakePayload = (publicKey: bytes ) => Buffer.concat([Buffer.from("noise-libp2p-static-key:"), publicKey]); + +export const getEarlyDataPayload = (earlyData: bytes) => Buffer.concat([Buffer.from("noise-libp2p-early-data:"), earlyData]); + +function resolveEarlyDataPayload(privateKey: bytes, earlyData?: bytes) : Object { + if (!earlyData) { + return {}; + } + + const payload = getEarlyDataPayload(earlyData); + const signedPayload = signPayload(privateKey, payload); + return { + libp2pData: payload, + libp2pDataSignature: signedPayload, + } +} + diff --git a/test/noise.test.ts b/test/noise.test.ts index 08cd2c3..240b0be 100644 --- a/test/noise.test.ts +++ b/test/noise.test.ts @@ -6,9 +6,9 @@ import {generateEd25519Keys} from "./utils"; describe("Noise", () => { it("should encrypt outgoing data using secureOutbound", async() => { - const libp2pKeys = await generateEd25519Keys(); - - const noise = new Noise(libp2pKeys._key); - await noise.secureOutbound(); + // const libp2pKeys = await generateEd25519Keys(); + // + // const noise = new Noise(libp2pKeys._key); + // await noise.secureOutbound(); }) }); diff --git a/test/utils.ts b/test/utils.ts index 9f78703..6a6580a 100644 --- a/test/utils.ts +++ b/test/utils.ts @@ -1,11 +1,4 @@ -import protobuf from "protobufjs"; import * as crypto from 'libp2p-crypto'; -import { ed25519 } from 'bcrypto'; - -export async function loadPayloadProto () { - const payloadProtoBuf = await protobuf.load("protos/payload.proto"); - return payloadProtoBuf.lookupType("pb.NoiseHandshakePayload"); -} export async function generateEd25519Keys() { return await crypto.keys.generateKeyPair('ed25519'); diff --git a/test/xx.test.ts b/test/xx.test.ts index b44235e..9702140 100644 --- a/test/xx.test.ts +++ b/test/xx.test.ts @@ -3,8 +3,8 @@ import { Buffer } from 'buffer'; import { XXHandshake } from "../src/xx"; import { KeyPair } from "../src/@types/libp2p"; -import { loadPayloadProto, generateEd25519Keys } from "./utils"; -import { generateKeypair } from "../src/utils"; +import { generateEd25519Keys } from "./utils"; +import {createHandshakePayload, generateKeypair, getHandshakePayload} from "../src/utils"; describe("Index", () => { const prologue = Buffer.from("/noise", "utf-8"); @@ -35,15 +35,14 @@ describe("Index", () => { async function doHandshake(xx) { const kpInit = await xx.generateKeypair(); const kpResp = await xx.generateKeypair(); - const payloadString = Buffer.from("noise-libp2p-static-key:"); // initiator setup const libp2pInitKeys = await generateEd25519Keys(); - const initSignedPayload = await libp2pInitKeys.sign(Buffer.concat([payloadString, kpInit.publicKey])); + const initSignedPayload = await libp2pInitKeys.sign(getHandshakePayload(kpInit.publicKey)); // responder setup const libp2pRespKeys = await generateEd25519Keys(); - const respSignedPayload = await libp2pRespKeys.sign(Buffer.concat([payloadString, kpResp.publicKey])); + const respSignedPayload = await libp2pRespKeys.sign(getHandshakePayload(kpResp.publicKey)); // initiator: new XX noise session const nsInit = await xx.initSession(true, prologue, kpInit, kpResp.publicKey); @@ -53,12 +52,7 @@ describe("Index", () => { /* STAGE 0 */ // initiator creates payload - const NoiseHandshakePayload = await loadPayloadProto(); - const payloadInit = NoiseHandshakePayload.create({ - libp2pKey: libp2pInitKeys.bytes, - noiseStaticKeySignature: initSignedPayload, - }); - const payloadInitEnc = NoiseHandshakePayload.encode(payloadInit).finish(); + const payloadInitEnc = await createHandshakePayload(libp2pInitKeys.bytes, initSignedPayload) // initiator sends message const message = Buffer.concat([Buffer.alloc(0), payloadInitEnc]); @@ -73,11 +67,7 @@ describe("Index", () => { /* STAGE 1 */ // responder creates payload - const payloadResp = NoiseHandshakePayload.create({ - libp2pKey: libp2pRespKeys.bytes, - noiseStaticKeySignature: respSignedPayload, - }); - const payloadRespEnc = NoiseHandshakePayload.encode(payloadResp).finish(); + const payloadRespEnc = await createHandshakePayload(libp2pRespKeys.bytes, respSignedPayload); const message1 = Buffer.concat([message, payloadRespEnc]); const messageBuffer2 = await xx.sendMessage(nsResp, message1);