From 9b11560183671113b7236e1d53f5588e03f4f818 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marin=20Petruni=C4=87?= Date: Fri, 19 Jun 2020 12:49:10 +0200 Subject: [PATCH 01/11] fix some configurations --- .nvmrc | 2 +- .travis.yml | 1 + package.json | 5 ++++- src/noise.ts | 2 +- tsconfig.json | 1 + 5 files changed, 8 insertions(+), 3 deletions(-) diff --git a/.nvmrc b/.nvmrc index f8c17e7..48082f7 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -12.4.0 +12 diff --git a/.travis.yml b/.travis.yml index ffd38da..33aa9fc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -23,6 +23,7 @@ jobs: script: - yarn aegir dep-check - yarn run lint + - yarn run build - stage: test name: chrome diff --git a/package.json b/package.json index ec8079d..920a0b8 100644 --- a/package.json +++ b/package.json @@ -2,8 +2,10 @@ "name": "libp2p-noise", "version": "1.1.2", "main": "dist/src/index.js", + "types": "dist/src/dist/index.d.ts", "files": [ - "dist" + "dist", + "src" ], "repository": "git@github.com:NodeFactoryIo/js-libp2p-noise.git", "author": "NodeFactory ", @@ -16,6 +18,7 @@ "scripts": { "build": "aegir build --ts", "lint": "aegir lint --ts", + "lint:fix": "aegir lint --ts --fix", "test": "aegir test --ts", "test:node": "aegir test -t node --ts", "test:browser": "aegir test -t browser --ts", diff --git a/src/noise.ts b/src/noise.ts index cd58ec2..4f2816f 100644 --- a/src/noise.ts +++ b/src/noise.ts @@ -226,7 +226,7 @@ export class Noise implements INoiseConnection { const [secure, user] = DuplexPair(); const network = connection.unwrap(); - pipe( + await pipe( secure, // write to wrapper ensureBuffer, // ensure any type of data is converted to buffer encryptStream(handshake), // data is encrypted diff --git a/tsconfig.json b/tsconfig.json index 970ca4c..dc2c70f 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -4,6 +4,7 @@ "module": "commonjs", "strict": true, "allowJs": true, + "sourceMap": true, "resolveJsonModule": true, "esModuleInterop": true, "noImplicitAny": false, From 8327a6035629bf0d6c6c60924895589435edd4a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marin=20Petruni=C4=87?= Date: Fri, 19 Jun 2020 12:49:40 +0200 Subject: [PATCH 02/11] fix automatic lint --- src/constants.ts | 8 +- src/crypto.ts | 37 +- src/encoder.ts | 54 +-- src/errors.ts | 10 +- src/handshake-ik.ts | 162 ++++----- src/handshake-xx-fallback.ts | 82 ++--- src/handshake-xx.ts | 172 +++++----- src/handshakes/abstract-handshake.ts | 209 ++++++------ src/handshakes/ik.ts | 183 +++++----- src/handshakes/xx.ts | 205 ++++++------ src/index.ts | 6 +- src/keycache.ts | 25 +- src/logger.ts | 37 +- src/noise.ts | 177 +++++----- src/proto/payload.js | 334 +++++++++--------- src/utils.ts | 108 +++--- test/fixtures/peer.ts | 12 +- test/handshakes/ik.spec.ts | 77 +++-- test/handshakes/xx.spec.ts | 170 +++++----- test/ik-handshake.spec.ts | 104 +++--- test/index.spec.ts | 18 +- test/keycache.spec.ts | 42 +-- test/noise.spec.ts | 483 +++++++++++++-------------- test/utils.ts | 14 +- test/xx-fallback-handshake.spec.ts | 84 ++--- test/xx-handshake.spec.ts | 153 +++++---- 26 files changed, 1457 insertions(+), 1509 deletions(-) diff --git a/src/constants.ts b/src/constants.ts index 9b34786..1a64109 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -1,6 +1,4 @@ -export const NOISE_MSG_MAX_LENGTH_BYTES = 65535; -export const NOISE_MSG_MAX_LENGTH_BYTES_WITHOUT_TAG = NOISE_MSG_MAX_LENGTH_BYTES - 16; - -export const DUMP_SESSION_KEYS = process.env.DUMP_SESSION_KEYS; - +export const NOISE_MSG_MAX_LENGTH_BYTES = 65535 +export const NOISE_MSG_MAX_LENGTH_BYTES_WITHOUT_TAG = NOISE_MSG_MAX_LENGTH_BYTES - 16 +export const DUMP_SESSION_KEYS = process.env.DUMP_SESSION_KEYS diff --git a/src/crypto.ts b/src/crypto.ts index d9dcb1a..8e50f71 100644 --- a/src/crypto.ts +++ b/src/crypto.ts @@ -1,49 +1,48 @@ -import { Buffer } from "buffer"; -import {IHandshake} from "./@types/handshake-interface"; -import {NOISE_MSG_MAX_LENGTH_BYTES, NOISE_MSG_MAX_LENGTH_BYTES_WITHOUT_TAG} from "./constants"; +import { Buffer } from 'buffer' +import { IHandshake } from './@types/handshake-interface' +import { NOISE_MSG_MAX_LENGTH_BYTES, NOISE_MSG_MAX_LENGTH_BYTES_WITHOUT_TAG } from './constants' interface IReturnEncryptionWrapper { (source: Iterable): AsyncIterableIterator; } // Returns generator that encrypts payload from the user -export function encryptStream(handshake: IHandshake): IReturnEncryptionWrapper { +export function encryptStream (handshake: IHandshake): IReturnEncryptionWrapper { return async function * (source) { for await (const chunk of source) { - const chunkBuffer = Buffer.from(chunk.buffer, chunk.byteOffset, chunk.length); + const chunkBuffer = Buffer.from(chunk.buffer, chunk.byteOffset, chunk.length) for (let i = 0; i < chunkBuffer.length; i += NOISE_MSG_MAX_LENGTH_BYTES_WITHOUT_TAG) { - let end = i + NOISE_MSG_MAX_LENGTH_BYTES_WITHOUT_TAG; + let end = i + NOISE_MSG_MAX_LENGTH_BYTES_WITHOUT_TAG if (end > chunkBuffer.length) { - end = chunkBuffer.length; + end = chunkBuffer.length } - const data = handshake.encrypt(chunkBuffer.slice(i, end), handshake.session); - yield data; + const data = handshake.encrypt(chunkBuffer.slice(i, end), handshake.session) + yield data } } } } - // Decrypt received payload to the user -export function decryptStream(handshake: IHandshake): IReturnEncryptionWrapper { +export function decryptStream (handshake: IHandshake): IReturnEncryptionWrapper { return async function * (source) { for await (const chunk of source) { - const chunkBuffer = Buffer.from(chunk.buffer, chunk.byteOffset, chunk.length); + const chunkBuffer = Buffer.from(chunk.buffer, chunk.byteOffset, chunk.length) for (let i = 0; i < chunkBuffer.length; i += NOISE_MSG_MAX_LENGTH_BYTES) { - let end = i + NOISE_MSG_MAX_LENGTH_BYTES; + let end = i + NOISE_MSG_MAX_LENGTH_BYTES if (end > chunkBuffer.length) { - end = chunkBuffer.length; + end = chunkBuffer.length } - const chunk = chunkBuffer.slice(i, end); - const {plaintext: decrypted, valid} = await handshake.decrypt(chunk, handshake.session); - if(!valid) { - throw new Error("Failed to validate decrypted chunk"); + const chunk = chunkBuffer.slice(i, end) + const { plaintext: decrypted, valid } = await handshake.decrypt(chunk, handshake.session) + if (!valid) { + throw new Error('Failed to validate decrypted chunk') } - yield decrypted; + yield decrypted } } } diff --git a/src/encoder.ts b/src/encoder.ts index fd10fdd..08877f3 100644 --- a/src/encoder.ts +++ b/src/encoder.ts @@ -1,66 +1,66 @@ -import {Buffer} from "buffer"; -import {bytes} from "./@types/basic"; -import {MessageBuffer} from "./@types/handshake"; +import { Buffer } from 'buffer' +import { bytes } from './@types/basic' +import { MessageBuffer } from './@types/handshake' export const uint16BEEncode = (value, target, offset) => { - target = target || Buffer.allocUnsafe(2); - target.writeUInt16BE(value, offset); - return target; -}; -uint16BEEncode.bytes = 2; + target = target || Buffer.allocUnsafe(2) + target.writeUInt16BE(value, offset) + return target +} +uint16BEEncode.bytes = 2 export const uint16BEDecode = data => { - if (data.length < 2) throw RangeError('Could not decode int16BE'); - return data.readUInt16BE(0); -}; -uint16BEDecode.bytes = 2; + if (data.length < 2) throw RangeError('Could not decode int16BE') + return data.readUInt16BE(0) +} +uint16BEDecode.bytes = 2 // Note: IK and XX encoder usage is opposite (XX uses in stages encode0 where IK uses encode1) -export function encode0(message: MessageBuffer): bytes { - return Buffer.concat([message.ne, message.ciphertext]); +export function encode0 (message: MessageBuffer): bytes { + return Buffer.concat([message.ne, message.ciphertext]) } -export function encode1(message: MessageBuffer): bytes { - return Buffer.concat([message.ne, message.ns, message.ciphertext]); +export function encode1 (message: MessageBuffer): bytes { + return Buffer.concat([message.ne, message.ns, message.ciphertext]) } -export function encode2(message: MessageBuffer): bytes { - return Buffer.concat([message.ns, message.ciphertext]); +export function encode2 (message: MessageBuffer): bytes { + return Buffer.concat([message.ns, message.ciphertext]) } -export function decode0(input: bytes): MessageBuffer { +export function decode0 (input: bytes): MessageBuffer { if (input.length < 32) { - throw new Error("Cannot decode stage 0 MessageBuffer: length less than 32 bytes."); + throw new Error('Cannot decode stage 0 MessageBuffer: length less than 32 bytes.') } return { ne: input.slice(0, 32), ciphertext: input.slice(32, input.length), - ns: Buffer.alloc(0), + ns: Buffer.alloc(0) } } -export function decode1(input: bytes): MessageBuffer { +export function decode1 (input: bytes): MessageBuffer { if (input.length < 80) { - throw new Error("Cannot decode stage 1 MessageBuffer: length less than 80 bytes."); + throw new Error('Cannot decode stage 1 MessageBuffer: length less than 80 bytes.') } return { ne: input.slice(0, 32), ns: input.slice(32, 80), - ciphertext: input.slice(80, input.length), + ciphertext: input.slice(80, input.length) } } -export function decode2(input: bytes): MessageBuffer { +export function decode2 (input: bytes): MessageBuffer { if (input.length < 48) { - throw new Error("Cannot decode stage 2 MessageBuffer: length less than 48 bytes."); + throw new Error('Cannot decode stage 2 MessageBuffer: length less than 48 bytes.') } return { ne: Buffer.alloc(0), ns: input.slice(0, 48), - ciphertext: input.slice(48, input.length), + ciphertext: input.slice(48, input.length) } } diff --git a/src/errors.ts b/src/errors.ts index 46a5c0a..8a52f23 100644 --- a/src/errors.ts +++ b/src/errors.ts @@ -1,10 +1,10 @@ export class FailedIKError extends Error { public initialMsg; - constructor(initialMsg, message?: string) { - super(message); + constructor (initialMsg, message?: string) { + super(message) - this.initialMsg = initialMsg; - this.name = "FailedIKhandshake"; + this.initialMsg = initialMsg + this.name = 'FailedIKhandshake' } -}; +} diff --git a/src/handshake-ik.ts b/src/handshake-ik.ts index e34b283..4a76716 100644 --- a/src/handshake-ik.ts +++ b/src/handshake-ik.ts @@ -1,22 +1,22 @@ -import {WrappedConnection} from "./noise"; -import {IK} from "./handshakes/ik"; -import {NoiseSession} from "./@types/handshake"; -import {bytes, bytes32} from "./@types/basic"; -import {KeyPair} from "./@types/libp2p"; -import {IHandshake} from "./@types/handshake-interface"; -import {Buffer} from "buffer"; -import {decode0, decode1, encode0, encode1} from "./encoder"; -import {decodePayload, getPeerIdFromPayload, verifySignedPayload} from "./utils"; -import {FailedIKError} from "./errors"; +import { WrappedConnection } from './noise' +import { IK } from './handshakes/ik' +import { NoiseSession } from './@types/handshake' +import { bytes, bytes32 } from './@types/basic' +import { KeyPair } from './@types/libp2p' +import { IHandshake } from './@types/handshake-interface' +import { Buffer } from 'buffer' +import { decode0, decode1, encode0, encode1 } from './encoder' +import { decodePayload, getPeerIdFromPayload, verifySignedPayload } from './utils' +import { FailedIKError } from './errors' import { - logger, + logger, logLocalStaticKeys, - logRemoteStaticKey, - logLocalEphemeralKeys, - logRemoteEphemeralKey, + logRemoteStaticKey, + logLocalEphemeralKeys, + logRemoteEphemeralKey, logCipherState -} from "./logger"; -import PeerId from "peer-id"; +} from './logger' +import PeerId from 'peer-id' export class IKHandshake implements IHandshake { public isInitiator: boolean; @@ -30,7 +30,7 @@ export class IKHandshake implements IHandshake { private connection: WrappedConnection; private ik: IK; - constructor( + constructor ( isInitiator: boolean, payload: bytes, prologue: bytes32, @@ -38,118 +38,118 @@ export class IKHandshake implements IHandshake { connection: WrappedConnection, remoteStaticKey: bytes, remotePeer?: PeerId, - handshake?: IK, + handshake?: IK ) { - this.isInitiator = isInitiator; - this.payload = Buffer.from(payload); - this.prologue = prologue; - this.staticKeypair = staticKeypair; - this.connection = connection; - if(remotePeer) { - this.remotePeer = remotePeer; + this.isInitiator = isInitiator + this.payload = Buffer.from(payload) + this.prologue = prologue + this.staticKeypair = staticKeypair + this.connection = connection + if (remotePeer) { + this.remotePeer = remotePeer } - this.ik = handshake || new IK(); - this.session = this.ik.initSession(this.isInitiator, this.prologue, this.staticKeypair, remoteStaticKey); + this.ik = handshake || new IK() + this.session = this.ik.initSession(this.isInitiator, this.prologue, this.staticKeypair, remoteStaticKey) this.remoteEarlyData = Buffer.alloc(0) } - public async stage0(): Promise { + public async stage0 (): Promise { logLocalStaticKeys(this.session.hs.s) logRemoteStaticKey(this.session.hs.rs) if (this.isInitiator) { - logger("IK Stage 0 - Initiator sending message..."); - const messageBuffer = this.ik.sendMessage(this.session, this.payload); - this.connection.writeLP(encode1(messageBuffer)); - logger("IK Stage 0 - Initiator sent message."); + logger('IK Stage 0 - Initiator sending message...') + const messageBuffer = this.ik.sendMessage(this.session, this.payload) + this.connection.writeLP(encode1(messageBuffer)) + logger('IK Stage 0 - Initiator sent message.') logLocalEphemeralKeys(this.session.hs.e) } else { - logger("IK Stage 0 - Responder receiving message..."); - const receivedMsg = await this.connection.readLP(); + logger('IK Stage 0 - Responder receiving message...') + const receivedMsg = await this.connection.readLP() try { - const receivedMessageBuffer = decode1(receivedMsg.slice()); - const {plaintext, valid} = this.ik.recvMessage(this.session, receivedMessageBuffer); - if(!valid) { - throw new Error("ik handshake stage 0 decryption validation fail"); + const receivedMessageBuffer = decode1(receivedMsg.slice()) + const { plaintext, valid } = this.ik.recvMessage(this.session, receivedMessageBuffer) + if (!valid) { + throw new Error('ik handshake stage 0 decryption validation fail') } - logger("IK Stage 0 - Responder got message, going to verify payload."); - const decodedPayload = await decodePayload(plaintext); - this.remotePeer = this.remotePeer || await getPeerIdFromPayload(decodedPayload); - await verifySignedPayload(this.session.hs.rs, decodedPayload, this.remotePeer); - this.setRemoteEarlyData(decodedPayload.data); - logger("IK Stage 0 - Responder successfully verified payload!"); + logger('IK Stage 0 - Responder got message, going to verify payload.') + const decodedPayload = await decodePayload(plaintext) + this.remotePeer = this.remotePeer || await getPeerIdFromPayload(decodedPayload) + await verifySignedPayload(this.session.hs.rs, decodedPayload, this.remotePeer) + this.setRemoteEarlyData(decodedPayload.data) + logger('IK Stage 0 - Responder successfully verified payload!') logRemoteEphemeralKey(this.session.hs.re) } catch (e) { - logger("Responder breaking up with IK handshake in stage 0."); + logger('Responder breaking up with IK handshake in stage 0.') - throw new FailedIKError(receivedMsg, `Error occurred while verifying initiator's signed payload: ${e.message}`); + throw new FailedIKError(receivedMsg, `Error occurred while verifying initiator's signed payload: ${e.message}`) } } } - public async stage1(): Promise { + public async stage1 (): Promise { if (this.isInitiator) { - logger("IK Stage 1 - Initiator receiving message..."); - const receivedMsg = (await this.connection.readLP()).slice(); - const receivedMessageBuffer = decode0(Buffer.from(receivedMsg)); - const {plaintext, valid} = this.ik.recvMessage(this.session, receivedMessageBuffer); - logger("IK Stage 1 - Initiator got message, going to verify payload."); + logger('IK Stage 1 - Initiator receiving message...') + const receivedMsg = (await this.connection.readLP()).slice() + const receivedMessageBuffer = decode0(Buffer.from(receivedMsg)) + const { plaintext, valid } = this.ik.recvMessage(this.session, receivedMessageBuffer) + logger('IK Stage 1 - Initiator got message, going to verify payload.') try { - if(!valid) { - throw new Error("ik stage 1 decryption validation fail"); + if (!valid) { + throw new Error('ik stage 1 decryption validation fail') } - const decodedPayload = await decodePayload(plaintext); - this.remotePeer = this.remotePeer || await getPeerIdFromPayload(decodedPayload); - await verifySignedPayload(receivedMessageBuffer.ns.slice(0, 32), decodedPayload, this.remotePeer); - this.setRemoteEarlyData(decodedPayload.data); - logger("IK Stage 1 - Initiator successfully verified payload!"); + const decodedPayload = await decodePayload(plaintext) + this.remotePeer = this.remotePeer || await getPeerIdFromPayload(decodedPayload) + await verifySignedPayload(receivedMessageBuffer.ns.slice(0, 32), decodedPayload, this.remotePeer) + this.setRemoteEarlyData(decodedPayload.data) + logger('IK Stage 1 - Initiator successfully verified payload!') logRemoteEphemeralKey(this.session.hs.re) } catch (e) { - logger("Initiator breaking up with IK handshake in stage 1."); - throw new FailedIKError(receivedMsg, `Error occurred while verifying responder's signed payload: ${e.message}`); + logger('Initiator breaking up with IK handshake in stage 1.') + throw new FailedIKError(receivedMsg, `Error occurred while verifying responder's signed payload: ${e.message}`) } } else { - logger("IK Stage 1 - Responder sending message..."); - const messageBuffer = this.ik.sendMessage(this.session, this.payload); - this.connection.writeLP(encode0(messageBuffer)); - logger("IK Stage 1 - Responder sent message..."); + logger('IK Stage 1 - Responder sending message...') + const messageBuffer = this.ik.sendMessage(this.session, this.payload) + this.connection.writeLP(encode0(messageBuffer)) + logger('IK Stage 1 - Responder sent message...') logLocalEphemeralKeys(this.session.hs.e) } logCipherState(this.session) } - public decrypt(ciphertext: bytes, session: NoiseSession): {plaintext: bytes; valid: boolean} { - const cs = this.getCS(session, false); - return this.ik.decryptWithAd(cs, Buffer.alloc(0), ciphertext); + public decrypt (ciphertext: bytes, session: NoiseSession): {plaintext: bytes; valid: boolean} { + const cs = this.getCS(session, false) + return this.ik.decryptWithAd(cs, Buffer.alloc(0), ciphertext) } - public encrypt(plaintext: Buffer, session: NoiseSession): Buffer { - const cs = this.getCS(session); - return this.ik.encryptWithAd(cs, Buffer.alloc(0), plaintext); + public encrypt (plaintext: Buffer, session: NoiseSession): Buffer { + const cs = this.getCS(session) + return this.ik.encryptWithAd(cs, Buffer.alloc(0), plaintext) } - public getLocalEphemeralKeys(): KeyPair { + public getLocalEphemeralKeys (): KeyPair { if (!this.session.hs.e) { - throw new Error("Ephemeral keys do not exist."); + throw new Error('Ephemeral keys do not exist.') } - return this.session.hs.e; + return this.session.hs.e } - private getCS(session: NoiseSession, encryption = true) { + private getCS (session: NoiseSession, encryption = true) { if (!session.cs1 || !session.cs2) { - throw new Error("Handshake not completed properly, cipher state does not exist."); + throw new Error('Handshake not completed properly, cipher state does not exist.') } if (this.isInitiator) { - return encryption ? session.cs1 : session.cs2; + return encryption ? session.cs1 : session.cs2 } else { - return encryption ? session.cs2 : session.cs1; + return encryption ? session.cs2 : session.cs1 } } - private setRemoteEarlyData(data: Uint8Array|null|undefined): void { - if(data){ - this.remoteEarlyData = Buffer.from(data.buffer, data.byteOffset, data.length); + private setRemoteEarlyData (data: Uint8Array|null|undefined): void { + if (data) { + this.remoteEarlyData = Buffer.from(data.buffer, data.byteOffset, data.length) } } } diff --git a/src/handshake-xx-fallback.ts b/src/handshake-xx-fallback.ts index 1d29f70..4c19a21 100644 --- a/src/handshake-xx-fallback.ts +++ b/src/handshake-xx-fallback.ts @@ -1,19 +1,19 @@ -import {Buffer} from "buffer"; -import {XXHandshake} from "./handshake-xx"; -import {XX} from "./handshakes/xx"; -import {KeyPair} from "./@types/libp2p"; -import {bytes, bytes32} from "./@types/basic"; -import {decodePayload, getPeerIdFromPayload, verifySignedPayload} from "./utils"; -import {logger, logLocalEphemeralKeys, logRemoteEphemeralKey, logRemoteStaticKey} from "./logger"; -import {WrappedConnection} from "./noise"; -import {decode0, decode1} from "./encoder"; -import PeerId from "peer-id"; +import { Buffer } from 'buffer' +import { XXHandshake } from './handshake-xx' +import { XX } from './handshakes/xx' +import { KeyPair } from './@types/libp2p' +import { bytes, bytes32 } from './@types/basic' +import { decodePayload, getPeerIdFromPayload, verifySignedPayload } from './utils' +import { logger, logLocalEphemeralKeys, logRemoteEphemeralKey, logRemoteStaticKey } from './logger' +import { WrappedConnection } from './noise' +import { decode0, decode1 } from './encoder' +import PeerId from 'peer-id' export class XXFallbackHandshake extends XXHandshake { private ephemeralKeys?: KeyPair; private initialMsg: bytes; - constructor( + constructor ( isInitiator: boolean, payload: bytes, prologue: bytes32, @@ -22,63 +22,63 @@ export class XXFallbackHandshake extends XXHandshake { initialMsg: bytes, remotePeer?: PeerId, ephemeralKeys?: KeyPair, - handshake?: XX, + handshake?: XX ) { - super(isInitiator, payload, prologue, staticKeypair, connection, remotePeer, handshake); + super(isInitiator, payload, prologue, staticKeypair, connection, remotePeer, handshake) if (ephemeralKeys) { - this.ephemeralKeys = ephemeralKeys; + this.ephemeralKeys = ephemeralKeys } - this.initialMsg = initialMsg; + this.initialMsg = initialMsg } // stage 0 - public async propose(): Promise { + public async propose (): Promise { if (this.isInitiator) { - this.xx.sendMessage(this.session, Buffer.alloc(0), this.ephemeralKeys); - logger("XX Fallback Stage 0 - Initialized state as the first message was sent by initiator."); + this.xx.sendMessage(this.session, Buffer.alloc(0), this.ephemeralKeys) + logger('XX Fallback Stage 0 - Initialized state as the first message was sent by initiator.') logLocalEphemeralKeys(this.session.hs.e) } else { - logger("XX Fallback Stage 0 - Responder decoding initial msg from IK."); - const receivedMessageBuffer = decode0(this.initialMsg); - const {valid} = this.xx.recvMessage(this.session, { + logger('XX Fallback Stage 0 - Responder decoding initial msg from IK.') + const receivedMessageBuffer = decode0(this.initialMsg) + const { valid } = this.xx.recvMessage(this.session, { ne: receivedMessageBuffer.ne, ns: Buffer.alloc(0), - ciphertext: Buffer.alloc(0), - }); - if(!valid) { - throw new Error("xx fallback stage 0 decryption validation fail"); + ciphertext: Buffer.alloc(0) + }) + if (!valid) { + throw new Error('xx fallback stage 0 decryption validation fail') } - logger("XX Fallback Stage 0 - Responder used received message from IK."); + logger('XX Fallback Stage 0 - Responder used received message from IK.') logRemoteEphemeralKey(this.session.hs.re) } } // stage 1 - public async exchange(): Promise { + public async exchange (): Promise { if (this.isInitiator) { - const receivedMessageBuffer = decode1(this.initialMsg); - const {plaintext, valid} = this.xx.recvMessage(this.session, receivedMessageBuffer); - if(!valid) { - throw new Error("xx fallback stage 1 decryption validation fail"); + const receivedMessageBuffer = decode1(this.initialMsg) + const { plaintext, valid } = this.xx.recvMessage(this.session, receivedMessageBuffer) + if (!valid) { + throw new Error('xx fallback stage 1 decryption validation fail') } - logger('XX Fallback Stage 1 - Initiator used received message from IK.'); + logger('XX Fallback Stage 1 - Initiator used received message from IK.') logRemoteEphemeralKey(this.session.hs.re) logRemoteStaticKey(this.session.hs.rs) - logger("Initiator going to check remote's signature..."); + logger("Initiator going to check remote's signature...") try { - const decodedPayload = await decodePayload(plaintext); - this.remotePeer = this.remotePeer || await getPeerIdFromPayload(decodedPayload); - await verifySignedPayload(this.session.hs.rs, decodedPayload, this.remotePeer); + const decodedPayload = await decodePayload(plaintext) + this.remotePeer = this.remotePeer || await getPeerIdFromPayload(decodedPayload) + await verifySignedPayload(this.session.hs.rs, decodedPayload, this.remotePeer) this.setRemoteEarlyData(decodedPayload.data) } catch (e) { - throw new Error(`Error occurred while verifying signed payload from responder: ${e.message}`); + throw new Error(`Error occurred while verifying signed payload from responder: ${e.message}`) } - logger("All good with the signature!"); + logger('All good with the signature!') } else { - logger("XX Fallback Stage 1 - Responder start"); - await super.exchange(); - logger("XX Fallback Stage 1 - Responder end"); + logger('XX Fallback Stage 1 - Responder start') + await super.exchange() + logger('XX Fallback Stage 1 - Responder end') } } } diff --git a/src/handshake-xx.ts b/src/handshake-xx.ts index 286acd0..ba1bbef 100644 --- a/src/handshake-xx.ts +++ b/src/handshake-xx.ts @@ -1,26 +1,26 @@ -import { Buffer } from "buffer"; +import { Buffer } from 'buffer' -import { XX } from "./handshakes/xx"; -import { KeyPair } from "./@types/libp2p"; -import { bytes, bytes32 } from "./@types/basic"; -import { NoiseSession } from "./@types/handshake"; -import {IHandshake} from "./@types/handshake-interface"; +import { XX } from './handshakes/xx' +import { KeyPair } from './@types/libp2p' +import { bytes, bytes32 } from './@types/basic' +import { NoiseSession } from './@types/handshake' +import { IHandshake } from './@types/handshake-interface' import { decodePayload, getPeerIdFromPayload, - verifySignedPayload, -} from "./utils"; + verifySignedPayload +} from './utils' import { - logger, - logLocalStaticKeys, - logLocalEphemeralKeys, - logRemoteEphemeralKey, - logRemoteStaticKey, - logCipherState, -} from "./logger"; -import {decode0, decode1, decode2, encode0, encode1, encode2} from "./encoder"; -import { WrappedConnection } from "./noise"; -import PeerId from "peer-id"; + logger, + logLocalStaticKeys, + logLocalEphemeralKeys, + logRemoteEphemeralKey, + logRemoteStaticKey, + logCipherState +} from './logger' +import { decode0, decode1, decode2, encode0, encode1, encode2 } from './encoder' +import { WrappedConnection } from './noise' +import PeerId from 'peer-id' export class XXHandshake implements IHandshake { public isInitiator: boolean; @@ -35,139 +35,139 @@ export class XXHandshake implements IHandshake { private prologue: bytes32; - constructor( + constructor ( isInitiator: boolean, payload: bytes, prologue: bytes32, staticKeypair: KeyPair, connection: WrappedConnection, remotePeer?: PeerId, - handshake?: XX, + handshake?: XX ) { - this.isInitiator = isInitiator; - this.payload = payload; - this.prologue = prologue; - this.staticKeypair = staticKeypair; - this.connection = connection; - if(remotePeer) { - this.remotePeer = remotePeer; + this.isInitiator = isInitiator + this.payload = payload + this.prologue = prologue + this.staticKeypair = staticKeypair + this.connection = connection + if (remotePeer) { + this.remotePeer = remotePeer } - this.xx = handshake || new XX(); - this.session = this.xx.initSession(this.isInitiator, this.prologue, this.staticKeypair); + this.xx = handshake || new XX() + this.session = this.xx.initSession(this.isInitiator, this.prologue, this.staticKeypair) this.remoteEarlyData = Buffer.alloc(0) } // stage 0 - public async propose(): Promise { + public async propose (): Promise { logLocalStaticKeys(this.session.hs.s) if (this.isInitiator) { - logger("Stage 0 - Initiator starting to send first message."); - const messageBuffer = this.xx.sendMessage(this.session, Buffer.alloc(0)); - this.connection.writeLP(encode0(messageBuffer)); - logger("Stage 0 - Initiator finished sending first message."); + logger('Stage 0 - Initiator starting to send first message.') + const messageBuffer = this.xx.sendMessage(this.session, Buffer.alloc(0)) + this.connection.writeLP(encode0(messageBuffer)) + logger('Stage 0 - Initiator finished sending first message.') logLocalEphemeralKeys(this.session.hs.e) } else { - logger("Stage 0 - Responder waiting to receive first message..."); - const receivedMessageBuffer = decode0((await this.connection.readLP()).slice()); - const {valid} = this.xx.recvMessage(this.session, receivedMessageBuffer); - if(!valid) { - throw new Error("xx handshake stage 0 validation fail"); + logger('Stage 0 - Responder waiting to receive first message...') + const receivedMessageBuffer = decode0((await this.connection.readLP()).slice()) + const { valid } = this.xx.recvMessage(this.session, receivedMessageBuffer) + if (!valid) { + throw new Error('xx handshake stage 0 validation fail') } - logger("Stage 0 - Responder received first message."); + logger('Stage 0 - Responder received first message.') logRemoteEphemeralKey(this.session.hs.re) } } // stage 1 - public async exchange(): Promise { + public async exchange (): Promise { if (this.isInitiator) { - logger('Stage 1 - Initiator waiting to receive first message from responder...'); - const receivedMessageBuffer = decode1((await this.connection.readLP()).slice()); - const {plaintext, valid} = this.xx.recvMessage(this.session, receivedMessageBuffer); - if(!valid) { - throw new Error("xx handshake stage 1 validation fail"); + logger('Stage 1 - Initiator waiting to receive first message from responder...') + const receivedMessageBuffer = decode1((await this.connection.readLP()).slice()) + const { plaintext, valid } = this.xx.recvMessage(this.session, receivedMessageBuffer) + if (!valid) { + throw new Error('xx handshake stage 1 validation fail') } - logger('Stage 1 - Initiator received the message.'); + logger('Stage 1 - Initiator received the message.') logRemoteEphemeralKey(this.session.hs.re) logRemoteStaticKey(this.session.hs.rs) - logger("Initiator going to check remote's signature..."); + logger("Initiator going to check remote's signature...") try { - const decodedPayload = await decodePayload(plaintext); - this.remotePeer = this.remotePeer || await getPeerIdFromPayload(decodedPayload); - this.remotePeer = await verifySignedPayload(receivedMessageBuffer.ns, decodedPayload, this.remotePeer); + const decodedPayload = await decodePayload(plaintext) + this.remotePeer = this.remotePeer || await getPeerIdFromPayload(decodedPayload) + this.remotePeer = await verifySignedPayload(receivedMessageBuffer.ns, decodedPayload, this.remotePeer) this.setRemoteEarlyData(decodedPayload.data) } catch (e) { - throw new Error(`Error occurred while verifying signed payload: ${e.message}`); + throw new Error(`Error occurred while verifying signed payload: ${e.message}`) } - logger("All good with the signature!"); + logger('All good with the signature!') } else { - logger('Stage 1 - Responder sending out first message with signed payload and static key.'); - const messageBuffer = this.xx.sendMessage(this.session, this.payload); - this.connection.writeLP(encode1(messageBuffer)); + logger('Stage 1 - Responder sending out first message with signed payload and static key.') + const messageBuffer = this.xx.sendMessage(this.session, this.payload) + this.connection.writeLP(encode1(messageBuffer)) logger('Stage 1 - Responder sent the second handshake message with signed payload.') logLocalEphemeralKeys(this.session.hs.e) } } // stage 2 - public async finish(): Promise { + public async finish (): Promise { if (this.isInitiator) { - logger('Stage 2 - Initiator sending third handshake message.'); - const messageBuffer = this.xx.sendMessage(this.session, this.payload); - this.connection.writeLP(encode2(messageBuffer)); - logger('Stage 2 - Initiator sent message with signed payload.'); + logger('Stage 2 - Initiator sending third handshake message.') + const messageBuffer = this.xx.sendMessage(this.session, this.payload) + this.connection.writeLP(encode2(messageBuffer)) + logger('Stage 2 - Initiator sent message with signed payload.') } else { - logger('Stage 2 - Responder waiting for third handshake message...'); - const receivedMessageBuffer = decode2((await this.connection.readLP()).slice()); - const {plaintext, valid} = this.xx.recvMessage(this.session, receivedMessageBuffer); - if(!valid) { - throw new Error("xx handshake stage 2 validation fail"); + logger('Stage 2 - Responder waiting for third handshake message...') + const receivedMessageBuffer = decode2((await this.connection.readLP()).slice()) + const { plaintext, valid } = this.xx.recvMessage(this.session, receivedMessageBuffer) + if (!valid) { + throw new Error('xx handshake stage 2 validation fail') } - logger('Stage 2 - Responder received the message, finished handshake.'); + logger('Stage 2 - Responder received the message, finished handshake.') try { - const decodedPayload = await decodePayload(plaintext); - this.remotePeer = this.remotePeer || await getPeerIdFromPayload(decodedPayload); - await verifySignedPayload(this.session.hs.rs, decodedPayload, this.remotePeer); + const decodedPayload = await decodePayload(plaintext) + this.remotePeer = this.remotePeer || await getPeerIdFromPayload(decodedPayload) + await verifySignedPayload(this.session.hs.rs, decodedPayload, this.remotePeer) this.setRemoteEarlyData(decodedPayload.data) } catch (e) { - throw new Error(`Error occurred while verifying signed payload: ${e.message}`); + throw new Error(`Error occurred while verifying signed payload: ${e.message}`) } } logCipherState(this.session) } - public encrypt(plaintext: bytes, session: NoiseSession): bytes { - const cs = this.getCS(session); + public encrypt (plaintext: bytes, session: NoiseSession): bytes { + const cs = this.getCS(session) - return this.xx.encryptWithAd(cs, Buffer.alloc(0), plaintext); + return this.xx.encryptWithAd(cs, Buffer.alloc(0), plaintext) } - public decrypt(ciphertext: bytes, session: NoiseSession): {plaintext: bytes; valid: boolean} { - const cs = this.getCS(session, false); - return this.xx.decryptWithAd(cs, Buffer.alloc(0), ciphertext); + public decrypt (ciphertext: bytes, session: NoiseSession): {plaintext: bytes; valid: boolean} { + const cs = this.getCS(session, false) + return this.xx.decryptWithAd(cs, Buffer.alloc(0), ciphertext) } - public getRemoteStaticKey(): bytes { - return this.session.hs.rs; + public getRemoteStaticKey (): bytes { + return this.session.hs.rs } - private getCS(session: NoiseSession, encryption = true) { + private getCS (session: NoiseSession, encryption = true) { if (!session.cs1 || !session.cs2) { - throw new Error("Handshake not completed properly, cipher state does not exist."); + throw new Error('Handshake not completed properly, cipher state does not exist.') } if (this.isInitiator) { - return encryption ? session.cs1 : session.cs2; + return encryption ? session.cs1 : session.cs2 } else { - return encryption ? session.cs2 : session.cs1; + return encryption ? session.cs2 : session.cs1 } } - protected setRemoteEarlyData(data: Uint8Array|null|undefined): void { - if(data){ - this.remoteEarlyData = Buffer.from(data.buffer, data.byteOffset, data.length); + protected setRemoteEarlyData (data: Uint8Array|null|undefined): void { + if (data) { + this.remoteEarlyData = Buffer.from(data.buffer, data.byteOffset, data.length) } } } diff --git a/src/handshakes/abstract-handshake.ts b/src/handshakes/abstract-handshake.ts index 85d63b7..83a5d53 100644 --- a/src/handshakes/abstract-handshake.ts +++ b/src/handshakes/abstract-handshake.ts @@ -1,180 +1,179 @@ -import {Buffer} from "buffer"; -import AEAD from 'bcrypto/lib/js/aead'; -import x25519 from 'bcrypto/lib/js/x25519'; -import SHA256 from 'bcrypto/lib/js/sha256'; +import { Buffer } from 'buffer' +import AEAD from 'bcrypto/lib/js/aead' +import x25519 from 'bcrypto/lib/js/x25519' +import SHA256 from 'bcrypto/lib/js/sha256' -import {bytes, bytes32, uint32} from "../@types/basic"; -import {CipherState, MessageBuffer, SymmetricState} from "../@types/handshake"; -import {getHkdf} from "../utils"; -import {logger} from "../logger"; +import { bytes, bytes32, uint32 } from '../@types/basic' +import { CipherState, MessageBuffer, SymmetricState } from '../@types/handshake' +import { getHkdf } from '../utils' +import { logger } from '../logger' -export const MIN_NONCE = 0; +export const MIN_NONCE = 0 export abstract class AbstractHandshake { - public encryptWithAd(cs: CipherState, ad: bytes, plaintext: bytes): bytes { - const e = this.encrypt(cs.k, cs.n, ad, plaintext); - this.setNonce(cs, this.incrementNonce(cs.n)); + public encryptWithAd (cs: CipherState, ad: bytes, plaintext: bytes): bytes { + const e = this.encrypt(cs.k, cs.n, ad, plaintext) + this.setNonce(cs, this.incrementNonce(cs.n)) - return e; + return e } - public decryptWithAd(cs: CipherState, ad: bytes, ciphertext: bytes): {plaintext: bytes; valid: boolean} { - const {plaintext, valid} = this.decrypt(cs.k, cs.n, ad, ciphertext); - this.setNonce(cs, this.incrementNonce(cs.n)); + public decryptWithAd (cs: CipherState, ad: bytes, ciphertext: bytes): {plaintext: bytes; valid: boolean} { + const { plaintext, valid } = this.decrypt(cs.k, cs.n, ad, ciphertext) + this.setNonce(cs, this.incrementNonce(cs.n)) - return {plaintext, valid}; + return { plaintext, valid } } - // Cipher state related - protected hasKey(cs: CipherState): boolean { - return !this.isEmptyKey(cs.k); + protected hasKey (cs: CipherState): boolean { + return !this.isEmptyKey(cs.k) } - protected setNonce(cs: CipherState, nonce: uint32): void { - cs.n = nonce; + protected setNonce (cs: CipherState, nonce: uint32): void { + cs.n = nonce } - protected createEmptyKey(): bytes32 { - return Buffer.alloc(32); + protected createEmptyKey (): bytes32 { + return Buffer.alloc(32) } - protected isEmptyKey(k: bytes32): boolean { - const emptyKey = this.createEmptyKey(); - return emptyKey.equals(k); + protected isEmptyKey (k: bytes32): boolean { + const emptyKey = this.createEmptyKey() + return emptyKey.equals(k) } - protected incrementNonce(n: uint32): uint32 { - return n + 1; + protected incrementNonce (n: uint32): uint32 { + return n + 1 } - protected nonceToBytes(n: uint32): bytes { - const nonce = Buffer.alloc(12); - nonce.writeUInt32LE(n, 4); + protected nonceToBytes (n: uint32): bytes { + const nonce = Buffer.alloc(12) + nonce.writeUInt32LE(n, 4) - return nonce; + return nonce } - protected encrypt(k: bytes32, n: uint32, ad: bytes, plaintext: bytes): bytes { - const nonce = this.nonceToBytes(n); - const ctx = new AEAD(); - plaintext = Buffer.from(plaintext); - ctx.init(k, nonce); - ctx.aad(ad); - ctx.encrypt(plaintext); + protected encrypt (k: bytes32, n: uint32, ad: bytes, plaintext: bytes): bytes { + const nonce = this.nonceToBytes(n) + const ctx = new AEAD() + plaintext = Buffer.from(plaintext) + ctx.init(k, nonce) + ctx.aad(ad) + ctx.encrypt(plaintext) // Encryption is done on the sent reference - return Buffer.concat([plaintext, ctx.final()]); + return Buffer.concat([plaintext, ctx.final()]) } - protected encryptAndHash(ss: SymmetricState, plaintext: bytes): bytes { - let ciphertext; + protected encryptAndHash (ss: SymmetricState, plaintext: bytes): bytes { + let ciphertext if (this.hasKey(ss.cs)) { - ciphertext = this.encryptWithAd(ss.cs, ss.h, plaintext); + ciphertext = this.encryptWithAd(ss.cs, ss.h, plaintext) } else { - ciphertext = plaintext; + ciphertext = plaintext } - this.mixHash(ss, ciphertext); - return ciphertext; + this.mixHash(ss, ciphertext) + return ciphertext } - protected decrypt(k: bytes32, n: uint32, ad: bytes, ciphertext: bytes): {plaintext: bytes; valid: boolean} { - const nonce = this.nonceToBytes(n); - const ctx = new AEAD(); - ciphertext = Buffer.from(ciphertext); - const tag = ciphertext.slice(ciphertext.length - 16); - ciphertext = ciphertext.slice(0, ciphertext.length - 16); - ctx.init(k, nonce); - ctx.aad(ad); - ctx.decrypt(ciphertext); + protected decrypt (k: bytes32, n: uint32, ad: bytes, ciphertext: bytes): {plaintext: bytes; valid: boolean} { + const nonce = this.nonceToBytes(n) + const ctx = new AEAD() + ciphertext = Buffer.from(ciphertext) + const tag = ciphertext.slice(ciphertext.length - 16) + ciphertext = ciphertext.slice(0, ciphertext.length - 16) + ctx.init(k, nonce) + ctx.aad(ad) + ctx.decrypt(ciphertext) // Decryption is done on the sent reference - return {plaintext: ciphertext, valid: ctx.verify(tag)}; + return { plaintext: ciphertext, valid: ctx.verify(tag) } } - protected decryptAndHash(ss: SymmetricState, ciphertext: bytes): {plaintext: bytes; valid: boolean} { - let plaintext: bytes, valid = true; + protected decryptAndHash (ss: SymmetricState, ciphertext: bytes): {plaintext: bytes; valid: boolean} { + let plaintext: bytes; let valid = true if (this.hasKey(ss.cs)) { - ({plaintext, valid} = this.decryptWithAd(ss.cs, ss.h, ciphertext)); + ({ plaintext, valid } = this.decryptWithAd(ss.cs, ss.h, ciphertext)) } else { - plaintext = ciphertext; + plaintext = ciphertext } - this.mixHash(ss, ciphertext); - return {plaintext, valid}; + this.mixHash(ss, ciphertext) + return { plaintext, valid } } - protected dh(privateKey: bytes32, publicKey: bytes32): bytes32 { + protected dh (privateKey: bytes32, publicKey: bytes32): bytes32 { try { - const derived = x25519.derive(publicKey, privateKey); - const result = Buffer.alloc(32); - derived.copy(result); - return result; + const derived = x25519.derive(publicKey, privateKey) + const result = Buffer.alloc(32) + derived.copy(result) + return result } catch (e) { - logger(e.message); - return Buffer.alloc(32); + logger(e.message) + return Buffer.alloc(32) } } - protected mixHash(ss: SymmetricState, data: bytes): void { - ss.h = this.getHash(ss.h, data); + protected mixHash (ss: SymmetricState, data: bytes): void { + ss.h = this.getHash(ss.h, data) } - protected getHash(a: bytes, b: bytes): bytes32 { - return SHA256.digest(Buffer.from([...a, ...b])); + protected getHash (a: bytes, b: bytes): bytes32 { + return SHA256.digest(Buffer.from([...a, ...b])) } - protected mixKey(ss: SymmetricState, ikm: bytes32): void { - const [ ck, tempK ] = getHkdf(ss.ck, ikm); - ss.cs = this.initializeKey(tempK) as CipherState; - ss.ck = ck; + protected mixKey (ss: SymmetricState, ikm: bytes32): void { + const [ck, tempK] = getHkdf(ss.ck, ikm) + ss.cs = this.initializeKey(tempK) as CipherState + ss.ck = ck } - protected initializeKey(k: bytes32): CipherState { - const n = MIN_NONCE; - return { k, n }; + protected initializeKey (k: bytes32): CipherState { + const n = MIN_NONCE + return { k, n } } // Symmetric state related - protected initializeSymmetric(protocolName: string): SymmetricState { - const protocolNameBytes: bytes = Buffer.from(protocolName, 'utf-8'); - const h = this.hashProtocolName(protocolNameBytes); + protected initializeSymmetric (protocolName: string): SymmetricState { + const protocolNameBytes: bytes = Buffer.from(protocolName, 'utf-8') + const h = this.hashProtocolName(protocolNameBytes) - const ck = h; - const key = this.createEmptyKey(); - const cs: CipherState = this.initializeKey(key); + const ck = h + const key = this.createEmptyKey() + const cs: CipherState = this.initializeKey(key) - return { cs, ck, h }; + return { cs, ck, h } } - protected hashProtocolName(protocolName: bytes): bytes32 { + protected hashProtocolName (protocolName: bytes): bytes32 { if (protocolName.length <= 32) { - const h = Buffer.alloc(32); - protocolName.copy(h); - return h; + const h = Buffer.alloc(32) + protocolName.copy(h) + return h } else { - return this.getHash(protocolName, Buffer.alloc(0)); + return this.getHash(protocolName, Buffer.alloc(0)) } } - protected split(ss: SymmetricState) { - const [ tempk1, tempk2 ] = getHkdf(ss.ck, Buffer.alloc(0)); - const cs1 = this.initializeKey(tempk1); - const cs2 = this.initializeKey(tempk2); + protected split (ss: SymmetricState) { + const [tempk1, tempk2] = getHkdf(ss.ck, Buffer.alloc(0)) + const cs1 = this.initializeKey(tempk1) + const cs2 = this.initializeKey(tempk2) - return { cs1, cs2 }; + return { cs1, cs2 } } - protected writeMessageRegular(cs: CipherState, payload: bytes): MessageBuffer { - const ciphertext = this.encryptWithAd(cs, Buffer.alloc(0), payload); - const ne = this.createEmptyKey(); - const ns = Buffer.alloc(0); + protected writeMessageRegular (cs: CipherState, payload: bytes): MessageBuffer { + const ciphertext = this.encryptWithAd(cs, Buffer.alloc(0), payload) + const ne = this.createEmptyKey() + const ns = Buffer.alloc(0) - return { ne, ns, ciphertext }; + return { ne, ns, ciphertext } } - protected readMessageRegular(cs: CipherState, message: MessageBuffer): {plaintext: bytes; valid: boolean} { - return this.decryptWithAd(cs, Buffer.alloc(0), message.ciphertext); + protected readMessageRegular (cs: CipherState, message: MessageBuffer): {plaintext: bytes; valid: boolean} { + return this.decryptWithAd(cs, Buffer.alloc(0), message.ciphertext) } } diff --git a/src/handshakes/ik.ts b/src/handshakes/ik.ts index 56dd8b0..c57797d 100644 --- a/src/handshakes/ik.ts +++ b/src/handshakes/ik.ts @@ -1,157 +1,156 @@ -import {Buffer} from "buffer"; -import {CipherState, HandshakeState, MessageBuffer, NoiseSession} from "../@types/handshake"; -import {bytes, bytes32} from "../@types/basic"; -import {generateKeypair, isValidPublicKey} from "../utils"; -import {AbstractHandshake} from "./abstract-handshake"; -import {KeyPair} from "../@types/libp2p"; - +import { Buffer } from 'buffer' +import { CipherState, HandshakeState, MessageBuffer, NoiseSession } from '../@types/handshake' +import { bytes, bytes32 } from '../@types/basic' +import { generateKeypair, isValidPublicKey } from '../utils' +import { AbstractHandshake } from './abstract-handshake' +import { KeyPair } from '../@types/libp2p' export class IK extends AbstractHandshake { - public initSession(initiator: boolean, prologue: bytes32, s: KeyPair, rs: bytes32): NoiseSession { - const psk = this.createEmptyKey(); + public initSession (initiator: boolean, prologue: bytes32, s: KeyPair, rs: bytes32): NoiseSession { + const psk = this.createEmptyKey() - let hs; + let hs if (initiator) { - hs = this.initializeInitiator(prologue, s, rs, psk); + hs = this.initializeInitiator(prologue, s, rs, psk) } else { - hs = this.initializeResponder(prologue, s, rs, psk); + hs = this.initializeResponder(prologue, s, rs, psk) } return { hs, i: initiator, - mc: 0, - }; + mc: 0 + } } - public sendMessage(session: NoiseSession, message: bytes): MessageBuffer { - let messageBuffer: MessageBuffer; + public sendMessage (session: NoiseSession, message: bytes): MessageBuffer { + let messageBuffer: MessageBuffer if (session.mc === 0) { - messageBuffer = this.writeMessageA(session.hs, message); + messageBuffer = this.writeMessageA(session.hs, message) } else if (session.mc === 1) { - const { messageBuffer: mb, h, cs1, cs2 } = this.writeMessageB(session.hs, message); - messageBuffer = mb; - session.h = h; - session.cs1 = cs1; - session.cs2 = cs2; + const { messageBuffer: mb, h, cs1, cs2 } = this.writeMessageB(session.hs, message) + messageBuffer = mb + session.h = h + session.cs1 = cs1 + session.cs2 = cs2 } else if (session.mc > 1) { if (session.i) { if (!session.cs1) { - throw new Error("CS1 (cipher state) is not defined") + throw new Error('CS1 (cipher state) is not defined') } - messageBuffer = this.writeMessageRegular(session.cs1, message); + messageBuffer = this.writeMessageRegular(session.cs1, message) } else { if (!session.cs2) { - throw new Error("CS2 (cipher state) is not defined") + throw new Error('CS2 (cipher state) is not defined') } - messageBuffer = this.writeMessageRegular(session.cs2, message); + messageBuffer = this.writeMessageRegular(session.cs2, message) } } else { - throw new Error("Session invalid.") + throw new Error('Session invalid.') } - session.mc++; - return messageBuffer; + session.mc++ + return messageBuffer } - public recvMessage(session: NoiseSession, message: MessageBuffer): {plaintext: bytes; valid: boolean} { - let plaintext = Buffer.alloc(0), valid = false; + public recvMessage (session: NoiseSession, message: MessageBuffer): {plaintext: bytes; valid: boolean} { + let plaintext = Buffer.alloc(0); let valid = false if (session.mc === 0) { - ({plaintext, valid} = this.readMessageA(session.hs, message)); + ({ plaintext, valid } = this.readMessageA(session.hs, message)) } if (session.mc === 1) { - const { plaintext: pt, valid: v, h, cs1, cs2 } = this.readMessageB(session.hs, message); - plaintext = pt; - valid = v; - session.h = h; - session.cs1 = cs1; - session.cs2 = cs2; + const { plaintext: pt, valid: v, h, cs1, cs2 } = this.readMessageB(session.hs, message) + plaintext = pt + valid = v + session.h = h + session.cs1 = cs1 + session.cs2 = cs2 } - session.mc++; - return {plaintext, valid}; + session.mc++ + return { plaintext, valid } } - private writeMessageA(hs: HandshakeState, payload: bytes): MessageBuffer { - hs.e = generateKeypair(); - const ne = hs.e.publicKey; - this.mixHash(hs.ss, ne); - this.mixKey(hs.ss, this.dh(hs.e.privateKey, hs.rs)); - const spk = Buffer.from(hs.s.publicKey); - const ns = this.encryptAndHash(hs.ss, spk); + private writeMessageA (hs: HandshakeState, payload: bytes): MessageBuffer { + hs.e = generateKeypair() + const ne = hs.e.publicKey + this.mixHash(hs.ss, ne) + this.mixKey(hs.ss, this.dh(hs.e.privateKey, hs.rs)) + const spk = Buffer.from(hs.s.publicKey) + const ns = this.encryptAndHash(hs.ss, spk) - this.mixKey(hs.ss, this.dh(hs.s.privateKey, hs.rs)); - const ciphertext = this.encryptAndHash(hs.ss, payload); + this.mixKey(hs.ss, this.dh(hs.s.privateKey, hs.rs)) + const ciphertext = this.encryptAndHash(hs.ss, payload) - return { ne, ns, ciphertext }; + return { ne, ns, ciphertext } } - private writeMessageB(hs: HandshakeState, payload: bytes) { - hs.e = generateKeypair(); - const ne = hs.e.publicKey; - this.mixHash(hs.ss, ne); + private writeMessageB (hs: HandshakeState, payload: bytes) { + hs.e = generateKeypair() + const ne = hs.e.publicKey + this.mixHash(hs.ss, ne) - this.mixKey(hs.ss, this.dh(hs.e.privateKey, hs.re)); - this.mixKey(hs.ss, this.dh(hs.e.privateKey, hs.rs)); - const ciphertext = this.encryptAndHash(hs.ss, payload); - const ns = this.createEmptyKey(); - const messageBuffer: MessageBuffer = {ne, ns, ciphertext}; - const { cs1, cs2 } = this.split(hs.ss); + this.mixKey(hs.ss, this.dh(hs.e.privateKey, hs.re)) + this.mixKey(hs.ss, this.dh(hs.e.privateKey, hs.rs)) + const ciphertext = this.encryptAndHash(hs.ss, payload) + const ns = this.createEmptyKey() + const messageBuffer: MessageBuffer = { ne, ns, ciphertext } + const { cs1, cs2 } = this.split(hs.ss) return { messageBuffer, cs1, cs2, h: hs.ss.h } } - private readMessageA(hs: HandshakeState, message: MessageBuffer): {plaintext: bytes; valid: boolean} { + private readMessageA (hs: HandshakeState, message: MessageBuffer): {plaintext: bytes; valid: boolean} { if (isValidPublicKey(message.ne)) { - hs.re = message.ne; + hs.re = message.ne } - this.mixHash(hs.ss, hs.re); - this.mixKey(hs.ss, this.dh(hs.s.privateKey, hs.re)); - const {plaintext: ns, valid: valid1} = this.decryptAndHash(hs.ss, message.ns); + this.mixHash(hs.ss, hs.re) + this.mixKey(hs.ss, this.dh(hs.s.privateKey, hs.re)) + const { plaintext: ns, valid: valid1 } = this.decryptAndHash(hs.ss, message.ns) if (valid1 && ns.length === 32 && isValidPublicKey(ns)) { - hs.rs = ns; + hs.rs = ns } - this.mixKey(hs.ss, this.dh(hs.s.privateKey, hs.rs)); - const {plaintext, valid: valid2} = this.decryptAndHash(hs.ss, message.ciphertext); - return {plaintext, valid: (valid1 && valid2)}; + this.mixKey(hs.ss, this.dh(hs.s.privateKey, hs.rs)) + const { plaintext, valid: valid2 } = this.decryptAndHash(hs.ss, message.ciphertext) + return { plaintext, valid: (valid1 && valid2) } } - private readMessageB(hs: HandshakeState, message: MessageBuffer): {h: bytes; plaintext: bytes; valid: boolean; cs1: CipherState; cs2: CipherState} { + private readMessageB (hs: HandshakeState, message: MessageBuffer): {h: bytes; plaintext: bytes; valid: boolean; cs1: CipherState; cs2: CipherState} { if (isValidPublicKey(message.ne)) { - hs.re = message.ne; + hs.re = message.ne } - this.mixHash(hs.ss, hs.re); + this.mixHash(hs.ss, hs.re) if (!hs.e) { - throw new Error("Handshake state should contain ephemeral key by now."); + throw new Error('Handshake state should contain ephemeral key by now.') } - this.mixKey(hs.ss, this.dh(hs.e.privateKey, hs.re)); - this.mixKey(hs.ss, this.dh(hs.s.privateKey, hs.re)); - const {plaintext, valid} = this.decryptAndHash(hs.ss, message.ciphertext); - const { cs1, cs2 } = this.split(hs.ss); + this.mixKey(hs.ss, this.dh(hs.e.privateKey, hs.re)) + this.mixKey(hs.ss, this.dh(hs.s.privateKey, hs.re)) + const { plaintext, valid } = this.decryptAndHash(hs.ss, message.ciphertext) + const { cs1, cs2 } = this.split(hs.ss) - return { h: hs.ss.h, valid, plaintext, cs1, cs2 }; + return { h: hs.ss.h, valid, plaintext, cs1, cs2 } } - private initializeInitiator(prologue: bytes32, s: KeyPair, rs: bytes32, psk: bytes32): HandshakeState { - const name = "Noise_IK_25519_ChaChaPoly_SHA256"; - const ss = this.initializeSymmetric(name); - this.mixHash(ss, prologue); - this.mixHash(ss, rs); - const re = Buffer.alloc(32); + private initializeInitiator (prologue: bytes32, s: KeyPair, rs: bytes32, psk: bytes32): HandshakeState { + const name = 'Noise_IK_25519_ChaChaPoly_SHA256' + const ss = this.initializeSymmetric(name) + this.mixHash(ss, prologue) + this.mixHash(ss, rs) + const re = Buffer.alloc(32) - return { ss, s, rs, re, psk }; + return { ss, s, rs, re, psk } } - private initializeResponder(prologue: bytes32, s: KeyPair, rs: bytes32, psk: bytes32): HandshakeState { - const name = "Noise_IK_25519_ChaChaPoly_SHA256"; - const ss = this.initializeSymmetric(name); - this.mixHash(ss, prologue); - this.mixHash(ss, s.publicKey); - const re = Buffer.alloc(32); + private initializeResponder (prologue: bytes32, s: KeyPair, rs: bytes32, psk: bytes32): HandshakeState { + const name = 'Noise_IK_25519_ChaChaPoly_SHA256' + const ss = this.initializeSymmetric(name) + this.mixHash(ss, prologue) + this.mixHash(ss, s.publicKey) + const re = Buffer.alloc(32) - return { ss, s, rs, re, psk }; + return { ss, s, rs, re, psk } } } diff --git a/src/handshakes/xx.ts b/src/handshakes/xx.ts index 4e608d0..1a09218 100644 --- a/src/handshakes/xx.ts +++ b/src/handshakes/xx.ts @@ -1,186 +1,185 @@ -import { Buffer } from 'buffer'; +import { Buffer } from 'buffer' import { bytes32, bytes } from '../@types/basic' import { KeyPair } from '../@types/libp2p' -import {generateKeypair, isValidPublicKey} from '../utils'; -import {CipherState, HandshakeState, MessageBuffer, NoiseSession} from "../@types/handshake"; -import {AbstractHandshake} from "./abstract-handshake"; - +import { generateKeypair, isValidPublicKey } from '../utils' +import { CipherState, HandshakeState, MessageBuffer, NoiseSession } from '../@types/handshake' +import { AbstractHandshake } from './abstract-handshake' export class XX extends AbstractHandshake { - private initializeInitiator(prologue: bytes32, s: KeyPair, rs: bytes32, psk: bytes32): HandshakeState { - const name = "Noise_XX_25519_ChaChaPoly_SHA256"; - const ss = this.initializeSymmetric(name); - this.mixHash(ss, prologue); - const re = Buffer.alloc(32); + private initializeInitiator (prologue: bytes32, s: KeyPair, rs: bytes32, psk: bytes32): HandshakeState { + const name = 'Noise_XX_25519_ChaChaPoly_SHA256' + const ss = this.initializeSymmetric(name) + this.mixHash(ss, prologue) + const re = Buffer.alloc(32) - return { ss, s, rs, psk, re }; + return { ss, s, rs, psk, re } } - private initializeResponder(prologue: bytes32, s: KeyPair, rs: bytes32, psk: bytes32): HandshakeState { - const name = "Noise_XX_25519_ChaChaPoly_SHA256"; - const ss = this.initializeSymmetric(name); - this.mixHash(ss, prologue); - const re = Buffer.alloc(32); + private initializeResponder (prologue: bytes32, s: KeyPair, rs: bytes32, psk: bytes32): HandshakeState { + const name = 'Noise_XX_25519_ChaChaPoly_SHA256' + const ss = this.initializeSymmetric(name) + this.mixHash(ss, prologue) + const re = Buffer.alloc(32) - return { ss, s, rs, psk, re }; + return { ss, s, rs, psk, re } } - private writeMessageA(hs: HandshakeState, payload: bytes, e?: KeyPair): MessageBuffer { - const ns = Buffer.alloc(0); + private writeMessageA (hs: HandshakeState, payload: bytes, e?: KeyPair): MessageBuffer { + const ns = Buffer.alloc(0) if (e) { - hs.e = e; + hs.e = e } else { - hs.e = generateKeypair(); + hs.e = generateKeypair() } - const ne = hs.e.publicKey; + const ne = hs.e.publicKey - this.mixHash(hs.ss, ne); - const ciphertext = this.encryptAndHash(hs.ss, payload); + this.mixHash(hs.ss, ne) + const ciphertext = this.encryptAndHash(hs.ss, payload) - return {ne, ns, ciphertext}; + return { ne, ns, ciphertext } } - private writeMessageB(hs: HandshakeState, payload: bytes): MessageBuffer { - hs.e = generateKeypair(); - const ne = hs.e.publicKey; - this.mixHash(hs.ss, ne); + private writeMessageB (hs: HandshakeState, payload: bytes): MessageBuffer { + hs.e = generateKeypair() + const ne = hs.e.publicKey + this.mixHash(hs.ss, ne) - this.mixKey(hs.ss, this.dh(hs.e.privateKey, hs.re)); - const spk = Buffer.from(hs.s.publicKey); - const ns = this.encryptAndHash(hs.ss, spk); + this.mixKey(hs.ss, this.dh(hs.e.privateKey, hs.re)) + const spk = Buffer.from(hs.s.publicKey) + const ns = this.encryptAndHash(hs.ss, spk) - this.mixKey(hs.ss, this.dh(hs.s.privateKey, hs.re)); - const ciphertext = this.encryptAndHash(hs.ss, payload); + this.mixKey(hs.ss, this.dh(hs.s.privateKey, hs.re)) + const ciphertext = this.encryptAndHash(hs.ss, payload) - return { ne, ns, ciphertext }; + return { ne, ns, ciphertext } } - private writeMessageC(hs: HandshakeState, payload: bytes) { - const spk = Buffer.from(hs.s.publicKey); - const ns = this.encryptAndHash(hs.ss, spk); - this.mixKey(hs.ss, this.dh(hs.s.privateKey, hs.re)); - const ciphertext = this.encryptAndHash(hs.ss, payload); - const ne = this.createEmptyKey(); - const messageBuffer: MessageBuffer = {ne, ns, ciphertext}; - const { cs1, cs2 } = this.split(hs.ss); + private writeMessageC (hs: HandshakeState, payload: bytes) { + const spk = Buffer.from(hs.s.publicKey) + const ns = this.encryptAndHash(hs.ss, spk) + this.mixKey(hs.ss, this.dh(hs.s.privateKey, hs.re)) + const ciphertext = this.encryptAndHash(hs.ss, payload) + const ne = this.createEmptyKey() + const messageBuffer: MessageBuffer = { ne, ns, ciphertext } + const { cs1, cs2 } = this.split(hs.ss) - return { h: hs.ss.h, messageBuffer, cs1, cs2 }; + return { h: hs.ss.h, messageBuffer, cs1, cs2 } } - private readMessageA(hs: HandshakeState, message: MessageBuffer): {plaintext: bytes; valid: boolean} { + private readMessageA (hs: HandshakeState, message: MessageBuffer): {plaintext: bytes; valid: boolean} { if (isValidPublicKey(message.ne)) { - hs.re = message.ne; + hs.re = message.ne } - this.mixHash(hs.ss, hs.re); - return this.decryptAndHash(hs.ss, message.ciphertext); + this.mixHash(hs.ss, hs.re) + return this.decryptAndHash(hs.ss, message.ciphertext) } - private readMessageB(hs: HandshakeState, message: MessageBuffer): {plaintext: bytes; valid: boolean} { + private readMessageB (hs: HandshakeState, message: MessageBuffer): {plaintext: bytes; valid: boolean} { if (isValidPublicKey(message.ne)) { - hs.re = message.ne; + hs.re = message.ne } - this.mixHash(hs.ss, hs.re); + this.mixHash(hs.ss, hs.re) if (!hs.e) { - throw new Error("Handshake state `e` param is missing."); + throw new Error('Handshake state `e` param is missing.') } - this.mixKey(hs.ss, this.dh(hs.e.privateKey, hs.re)); - const {plaintext: ns, valid: valid1} = this.decryptAndHash(hs.ss, message.ns); + this.mixKey(hs.ss, this.dh(hs.e.privateKey, hs.re)) + const { plaintext: ns, valid: valid1 } = this.decryptAndHash(hs.ss, message.ns) if (valid1 && ns.length === 32 && isValidPublicKey(ns)) { - hs.rs = ns; + hs.rs = ns } - this.mixKey(hs.ss, this.dh(hs.e.privateKey, hs.rs)); - const {plaintext, valid: valid2} = this.decryptAndHash(hs.ss, message.ciphertext); - return {plaintext, valid: (valid1 && valid2)}; + this.mixKey(hs.ss, this.dh(hs.e.privateKey, hs.rs)) + const { plaintext, valid: valid2 } = this.decryptAndHash(hs.ss, message.ciphertext) + return { plaintext, valid: (valid1 && valid2) } } - private readMessageC(hs: HandshakeState, message: MessageBuffer): {h: bytes; plaintext: bytes; valid: boolean; cs1: CipherState; cs2: CipherState} { - const {plaintext: ns, valid: valid1} = this.decryptAndHash(hs.ss, message.ns); + private readMessageC (hs: HandshakeState, message: MessageBuffer): {h: bytes; plaintext: bytes; valid: boolean; cs1: CipherState; cs2: CipherState} { + const { plaintext: ns, valid: valid1 } = this.decryptAndHash(hs.ss, message.ns) if (valid1 && ns.length === 32 && isValidPublicKey(ns)) { - hs.rs = ns; + hs.rs = ns } if (!hs.e) { - throw new Error("Handshake state `e` param is missing."); + throw new Error('Handshake state `e` param is missing.') } - this.mixKey(hs.ss, this.dh(hs.e.privateKey, hs.rs)); + this.mixKey(hs.ss, this.dh(hs.e.privateKey, hs.rs)) - const {plaintext, valid: valid2} = this.decryptAndHash(hs.ss, message.ciphertext); - const { cs1, cs2 } = this.split(hs.ss); + const { plaintext, valid: valid2 } = this.decryptAndHash(hs.ss, message.ciphertext) + const { cs1, cs2 } = this.split(hs.ss) - return { h: hs.ss.h, plaintext, valid: (valid1 && valid2), cs1, cs2 }; + return { h: hs.ss.h, plaintext, valid: (valid1 && valid2), cs1, cs2 } } - public initSession(initiator: boolean, prologue: bytes32, s: KeyPair): NoiseSession { - const psk = this.createEmptyKey(); - const rs = Buffer.alloc(32); // no static key yet - let hs; + public initSession (initiator: boolean, prologue: bytes32, s: KeyPair): NoiseSession { + const psk = this.createEmptyKey() + const rs = Buffer.alloc(32) // no static key yet + let hs if (initiator) { - hs = this.initializeInitiator(prologue, s, rs, psk); + hs = this.initializeInitiator(prologue, s, rs, psk) } else { - hs = this.initializeResponder(prologue, s, rs, psk); + hs = this.initializeResponder(prologue, s, rs, psk) } return { hs, i: initiator, - mc: 0, - }; + mc: 0 + } } - public sendMessage(session: NoiseSession, message: bytes, ephemeral?: KeyPair): MessageBuffer { - let messageBuffer: MessageBuffer; + public sendMessage (session: NoiseSession, message: bytes, ephemeral?: KeyPair): MessageBuffer { + let messageBuffer: MessageBuffer if (session.mc === 0) { - messageBuffer = this.writeMessageA(session.hs, message, ephemeral); + messageBuffer = this.writeMessageA(session.hs, message, ephemeral) } else if (session.mc === 1) { - messageBuffer = this.writeMessageB(session.hs, message); + messageBuffer = this.writeMessageB(session.hs, message) } else if (session.mc === 2) { - const { h, messageBuffer: resultingBuffer, cs1, cs2 } = this.writeMessageC(session.hs, message); - messageBuffer = resultingBuffer; - session.h = h; - session.cs1 = cs1; - session.cs2 = cs2; + const { h, messageBuffer: resultingBuffer, cs1, cs2 } = this.writeMessageC(session.hs, message) + messageBuffer = resultingBuffer + session.h = h + session.cs1 = cs1 + session.cs2 = cs2 } else if (session.mc > 2) { if (session.i) { if (!session.cs1) { - throw new Error("CS1 (cipher state) is not defined") + throw new Error('CS1 (cipher state) is not defined') } - messageBuffer = this.writeMessageRegular(session.cs1, message); + messageBuffer = this.writeMessageRegular(session.cs1, message) } else { if (!session.cs2) { - throw new Error("CS2 (cipher state) is not defined") + throw new Error('CS2 (cipher state) is not defined') } - messageBuffer = this.writeMessageRegular(session.cs2, message); + messageBuffer = this.writeMessageRegular(session.cs2, message) } } else { - throw new Error("Session invalid.") + throw new Error('Session invalid.') } - session.mc++; - return messageBuffer; + session.mc++ + return messageBuffer } - public recvMessage(session: NoiseSession, message: MessageBuffer): {plaintext: bytes; valid: boolean} { - let plaintext: bytes = Buffer.alloc(0); - let valid = false; + public recvMessage (session: NoiseSession, message: MessageBuffer): {plaintext: bytes; valid: boolean} { + let plaintext: bytes = Buffer.alloc(0) + let valid = false if (session.mc === 0) { - ({plaintext, valid} = this.readMessageA(session.hs, message)); + ({ plaintext, valid } = this.readMessageA(session.hs, message)) } else if (session.mc === 1) { - ({plaintext, valid} = this.readMessageB(session.hs, message)); + ({ plaintext, valid } = this.readMessageB(session.hs, message)) } else if (session.mc === 2) { - const { h, plaintext: resultingPlaintext, valid: resultingValid, cs1, cs2 } = this.readMessageC(session.hs, message); - plaintext = resultingPlaintext; - valid = resultingValid; - session.h = h; - session.cs1 = cs1; - session.cs2 = cs2; + const { h, plaintext: resultingPlaintext, valid: resultingValid, cs1, cs2 } = this.readMessageC(session.hs, message) + plaintext = resultingPlaintext + valid = resultingValid + session.h = h + session.cs1 = cs1 + session.cs2 = cs2 } - session.mc++; - return {plaintext, valid}; + session.mc++ + return { plaintext, valid } } } diff --git a/src/index.ts b/src/index.ts index 2c1d8b3..96a253e 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,7 +1,7 @@ -import {Noise} from "./noise"; -export * from "./noise"; +import { Noise } from './noise' +export * from './noise' /** * Default configuration, it will generate new noise static key and enable noise pipes (IK handshake). */ -export const NOISE = new Noise(); +export const NOISE = new Noise() diff --git a/src/keycache.ts b/src/keycache.ts index 56bb013..9574a46 100644 --- a/src/keycache.ts +++ b/src/keycache.ts @@ -1,5 +1,5 @@ -import {bytes, bytes32} from "./@types/basic"; -import PeerId from "peer-id"; +import { bytes, bytes32 } from './@types/basic' +import PeerId from 'peer-id' /** * Storage for static keys of previously connected peers. @@ -7,24 +7,23 @@ import PeerId from "peer-id"; class Keycache { private storage = new Map(); - public store(peerId: PeerId, key: bytes32): void { - this.storage.set(peerId.id, key); + public store (peerId: PeerId, key: bytes32): void { + this.storage.set(peerId.id, key) } - public load(peerId?: PeerId): bytes32 | null { - if(!peerId) { - return null; + public load (peerId?: PeerId): bytes32 | null { + if (!peerId) { + return null } - return this.storage.get(peerId.id) || null; + return this.storage.get(peerId.id) || null } - public resetStorage(): void { - this.storage.clear(); + public resetStorage (): void { + this.storage.clear() } - } -const KeyCache = new Keycache(); +const KeyCache = new Keycache() export { - KeyCache, + KeyCache } diff --git a/src/logger.ts b/src/logger.ts index 25964dd..2cd1025 100644 --- a/src/logger.ts +++ b/src/logger.ts @@ -1,47 +1,44 @@ -import debug from "debug"; -import {DUMP_SESSION_KEYS} from './constants'; -import { KeyPair } from "./@types/libp2p"; -import { NoiseSession, SymmetricState } from "./@types/handshake"; +import debug from 'debug' +import { DUMP_SESSION_KEYS } from './constants' +import { KeyPair } from './@types/libp2p' +import { NoiseSession, SymmetricState } from './@types/handshake' -export const logger = debug('libp2p:noise'); +export const logger = debug('libp2p:noise') -let keyLogger; -if(DUMP_SESSION_KEYS){ +let keyLogger +if (DUMP_SESSION_KEYS) { keyLogger = logger -} -else { +} else { keyLogger = () => { /* do nothing */ } } -export function logLocalStaticKeys(s: KeyPair): void { +export function logLocalStaticKeys (s: KeyPair): void { keyLogger(`LOCAL_STATIC_PUBLIC_KEY ${s.publicKey.toString('hex')}`) keyLogger(`LOCAL_STATIC_PRIVATE_KEY ${s.privateKey.toString('hex')}`) } -export function logLocalEphemeralKeys(e: KeyPair|undefined): void { - if(e){ +export function logLocalEphemeralKeys (e: KeyPair|undefined): void { + if (e) { keyLogger(`LOCAL_PUBLIC_EPHEMERAL_KEY ${e.publicKey.toString('hex')}`) keyLogger(`LOCAL_PRIVATE_EPHEMERAL_KEY ${e.privateKey.toString('hex')}`) - } - else{ + } else { keyLogger('Missing local ephemeral keys.') } } -export function logRemoteStaticKey(rs: Buffer): void { +export function logRemoteStaticKey (rs: Buffer): void { keyLogger(`REMOTE_STATIC_PUBLIC_KEY ${rs.toString('hex')}`) } -export function logRemoteEphemeralKey(re: Buffer): void { +export function logRemoteEphemeralKey (re: Buffer): void { keyLogger(`REMOTE_EPHEMERAL_PUBLIC_KEY ${re.toString('hex')}`) } -export function logCipherState(session: NoiseSession): void { - if(session.cs1 && session.cs2){ +export function logCipherState (session: NoiseSession): void { + if (session.cs1 && session.cs2) { keyLogger(`CIPHER_STATE_1 ${session.cs1.n} ${session.cs1.k.toString('hex')}`) keyLogger(`CIPHER_STATE_2 ${session.cs2.n} ${session.cs2.k.toString('hex')}`) - } - else{ + } else { keyLogger('Missing cipher state.') } } diff --git a/src/noise.ts b/src/noise.ts index 4f2816f..1c97c0a 100644 --- a/src/noise.ts +++ b/src/noise.ts @@ -1,25 +1,25 @@ -import x25519 from 'bcrypto/lib/js/x25519'; -import {Buffer} from "buffer"; -import Wrap from 'it-pb-rpc'; -import DuplexPair from 'it-pair/duplex'; -import ensureBuffer from 'it-buffer'; -import pipe from 'it-pipe'; -import {encode, decode} from 'it-length-prefixed'; +import x25519 from 'bcrypto/lib/js/x25519' +import { Buffer } from 'buffer' +import Wrap from 'it-pb-rpc' +import DuplexPair from 'it-pair/duplex' +import ensureBuffer from 'it-buffer' +import pipe from 'it-pipe' +import { encode, decode } from 'it-length-prefixed' -import {XXHandshake} from "./handshake-xx"; -import {IKHandshake} from "./handshake-ik"; -import {XXFallbackHandshake} from "./handshake-xx-fallback"; -import {generateKeypair, getPayload} from "./utils"; -import {uint16BEDecode, uint16BEEncode} from "./encoder"; -import {decryptStream, encryptStream} from "./crypto"; -import {bytes} from "./@types/basic"; -import {INoiseConnection, KeyPair, SecureOutbound} from "./@types/libp2p"; -import {Duplex} from "it-pair"; -import {IHandshake} from "./@types/handshake-interface"; -import {KeyCache} from "./keycache"; -import {logger} from "./logger"; -import PeerId from "peer-id"; -import {NOISE_MSG_MAX_LENGTH_BYTES} from "./constants"; +import { XXHandshake } from './handshake-xx' +import { IKHandshake } from './handshake-ik' +import { XXFallbackHandshake } from './handshake-xx-fallback' +import { generateKeypair, getPayload } from './utils' +import { uint16BEDecode, uint16BEEncode } from './encoder' +import { decryptStream, encryptStream } from './crypto' +import { bytes } from './@types/basic' +import { INoiseConnection, KeyPair, SecureOutbound } from './@types/libp2p' +import { Duplex } from 'it-pair' +import { IHandshake } from './@types/handshake-interface' +import { KeyCache } from './keycache' +import { logger } from './logger' +import PeerId from 'peer-id' +import { NOISE_MSG_MAX_LENGTH_BYTES } from './constants' export type WrappedConnection = ReturnType; @@ -31,7 +31,7 @@ type HandshakeParams = { }; export class Noise implements INoiseConnection { - public protocol = "/noise"; + public protocol = '/noise'; private readonly prologue = Buffer.alloc(0); private readonly staticKeys: KeyPair; @@ -43,19 +43,19 @@ export class Noise implements INoiseConnection { * @param staticNoiseKey x25519 private key, reuse for faster handshakes * @param earlyData */ - constructor(staticNoiseKey?: bytes, earlyData?: bytes) { - this.earlyData = earlyData || Buffer.alloc(0); - //disabled until properly specked - this.useNoisePipes = false; + constructor (staticNoiseKey?: bytes, earlyData?: bytes) { + this.earlyData = earlyData || Buffer.alloc(0) + // disabled until properly specked + this.useNoisePipes = false if (staticNoiseKey) { - const publicKey = x25519.publicKeyCreate(staticNoiseKey); + const publicKey = x25519.publicKeyCreate(staticNoiseKey) this.staticKeys = { privateKey: staticNoiseKey, - publicKey, + publicKey } } else { - this.staticKeys = generateKeypair(); + this.staticKeys = generateKeypair() } } @@ -66,7 +66,7 @@ export class Noise implements INoiseConnection { * @param {PeerId} remotePeer - PeerId of the remote peer. Used to validate the integrity of the remote peer. * @returns {Promise} */ - public async secureOutbound(localPeer: PeerId, connection: any, remotePeer: PeerId): Promise { + public async secureOutbound (localPeer: PeerId, connection: any, remotePeer: PeerId): Promise { const wrappedConnection = Wrap( connection, { @@ -74,19 +74,19 @@ export class Noise implements INoiseConnection { lengthDecoder: uint16BEDecode, maxDataLength: NOISE_MSG_MAX_LENGTH_BYTES } - ); + ) const handshake = await this.performHandshake({ connection: wrappedConnection, isInitiator: true, localPeer, - remotePeer, - }); - const conn = await this.createSecureConnection(wrappedConnection, handshake); + remotePeer + }) + const conn = await this.createSecureConnection(wrappedConnection, handshake) return { conn, remoteEarlyData: handshake.remoteEarlyData, - remotePeer: handshake.remotePeer, + remotePeer: handshake.remotePeer } } @@ -97,7 +97,7 @@ export class Noise implements INoiseConnection { * @param {PeerId} remotePeer - optional PeerId of the initiating peer, if known. This may only exist during transport upgrades. * @returns {Promise} */ - public async secureInbound(localPeer: PeerId, connection: any, remotePeer?: PeerId): Promise { + public async secureInbound (localPeer: PeerId, connection: any, remotePeer?: PeerId): Promise { const wrappedConnection = Wrap( connection, { @@ -105,20 +105,20 @@ export class Noise implements INoiseConnection { lengthDecoder: uint16BEDecode, maxDataLength: NOISE_MSG_MAX_LENGTH_BYTES } - ); + ) const handshake = await this.performHandshake({ connection: wrappedConnection, isInitiator: false, localPeer, remotePeer - }); - const conn = await this.createSecureConnection(wrappedConnection, handshake); + }) + const conn = await this.createSecureConnection(wrappedConnection, handshake) return { conn, remoteEarlyData: handshake.remoteEarlyData, remotePeer: handshake.remotePeer - }; + } } /** @@ -126,105 +126,104 @@ export class Noise implements INoiseConnection { * If noise pipes disabled or remote peer static key is unknown, use XX. * @param params */ - private async performHandshake(params: HandshakeParams): Promise { - const payload = await getPayload(params.localPeer, this.staticKeys.publicKey, this.earlyData); - let tryIK = this.useNoisePipes; - if(params.isInitiator && KeyCache.load(params.remotePeer) === null) { - //if we are initiator and remote static key is unknown, don't try IK - tryIK = false; + private async performHandshake (params: HandshakeParams): Promise { + const payload = await getPayload(params.localPeer, this.staticKeys.publicKey, this.earlyData) + let tryIK = this.useNoisePipes + if (params.isInitiator && KeyCache.load(params.remotePeer) === null) { + // if we are initiator and remote static key is unknown, don't try IK + tryIK = false } // Try IK if acting as responder or initiator that has remote's static key. if (tryIK) { // Try IK first - const { remotePeer, connection, isInitiator } = params; + const { remotePeer, connection, isInitiator } = params const ikHandshake = new IKHandshake( isInitiator, payload, this.prologue, this.staticKeys, connection, - //safe to cast as we did checks + // safe to cast as we did checks KeyCache.load(params.remotePeer) || Buffer.alloc(32), - remotePeer as PeerId, - ); + remotePeer as PeerId + ) try { - return await this.performIKHandshake(ikHandshake); + return await this.performIKHandshake(ikHandshake) } catch (e) { // IK failed, go to XX fallback - let ephemeralKeys; + let ephemeralKeys if (params.isInitiator) { - ephemeralKeys = ikHandshake.getLocalEphemeralKeys(); + ephemeralKeys = ikHandshake.getLocalEphemeralKeys() } - return await this.performXXFallbackHandshake(params, payload, e.initialMsg, ephemeralKeys); + return await this.performXXFallbackHandshake(params, payload, e.initialMsg, ephemeralKeys) } } else { // run XX handshake - return await this.performXXHandshake(params, payload); + return await this.performXXHandshake(params, payload) } } - private async performXXFallbackHandshake( + private async performXXFallbackHandshake ( params: HandshakeParams, payload: bytes, initialMsg: bytes, - ephemeralKeys?: KeyPair, + ephemeralKeys?: KeyPair ): Promise { - const { isInitiator, remotePeer, connection } = params; + const { isInitiator, remotePeer, connection } = params const handshake = - new XXFallbackHandshake(isInitiator, payload, this.prologue, this.staticKeys, connection, initialMsg, remotePeer, ephemeralKeys); + new XXFallbackHandshake(isInitiator, payload, this.prologue, this.staticKeys, connection, initialMsg, remotePeer, ephemeralKeys) try { - await handshake.propose(); - await handshake.exchange(); - await handshake.finish(); + await handshake.propose() + await handshake.exchange() + await handshake.finish() } catch (e) { - logger(e); - throw new Error(`Error occurred during XX Fallback handshake: ${e.message}`); + logger(e) + throw new Error(`Error occurred during XX Fallback handshake: ${e.message}`) } - return handshake; + return handshake } - private async performXXHandshake( + private async performXXHandshake ( params: HandshakeParams, - payload: bytes, + payload: bytes ): Promise { - const { isInitiator, remotePeer, connection } = params; - const handshake = new XXHandshake(isInitiator, payload, this.prologue, this.staticKeys, connection, remotePeer); + const { isInitiator, remotePeer, connection } = params + const handshake = new XXHandshake(isInitiator, payload, this.prologue, this.staticKeys, connection, remotePeer) try { - await handshake.propose(); - await handshake.exchange(); - await handshake.finish(); + await handshake.propose() + await handshake.exchange() + await handshake.finish() if (this.useNoisePipes && handshake.remotePeer) { - KeyCache.store(handshake.remotePeer, handshake.getRemoteStaticKey()); + KeyCache.store(handshake.remotePeer, handshake.getRemoteStaticKey()) } } catch (e) { - throw new Error(`Error occurred during XX handshake: ${e.message}`); + throw new Error(`Error occurred during XX handshake: ${e.message}`) } - return handshake; + return handshake } - private async performIKHandshake( - handshake: IKHandshake, + private async performIKHandshake ( + handshake: IKHandshake ): Promise { + await handshake.stage0() + await handshake.stage1() - await handshake.stage0(); - await handshake.stage1(); - - return handshake; + return handshake } - private async createSecureConnection( + private async createSecureConnection ( connection: WrappedConnection, - handshake: IHandshake, + handshake: IHandshake ): Promise { // Create encryption box/unbox wrapper - const [secure, user] = DuplexPair(); - const network = connection.unwrap(); + const [secure, user] = DuplexPair() + const network = connection.unwrap() await pipe( secure, // write to wrapper @@ -232,14 +231,12 @@ export class Noise implements INoiseConnection { encryptStream(handshake), // data is encrypted encode({ lengthEncoder: uint16BEEncode }), // prefix with message length network, // send to the remote peer - decode({ lengthDecoder: uint16BEDecode}), // read message length prefix + decode({ lengthDecoder: uint16BEDecode }), // read message length prefix ensureBuffer, // ensure any type of data is converted to buffer decryptStream(handshake), // decrypt the incoming data secure // pipe to the wrapper - ); + ) - return user; + return user } - - } diff --git a/src/proto/payload.js b/src/proto/payload.js index ff28de5..0da7b5e 100644 --- a/src/proto/payload.js +++ b/src/proto/payload.js @@ -1,33 +1,25 @@ -/*eslint-disable block-scoped-var, id-length, no-control-regex, no-magic-numbers, no-prototype-builtins, no-redeclare, no-shadow, no-var, sort-vars*/ -(function(global, factory) { /* global define, require, module */ +/* eslint-disable block-scoped-var, id-length, no-control-regex, no-magic-numbers, no-prototype-builtins, no-redeclare, no-shadow, no-var, sort-vars */ +(function (global, factory) { /* global define, require, module */ + /* AMD */ if (typeof define === 'function' && define.amd) { define(['protobufjs/minimal'], factory) } - /* AMD */ if (typeof define === 'function' && define.amd) - define(["protobufjs/minimal"], factory); + /* CommonJS */ else if (typeof require === 'function' && typeof module === 'object' && module && module.exports) { module.exports = factory(require('protobufjs/minimal')) } +})(this, function ($protobuf) { + // Common aliases + var $Reader = $protobuf.Reader; var $Writer = $protobuf.Writer; var $util = $protobuf.util - /* CommonJS */ else if (typeof require === 'function' && typeof module === 'object' && module && module.exports) - module.exports = factory(require("protobufjs/minimal")); + // Exported root namespace + var $root = $protobuf.roots.default || ($protobuf.roots.default = {}) -})(this, function($protobuf) { - "use strict"; - - // Common aliases - var $Reader = $protobuf.Reader, $Writer = $protobuf.Writer, $util = $protobuf.util; - - // Exported root namespace - var $root = $protobuf.roots["default"] || ($protobuf.roots["default"] = {}); - - $root.pb = (function() { - - /** + $root.pb = (function () { + /** * Namespace pb. * @exports pb * @namespace */ - var pb = {}; - - pb.NoiseHandshakePayload = (function() { - - /** + var pb = {} + + pb.NoiseHandshakePayload = (function () { + /** * Properties of a NoiseHandshakePayload. * @memberof pb * @interface INoiseHandshakePayload @@ -35,8 +27,8 @@ * @property {Uint8Array|null} [identitySig] NoiseHandshakePayload identitySig * @property {Uint8Array|null} [data] NoiseHandshakePayload data */ - - /** + + /** * Constructs a new NoiseHandshakePayload. * @memberof pb * @classdesc Represents a NoiseHandshakePayload. @@ -44,38 +36,39 @@ * @constructor * @param {pb.INoiseHandshakePayload=} [properties] Properties to set */ - function NoiseHandshakePayload(properties) { - if (properties) - for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) - if (properties[keys[i]] != null) - this[keys[i]] = properties[keys[i]]; - } - - /** + function NoiseHandshakePayload (properties) { + if (properties) { + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) { + if (properties[keys[i]] != null) { this[keys[i]] = properties[keys[i]] } + } + } + } + + /** * NoiseHandshakePayload identityKey. * @member {Uint8Array} identityKey * @memberof pb.NoiseHandshakePayload * @instance */ - NoiseHandshakePayload.prototype.identityKey = $util.newBuffer([]); - - /** + NoiseHandshakePayload.prototype.identityKey = $util.newBuffer([]) + + /** * NoiseHandshakePayload identitySig. * @member {Uint8Array} identitySig * @memberof pb.NoiseHandshakePayload * @instance */ - NoiseHandshakePayload.prototype.identitySig = $util.newBuffer([]); - - /** + NoiseHandshakePayload.prototype.identitySig = $util.newBuffer([]) + + /** * NoiseHandshakePayload data. * @member {Uint8Array} data * @memberof pb.NoiseHandshakePayload * @instance */ - NoiseHandshakePayload.prototype.data = $util.newBuffer([]); - - /** + NoiseHandshakePayload.prototype.data = $util.newBuffer([]) + + /** * Creates a new NoiseHandshakePayload instance using the specified properties. * @function create * @memberof pb.NoiseHandshakePayload @@ -83,11 +76,11 @@ * @param {pb.INoiseHandshakePayload=} [properties] Properties to set * @returns {pb.NoiseHandshakePayload} NoiseHandshakePayload instance */ - NoiseHandshakePayload.create = function create(properties) { - return new NoiseHandshakePayload(properties); - }; - - /** + NoiseHandshakePayload.create = function create (properties) { + return new NoiseHandshakePayload(properties) + } + + /** * Encodes the specified NoiseHandshakePayload message. Does not implicitly {@link pb.NoiseHandshakePayload.verify|verify} messages. * @function encode * @memberof pb.NoiseHandshakePayload @@ -96,19 +89,15 @@ * @param {$protobuf.Writer} [writer] Writer to encode to * @returns {$protobuf.Writer} Writer */ - NoiseHandshakePayload.encode = function encode(message, writer) { - if (!writer) - writer = $Writer.create(); - if (message.identityKey != null && message.hasOwnProperty("identityKey")) - writer.uint32(/* id 1, wireType 2 =*/10).bytes(message.identityKey); - if (message.identitySig != null && message.hasOwnProperty("identitySig")) - writer.uint32(/* id 2, wireType 2 =*/18).bytes(message.identitySig); - if (message.data != null && message.hasOwnProperty("data")) - writer.uint32(/* id 3, wireType 2 =*/26).bytes(message.data); - return writer; - }; - - /** + NoiseHandshakePayload.encode = function encode (message, writer) { + if (!writer) { writer = $Writer.create() } + if (message.identityKey != null && message.hasOwnProperty('identityKey')) { writer.uint32(/* id 1, wireType 2 = */10).bytes(message.identityKey) } + if (message.identitySig != null && message.hasOwnProperty('identitySig')) { writer.uint32(/* id 2, wireType 2 = */18).bytes(message.identitySig) } + if (message.data != null && message.hasOwnProperty('data')) { writer.uint32(/* id 3, wireType 2 = */26).bytes(message.data) } + return writer + } + + /** * Encodes the specified NoiseHandshakePayload message, length delimited. Does not implicitly {@link pb.NoiseHandshakePayload.verify|verify} messages. * @function encodeDelimited * @memberof pb.NoiseHandshakePayload @@ -117,11 +106,11 @@ * @param {$protobuf.Writer} [writer] Writer to encode to * @returns {$protobuf.Writer} Writer */ - NoiseHandshakePayload.encodeDelimited = function encodeDelimited(message, writer) { - return this.encode(message, writer).ldelim(); - }; - - /** + NoiseHandshakePayload.encodeDelimited = function encodeDelimited (message, writer) { + return this.encode(message, writer).ldelim() + } + + /** * Decodes a NoiseHandshakePayload message from the specified reader or buffer. * @function decode * @memberof pb.NoiseHandshakePayload @@ -132,31 +121,30 @@ * @throws {Error} If the payload is not a reader or valid buffer * @throws {$protobuf.util.ProtocolError} If required fields are missing */ - NoiseHandshakePayload.decode = function decode(reader, length) { - if (!(reader instanceof $Reader)) - reader = $Reader.create(reader); - var end = length === undefined ? reader.len : reader.pos + length, message = new $root.pb.NoiseHandshakePayload(); - while (reader.pos < end) { - var tag = reader.uint32(); - switch (tag >>> 3) { - case 1: - message.identityKey = reader.bytes(); - break; - case 2: - message.identitySig = reader.bytes(); - break; - case 3: - message.data = reader.bytes(); - break; - default: - reader.skipType(tag & 7); - break; - } - } - return message; - }; - - /** + NoiseHandshakePayload.decode = function decode (reader, length) { + if (!(reader instanceof $Reader)) { reader = $Reader.create(reader) } + var end = length === undefined ? reader.len : reader.pos + length; var message = new $root.pb.NoiseHandshakePayload() + while (reader.pos < end) { + var tag = reader.uint32() + switch (tag >>> 3) { + case 1: + message.identityKey = reader.bytes() + break + case 2: + message.identitySig = reader.bytes() + break + case 3: + message.data = reader.bytes() + break + default: + reader.skipType(tag & 7) + break + } + } + return message + } + + /** * Decodes a NoiseHandshakePayload message from the specified reader or buffer, length delimited. * @function decodeDelimited * @memberof pb.NoiseHandshakePayload @@ -166,13 +154,12 @@ * @throws {Error} If the payload is not a reader or valid buffer * @throws {$protobuf.util.ProtocolError} If required fields are missing */ - NoiseHandshakePayload.decodeDelimited = function decodeDelimited(reader) { - if (!(reader instanceof $Reader)) - reader = new $Reader(reader); - return this.decode(reader, reader.uint32()); - }; - - /** + NoiseHandshakePayload.decodeDelimited = function decodeDelimited (reader) { + if (!(reader instanceof $Reader)) { reader = new $Reader(reader) } + return this.decode(reader, reader.uint32()) + } + + /** * Verifies a NoiseHandshakePayload message. * @function verify * @memberof pb.NoiseHandshakePayload @@ -180,22 +167,21 @@ * @param {Object.} message Plain object to verify * @returns {string|null} `null` if valid, otherwise the reason why it is not */ - NoiseHandshakePayload.verify = function verify(message) { - if (typeof message !== "object" || message === null) - return "object expected"; - if (message.identityKey != null && message.hasOwnProperty("identityKey")) - if (!(message.identityKey && typeof message.identityKey.length === "number" || $util.isString(message.identityKey))) - return "identityKey: buffer expected"; - if (message.identitySig != null && message.hasOwnProperty("identitySig")) - if (!(message.identitySig && typeof message.identitySig.length === "number" || $util.isString(message.identitySig))) - return "identitySig: buffer expected"; - if (message.data != null && message.hasOwnProperty("data")) - if (!(message.data && typeof message.data.length === "number" || $util.isString(message.data))) - return "data: buffer expected"; - return null; - }; - - /** + NoiseHandshakePayload.verify = function verify (message) { + if (typeof message !== 'object' || message === null) { return 'object expected' } + if (message.identityKey != null && message.hasOwnProperty('identityKey')) { + if (!(message.identityKey && typeof message.identityKey.length === 'number' || $util.isString(message.identityKey))) { return 'identityKey: buffer expected' } + } + if (message.identitySig != null && message.hasOwnProperty('identitySig')) { + if (!(message.identitySig && typeof message.identitySig.length === 'number' || $util.isString(message.identitySig))) { return 'identitySig: buffer expected' } + } + if (message.data != null && message.hasOwnProperty('data')) { + if (!(message.data && typeof message.data.length === 'number' || $util.isString(message.data))) { return 'data: buffer expected' } + } + return null + } + + /** * Creates a NoiseHandshakePayload message from a plain object. Also converts values to their respective internal types. * @function fromObject * @memberof pb.NoiseHandshakePayload @@ -203,29 +189,22 @@ * @param {Object.} object Plain object * @returns {pb.NoiseHandshakePayload} NoiseHandshakePayload */ - NoiseHandshakePayload.fromObject = function fromObject(object) { - if (object instanceof $root.pb.NoiseHandshakePayload) - return object; - var message = new $root.pb.NoiseHandshakePayload(); - if (object.identityKey != null) - if (typeof object.identityKey === "string") - $util.base64.decode(object.identityKey, message.identityKey = $util.newBuffer($util.base64.length(object.identityKey)), 0); - else if (object.identityKey.length) - message.identityKey = object.identityKey; - if (object.identitySig != null) - if (typeof object.identitySig === "string") - $util.base64.decode(object.identitySig, message.identitySig = $util.newBuffer($util.base64.length(object.identitySig)), 0); - else if (object.identitySig.length) - message.identitySig = object.identitySig; - if (object.data != null) - if (typeof object.data === "string") - $util.base64.decode(object.data, message.data = $util.newBuffer($util.base64.length(object.data)), 0); - else if (object.data.length) - message.data = object.data; - return message; - }; - - /** + NoiseHandshakePayload.fromObject = function fromObject (object) { + if (object instanceof $root.pb.NoiseHandshakePayload) { return object } + var message = new $root.pb.NoiseHandshakePayload() + if (object.identityKey != null) { + if (typeof object.identityKey === 'string') { $util.base64.decode(object.identityKey, message.identityKey = $util.newBuffer($util.base64.length(object.identityKey)), 0) } else if (object.identityKey.length) { message.identityKey = object.identityKey } + } + if (object.identitySig != null) { + if (typeof object.identitySig === 'string') { $util.base64.decode(object.identitySig, message.identitySig = $util.newBuffer($util.base64.length(object.identitySig)), 0) } else if (object.identitySig.length) { message.identitySig = object.identitySig } + } + if (object.data != null) { + if (typeof object.data === 'string') { $util.base64.decode(object.data, message.data = $util.newBuffer($util.base64.length(object.data)), 0) } else if (object.data.length) { message.data = object.data } + } + return message + } + + /** * Creates a plain object from a NoiseHandshakePayload message. Also converts values to other types if specified. * @function toObject * @memberof pb.NoiseHandshakePayload @@ -234,58 +213,45 @@ * @param {$protobuf.IConversionOptions} [options] Conversion options * @returns {Object.} Plain object */ - NoiseHandshakePayload.toObject = function toObject(message, options) { - if (!options) - options = {}; - var object = {}; - if (options.defaults) { - if (options.bytes === String) - object.identityKey = ""; - else { - object.identityKey = []; - if (options.bytes !== Array) - object.identityKey = $util.newBuffer(object.identityKey); - } - if (options.bytes === String) - object.identitySig = ""; - else { - object.identitySig = []; - if (options.bytes !== Array) - object.identitySig = $util.newBuffer(object.identitySig); - } - if (options.bytes === String) - object.data = ""; - else { - object.data = []; - if (options.bytes !== Array) - object.data = $util.newBuffer(object.data); - } - } - if (message.identityKey != null && message.hasOwnProperty("identityKey")) - object.identityKey = options.bytes === String ? $util.base64.encode(message.identityKey, 0, message.identityKey.length) : options.bytes === Array ? Array.prototype.slice.call(message.identityKey) : message.identityKey; - if (message.identitySig != null && message.hasOwnProperty("identitySig")) - object.identitySig = options.bytes === String ? $util.base64.encode(message.identitySig, 0, message.identitySig.length) : options.bytes === Array ? Array.prototype.slice.call(message.identitySig) : message.identitySig; - if (message.data != null && message.hasOwnProperty("data")) - object.data = options.bytes === String ? $util.base64.encode(message.data, 0, message.data.length) : options.bytes === Array ? Array.prototype.slice.call(message.data) : message.data; - return object; - }; - - /** + NoiseHandshakePayload.toObject = function toObject (message, options) { + if (!options) { options = {} } + var object = {} + if (options.defaults) { + if (options.bytes === String) { object.identityKey = '' } else { + object.identityKey = [] + if (options.bytes !== Array) { object.identityKey = $util.newBuffer(object.identityKey) } + } + if (options.bytes === String) { object.identitySig = '' } else { + object.identitySig = [] + if (options.bytes !== Array) { object.identitySig = $util.newBuffer(object.identitySig) } + } + if (options.bytes === String) { object.data = '' } else { + object.data = [] + if (options.bytes !== Array) { object.data = $util.newBuffer(object.data) } + } + } + if (message.identityKey != null && message.hasOwnProperty('identityKey')) { object.identityKey = options.bytes === String ? $util.base64.encode(message.identityKey, 0, message.identityKey.length) : options.bytes === Array ? Array.prototype.slice.call(message.identityKey) : message.identityKey } + if (message.identitySig != null && message.hasOwnProperty('identitySig')) { object.identitySig = options.bytes === String ? $util.base64.encode(message.identitySig, 0, message.identitySig.length) : options.bytes === Array ? Array.prototype.slice.call(message.identitySig) : message.identitySig } + if (message.data != null && message.hasOwnProperty('data')) { object.data = options.bytes === String ? $util.base64.encode(message.data, 0, message.data.length) : options.bytes === Array ? Array.prototype.slice.call(message.data) : message.data } + return object + } + + /** * Converts this NoiseHandshakePayload to JSON. * @function toJSON * @memberof pb.NoiseHandshakePayload * @instance * @returns {Object.} JSON object */ - NoiseHandshakePayload.prototype.toJSON = function toJSON() { - return this.constructor.toObject(this, $protobuf.util.toJSONOptions); - }; - - return NoiseHandshakePayload; - })(); - - return pb; - })(); + NoiseHandshakePayload.prototype.toJSON = function toJSON () { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions) + } - return $root; -}); + return NoiseHandshakePayload + })() + + return pb + })() + + return $root +}) diff --git a/src/utils.ts b/src/utils.ts index 345b24f..144b4b3 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,78 +1,76 @@ -import HKDF from 'bcrypto/lib/hkdf'; -import x25519 from 'bcrypto/lib/js/x25519'; -import SHA256 from 'bcrypto/lib/js/sha256'; -import {Buffer} from "buffer"; -import PeerId from "peer-id"; -import {keys} from 'libp2p-crypto'; -import {KeyPair} from "./@types/libp2p"; -import {bytes, bytes32} from "./@types/basic"; -import {Hkdf, INoisePayload} from "./@types/handshake"; -import {pb} from "./proto/payload"; +import HKDF from 'bcrypto/lib/hkdf' +import x25519 from 'bcrypto/lib/js/x25519' +import SHA256 from 'bcrypto/lib/js/sha256' +import { Buffer } from 'buffer' +import PeerId from 'peer-id' +import { keys } from 'libp2p-crypto' +import { KeyPair } from './@types/libp2p' +import { bytes, bytes32 } from './@types/basic' +import { Hkdf, INoisePayload } from './@types/handshake' +import { pb } from './proto/payload' -const NoiseHandshakePayloadProto = pb.NoiseHandshakePayload; +const NoiseHandshakePayloadProto = pb.NoiseHandshakePayload -export function generateKeypair(): KeyPair { - const privateKey = x25519.privateKeyGenerate(); - const publicKey = x25519.publicKeyCreate(privateKey); +export function generateKeypair (): KeyPair { + const privateKey = x25519.privateKeyGenerate() + const publicKey = x25519.publicKeyCreate(privateKey) return { publicKey, - privateKey, + privateKey } } -export async function getPayload( +export async function getPayload ( localPeer: PeerId, staticPublicKey: bytes, - earlyData?: bytes, + earlyData?: bytes ): Promise { - const signedPayload = await signPayload(localPeer, getHandshakePayload(staticPublicKey)); - const earlyDataPayload = earlyData || Buffer.alloc(0); + const signedPayload = await signPayload(localPeer, getHandshakePayload(staticPublicKey)) + const earlyDataPayload = earlyData || Buffer.alloc(0) return await createHandshakePayload( localPeer.marshalPubKey(), signedPayload, earlyDataPayload - ); + ) } -export async function createHandshakePayload( +export async function createHandshakePayload ( libp2pPublicKey: bytes, signedPayload: bytes, - earlyData?: bytes, + earlyData?: bytes ): Promise { - const payloadInit = NoiseHandshakePayloadProto.create({ identityKey: libp2pPublicKey, identitySig: signedPayload, - data: earlyData || null, - }); + data: earlyData || null + }) - return Buffer.from(NoiseHandshakePayloadProto.encode(payloadInit).finish()); + return Buffer.from(NoiseHandshakePayloadProto.encode(payloadInit).finish()) } - -export async function signPayload(peerId: PeerId, payload: bytes): Promise { - return peerId.privKey.sign(payload); +export async function signPayload (peerId: PeerId, payload: bytes): Promise { + return peerId.privKey.sign(payload) } -export async function getPeerIdFromPayload(payload: pb.INoiseHandshakePayload): Promise { - return await PeerId.createFromPubKey(Buffer.from(payload.identityKey as Uint8Array)); +export async function getPeerIdFromPayload (payload: pb.INoiseHandshakePayload): Promise { + return await PeerId.createFromPubKey(Buffer.from(payload.identityKey as Uint8Array)) } -export async function decodePayload(payload: bytes|Uint8Array): Promise { +export async function decodePayload (payload: bytes|Uint8Array): Promise { return NoiseHandshakePayloadProto.toObject( NoiseHandshakePayloadProto.decode(Buffer.from(payload)) - ) as INoisePayload; + ) as INoisePayload } -export function getHandshakePayload(publicKey: bytes): bytes { - return Buffer.concat([Buffer.from("noise-libp2p-static-key:"), publicKey]); +export function getHandshakePayload (publicKey: bytes): bytes { + return Buffer.concat([Buffer.from('noise-libp2p-static-key:'), publicKey]) } -async function isValidPeerId(peerId: bytes, publicKeyProtobuf: bytes) { - const generatedPeerId = await PeerId.createFromPubKey(publicKeyProtobuf); - return generatedPeerId.id.equals(peerId); +async function isValidPeerId (peerId: bytes, publicKeyProtobuf: bytes) { + const generatedPeerId = await PeerId.createFromPubKey(publicKeyProtobuf) + return generatedPeerId.id.equals(peerId) } /** @@ -82,36 +80,36 @@ async function isValidPeerId(peerId: bytes, publicKeyProtobuf: bytes) { * @param {PeerId} remotePeer - owner's libp2p peer ID * @returns {Promise} - peer ID of payload owner */ -export async function verifySignedPayload( +export async function verifySignedPayload ( noiseStaticKey: bytes, payload: pb.INoiseHandshakePayload, remotePeer: PeerId ): Promise { - const identityKey = Buffer.from(payload.identityKey as Uint8Array); + const identityKey = Buffer.from(payload.identityKey as Uint8Array) if (!(await isValidPeerId(remotePeer.id, identityKey))) { - throw new Error("Peer ID doesn't match libp2p public key."); + throw new Error("Peer ID doesn't match libp2p public key.") } - const generatedPayload = getHandshakePayload(noiseStaticKey); + const generatedPayload = getHandshakePayload(noiseStaticKey) // Unmarshaling from PublicKey protobuf - const publicKey = keys.unmarshalPublicKey(identityKey); + const publicKey = keys.unmarshalPublicKey(identityKey) if (!payload.identitySig || !publicKey.verify(generatedPayload, Buffer.from(payload.identitySig))) { - throw new Error("Static key doesn't match to peer that signed payload!"); + throw new Error("Static key doesn't match to peer that signed payload!") } - return PeerId.createFromPubKey(identityKey); + return PeerId.createFromPubKey(identityKey) } -export function getHkdf(ck: bytes32, ikm: bytes): Hkdf { - const info = Buffer.alloc(0); - const prk = HKDF.extract(SHA256, ikm, ck); - const okm = HKDF.expand(SHA256, prk, info, 96); +export function getHkdf (ck: bytes32, ikm: bytes): Hkdf { + const info = Buffer.alloc(0) + const prk = HKDF.extract(SHA256, ikm, ck) + const okm = HKDF.expand(SHA256, prk, info, 96) - const k1 = okm.slice(0, 32); - const k2 = okm.slice(32, 64); - const k3 = okm.slice(64, 96); + const k1 = okm.slice(0, 32) + const k2 = okm.slice(32, 64) + const k3 = okm.slice(64, 96) - return [k1, k2, k3]; + return [k1, k2, k3] } -export function isValidPublicKey(pk: bytes): boolean { - return x25519.publicKeyVerify(pk.slice(0, 32)); +export function isValidPublicKey (pk: bytes): boolean { + return x25519.publicKeyVerify(pk.slice(0, 32)) } diff --git a/test/fixtures/peer.ts b/test/fixtures/peer.ts index 585b37b..9b7b0fb 100644 --- a/test/fixtures/peer.ts +++ b/test/fixtures/peer.ts @@ -1,4 +1,4 @@ -import PeerId from 'peer-id'; +import PeerId from 'peer-id' // ed25519 keys const peers = [{ @@ -17,7 +17,7 @@ const peers = [{ id: '12D3KooWPCofiCjhdtezP4eMnqBjjutFZNHjV39F5LWNrCvaLnzT', privKey: 'CAESYLhUut01XPu+yIPbtZ3WnxOd26FYuTMRn/BbdFYsZE2KxueKRlo9yIAxmFReoNFUKztUU4G2aUiTbqDQaA6i0MDG54pGWj3IgDGYVF6g0VQrO1RTgbZpSJNuoNBoDqLQwA==', pubKey: 'CAESIMbnikZaPciAMZhUXqDRVCs7VFOBtmlIk26g0GgOotDA' -}]; +}] export async function createPeerIdsFromFixtures (length) { return Promise.all( @@ -26,11 +26,11 @@ export async function createPeerIdsFromFixtures (length) { } export async function createPeerIds (length) { - const peerIds: any[] = []; + const peerIds: any[] = [] for (let i = 0; i < length; i++) { - const id = await PeerId.create({ keyType: 'ed25519', bits: 256 }); - peerIds.push(id); + const id = await PeerId.create({ keyType: 'ed25519', bits: 256 }) + peerIds.push(id) } - return peerIds; + return peerIds } diff --git a/test/handshakes/ik.spec.ts b/test/handshakes/ik.spec.ts index 6d83df7..07b1b3a 100644 --- a/test/handshakes/ik.spec.ts +++ b/test/handshakes/ik.spec.ts @@ -1,67 +1,66 @@ -import {Buffer} from "buffer"; -import {IK} from "../../src/handshakes/ik"; -import {KeyPair} from "../../src/@types/libp2p"; -import {createHandshakePayload, generateKeypair, getHandshakePayload} from "../../src/utils"; -import {assert, expect} from "chai"; -import {generateEd25519Keys} from "../utils"; +import { Buffer } from 'buffer' +import { IK } from '../../src/handshakes/ik' +import { KeyPair } from '../../src/@types/libp2p' +import { createHandshakePayload, generateKeypair, getHandshakePayload } from '../../src/utils' +import { assert, expect } from 'chai' +import { generateEd25519Keys } from '../utils' -describe("IK handshake", () => { - const prologue = Buffer.alloc(0); +describe('IK handshake', () => { + const prologue = Buffer.alloc(0) - it("Test complete IK handshake", async () => { + it('Test complete IK handshake', async () => { try { - const ikI = new IK(); - const ikR = new IK(); + const ikI = new IK() + const ikR = new IK() // Generate static noise keys - const kpInitiator: KeyPair = await generateKeypair(); - const kpResponder: KeyPair = await generateKeypair(); + const kpInitiator: KeyPair = await generateKeypair() + const kpResponder: KeyPair = await generateKeypair() // Generate libp2p keys - const libp2pInitKeys = await generateEd25519Keys(); - const libp2pRespKeys = await generateEd25519Keys(); + const libp2pInitKeys = await generateEd25519Keys() + const libp2pRespKeys = await generateEd25519Keys() // Create sessions - const initiatorSession = await ikI.initSession(true, prologue, kpInitiator, kpResponder.publicKey); - const responderSession = await ikR.initSession(false, prologue, kpResponder, Buffer.alloc(32)); + const initiatorSession = await ikI.initSession(true, prologue, kpInitiator, kpResponder.publicKey) + const responderSession = await ikR.initSession(false, prologue, kpResponder, Buffer.alloc(32)) /* Stage 0 */ // initiator creates payload - const initSignedPayload = await libp2pInitKeys.sign(getHandshakePayload(kpInitiator.publicKey)); - const libp2pInitPrivKey = libp2pInitKeys.marshal().slice(0, 32); - const libp2pInitPubKey = libp2pInitKeys.marshal().slice(32, 64); - const payloadInitEnc = await createHandshakePayload(libp2pInitPubKey, initSignedPayload); + const initSignedPayload = await libp2pInitKeys.sign(getHandshakePayload(kpInitiator.publicKey)) + const libp2pInitPrivKey = libp2pInitKeys.marshal().slice(0, 32) + const libp2pInitPubKey = libp2pInitKeys.marshal().slice(32, 64) + const payloadInitEnc = await createHandshakePayload(libp2pInitPubKey, initSignedPayload) // initiator sends message - const message = Buffer.concat([Buffer.alloc(0), payloadInitEnc]); - const messageBuffer = ikI.sendMessage(initiatorSession, message); + const message = Buffer.concat([Buffer.alloc(0), payloadInitEnc]) + const messageBuffer = ikI.sendMessage(initiatorSession, message) - expect(messageBuffer.ne.length).not.equal(0); + expect(messageBuffer.ne.length).not.equal(0) // responder receives message - const plaintext = ikR.recvMessage(responderSession, messageBuffer); + const plaintext = ikR.recvMessage(responderSession, messageBuffer) /* Stage 1 */ // responder creates payload - const libp2pRespPrivKey = libp2pRespKeys.marshal().slice(0, 32); - const libp2pRespPubKey = libp2pRespKeys.marshal().slice(32, 64); - const respSignedPayload = await libp2pRespKeys.sign(getHandshakePayload(kpResponder.publicKey)); - const payloadRespEnc = await createHandshakePayload(libp2pRespPubKey, respSignedPayload); + const libp2pRespPrivKey = libp2pRespKeys.marshal().slice(0, 32) + const libp2pRespPubKey = libp2pRespKeys.marshal().slice(32, 64) + const respSignedPayload = await libp2pRespKeys.sign(getHandshakePayload(kpResponder.publicKey)) + const payloadRespEnc = await createHandshakePayload(libp2pRespPubKey, respSignedPayload) - const message1 = Buffer.concat([message, payloadRespEnc]); - const messageBuffer2 = ikR.sendMessage(responderSession, message1); + const message1 = Buffer.concat([message, payloadRespEnc]) + const messageBuffer2 = ikR.sendMessage(responderSession, message1) // initiator receives message - const plaintext2 = ikI.recvMessage(initiatorSession, messageBuffer2); - - assert(initiatorSession.cs1.k.equals(responderSession.cs1.k)); - assert(initiatorSession.cs2.k.equals(responderSession.cs2.k)); + const plaintext2 = ikI.recvMessage(initiatorSession, messageBuffer2) + assert(initiatorSession.cs1.k.equals(responderSession.cs1.k)) + assert(initiatorSession.cs2.k.equals(responderSession.cs2.k)) } catch (e) { - console.error(e); - return assert(false, e.message); + console.error(e) + return assert(false, e.message) } - }); -}); + }) +}) diff --git a/test/handshakes/xx.spec.ts b/test/handshakes/xx.spec.ts index ec771df..9b3836e 100644 --- a/test/handshakes/xx.spec.ts +++ b/test/handshakes/xx.spec.ts @@ -1,143 +1,143 @@ -import { expect, assert } from "chai"; -import { Buffer } from 'buffer'; +import { expect, assert } from 'chai' +import { Buffer } from 'buffer' -import { XX } from "../../src/handshakes/xx"; -import { KeyPair } from "../../src/@types/libp2p"; -import { generateEd25519Keys } from "../utils"; -import {createHandshakePayload, generateKeypair, getHandshakePayload, getHkdf} from "../../src/utils"; +import { XX } from '../../src/handshakes/xx' +import { KeyPair } from '../../src/@types/libp2p' +import { generateEd25519Keys } from '../utils' +import { createHandshakePayload, generateKeypair, getHandshakePayload, getHkdf } from '../../src/utils' -describe("XX Handshake", () => { - const prologue = Buffer.alloc(0); +describe('XX Handshake', () => { + const prologue = Buffer.alloc(0) - it("Test creating new XX session", async () => { + it('Test creating new XX session', async () => { try { - const xx = new XX(); + const xx = new XX() - const kpInitiator: KeyPair = await generateKeypair(); - const kpResponder: KeyPair = await generateKeypair(); + const kpInitiator: KeyPair = await generateKeypair() + const kpResponder: KeyPair = await generateKeypair() - const session = await xx.initSession(true, prologue, kpInitiator); + const session = await xx.initSession(true, prologue, kpInitiator) } catch (e) { - assert(false, e.message); + assert(false, e.message) } - }); + }) - it("Test get HKDF", async () => { - const ckBytes = Buffer.from('4e6f6973655f58585f32353531395f58436861436861506f6c795f53484132353600000000000000000000000000000000000000000000000000000000000000', 'hex'); - const ikm = Buffer.from('a3eae50ea37a47e8a7aa0c7cd8e16528670536dcd538cebfd724fb68ce44f1910ad898860666227d4e8dd50d22a9a64d1c0a6f47ace092510161e9e442953da3', 'hex'); - const ck = Buffer.alloc(32); - ckBytes.copy(ck); + it('Test get HKDF', async () => { + const ckBytes = Buffer.from('4e6f6973655f58585f32353531395f58436861436861506f6c795f53484132353600000000000000000000000000000000000000000000000000000000000000', 'hex') + const ikm = Buffer.from('a3eae50ea37a47e8a7aa0c7cd8e16528670536dcd538cebfd724fb68ce44f1910ad898860666227d4e8dd50d22a9a64d1c0a6f47ace092510161e9e442953da3', 'hex') + const ck = Buffer.alloc(32) + ckBytes.copy(ck) - const [k1, k2, k3] = getHkdf(ck, ikm); - expect(k1.toString('hex')).to.equal('cc5659adff12714982f806e2477a8d5ddd071def4c29bb38777b7e37046f6914'); - expect(k2.toString('hex')).to.equal('a16ada915e551ab623f38be674bb4ef15d428ae9d80688899c9ef9b62ef208fa'); - expect(k3.toString('hex')).to.equal('ff67bf9727e31b06efc203907e6786667d2c7a74ac412b4d31a80ba3fd766f68'); - }); + const [k1, k2, k3] = getHkdf(ck, ikm) + expect(k1.toString('hex')).to.equal('cc5659adff12714982f806e2477a8d5ddd071def4c29bb38777b7e37046f6914') + expect(k2.toString('hex')).to.equal('a16ada915e551ab623f38be674bb4ef15d428ae9d80688899c9ef9b62ef208fa') + expect(k3.toString('hex')).to.equal('ff67bf9727e31b06efc203907e6786667d2c7a74ac412b4d31a80ba3fd766f68') + }) - async function doHandshake(xx) { - const kpInit = await generateKeypair(); - const kpResp = await generateKeypair(); + async function doHandshake (xx) { + const kpInit = await generateKeypair() + const kpResp = await generateKeypair() // initiator setup - const libp2pInitKeys = await generateEd25519Keys(); - const initSignedPayload = await libp2pInitKeys.sign(getHandshakePayload(kpInit.publicKey)); + const libp2pInitKeys = await generateEd25519Keys() + const initSignedPayload = await libp2pInitKeys.sign(getHandshakePayload(kpInit.publicKey)) // responder setup - const libp2pRespKeys = await generateEd25519Keys(); - const respSignedPayload = await libp2pRespKeys.sign(getHandshakePayload(kpResp.publicKey)); + const libp2pRespKeys = await generateEd25519Keys() + const respSignedPayload = await libp2pRespKeys.sign(getHandshakePayload(kpResp.publicKey)) // initiator: new XX noise session - const nsInit = xx.initSession(true, prologue, kpInit); + const nsInit = xx.initSession(true, prologue, kpInit) // responder: new XX noise session - const nsResp = xx.initSession(false, prologue, kpResp); + const nsResp = xx.initSession(false, prologue, kpResp) /* STAGE 0 */ // initiator creates payload - const libp2pInitPrivKey = libp2pInitKeys.marshal().slice(0, 32); - const libp2pInitPubKey = libp2pInitKeys.marshal().slice(32, 64); + const libp2pInitPrivKey = libp2pInitKeys.marshal().slice(0, 32) + const libp2pInitPubKey = libp2pInitKeys.marshal().slice(32, 64) - const payloadInitEnc = await createHandshakePayload(libp2pInitPubKey, initSignedPayload); + const payloadInitEnc = await createHandshakePayload(libp2pInitPubKey, initSignedPayload) // initiator sends message - const message = Buffer.concat([Buffer.alloc(0), payloadInitEnc]); - const messageBuffer = xx.sendMessage(nsInit, message); + const message = Buffer.concat([Buffer.alloc(0), payloadInitEnc]) + const messageBuffer = xx.sendMessage(nsInit, message) - expect(messageBuffer.ne.length).not.equal(0); + expect(messageBuffer.ne.length).not.equal(0) // responder receives message - xx.recvMessage(nsResp, messageBuffer); + xx.recvMessage(nsResp, messageBuffer) /* STAGE 1 */ // responder creates payload - const libp2pRespPrivKey = libp2pRespKeys.marshal().slice(0, 32); - const libp2pRespPubKey = libp2pRespKeys.marshal().slice(32, 64); - const payloadRespEnc = await createHandshakePayload(libp2pRespPubKey, respSignedPayload); + const libp2pRespPrivKey = libp2pRespKeys.marshal().slice(0, 32) + const libp2pRespPubKey = libp2pRespKeys.marshal().slice(32, 64) + const payloadRespEnc = await createHandshakePayload(libp2pRespPubKey, respSignedPayload) - const message1 = Buffer.concat([message, payloadRespEnc]); - const messageBuffer2 = xx.sendMessage(nsResp, message1); + const message1 = Buffer.concat([message, payloadRespEnc]) + const messageBuffer2 = xx.sendMessage(nsResp, message1) - expect(messageBuffer2.ne.length).not.equal(0); - expect(messageBuffer2.ns.length).not.equal(0); + expect(messageBuffer2.ne.length).not.equal(0) + expect(messageBuffer2.ns.length).not.equal(0) // initiator receive payload - xx.recvMessage(nsInit, messageBuffer2); + xx.recvMessage(nsInit, messageBuffer2) /* STAGE 2 */ // initiator send message - const messageBuffer3 = xx.sendMessage(nsInit, Buffer.alloc(0)); + const messageBuffer3 = xx.sendMessage(nsInit, Buffer.alloc(0)) // responder receive message - xx.recvMessage(nsResp, messageBuffer3); + xx.recvMessage(nsResp, messageBuffer3) - assert(nsInit.cs1.k.equals(nsResp.cs1.k)); - assert(nsInit.cs2.k.equals(nsResp.cs2.k)); + assert(nsInit.cs1.k.equals(nsResp.cs1.k)) + assert(nsInit.cs2.k.equals(nsResp.cs2.k)) - return { nsInit, nsResp }; + return { nsInit, nsResp } } - it("Test handshake", async () => { + it('Test handshake', async () => { try { - const xx = new XX(); - await doHandshake(xx); + const xx = new XX() + await doHandshake(xx) } catch (e) { - assert(false, e.message); + assert(false, e.message) } - }); + }) - it("Test symmetric encrypt and decrypt", async () => { + it('Test symmetric encrypt and decrypt', async () => { try { - const xx = new XX(); - const { nsInit, nsResp } = await doHandshake(xx); - const ad = Buffer.from("authenticated"); - const message = Buffer.from("HelloCrypto"); + const xx = new XX() + const { nsInit, nsResp } = await doHandshake(xx) + const ad = Buffer.from('authenticated') + const message = Buffer.from('HelloCrypto') - const ciphertext = xx.encryptWithAd(nsInit.cs1, ad, message); - assert(!Buffer.from("HelloCrypto").equals(ciphertext), "Encrypted message should not be same as plaintext."); - const {plaintext: decrypted, valid} = xx.decryptWithAd(nsResp.cs1, ad, ciphertext); + const ciphertext = xx.encryptWithAd(nsInit.cs1, ad, message) + assert(!Buffer.from('HelloCrypto').equals(ciphertext), 'Encrypted message should not be same as plaintext.') + const { plaintext: decrypted, valid } = xx.decryptWithAd(nsResp.cs1, ad, ciphertext) - assert(Buffer.from("HelloCrypto").equals(decrypted), "Decrypted text not equal to original message."); - assert(valid); + assert(Buffer.from('HelloCrypto').equals(decrypted), 'Decrypted text not equal to original message.') + assert(valid) } catch (e) { - assert(false, e.message); + assert(false, e.message) } - }); + }) - it("Test multiple messages encryption and decryption", async () => { - const xx = new XX(); - const { nsInit, nsResp } = await doHandshake(xx); - const ad = Buffer.from("authenticated"); - const message = Buffer.from("ethereum1"); + it('Test multiple messages encryption and decryption', async () => { + const xx = new XX() + const { nsInit, nsResp } = await doHandshake(xx) + const ad = Buffer.from('authenticated') + const message = Buffer.from('ethereum1') - const encrypted = xx.encryptWithAd(nsInit.cs1, ad, message); - const {plaintext: decrypted} = xx.decryptWithAd(nsResp.cs1, ad, encrypted); - assert.equal("ethereum1", decrypted.toString("utf8"), "Decrypted text not equal to original message."); + const encrypted = xx.encryptWithAd(nsInit.cs1, ad, message) + const { plaintext: decrypted } = xx.decryptWithAd(nsResp.cs1, ad, encrypted) + assert.equal('ethereum1', decrypted.toString('utf8'), 'Decrypted text not equal to original message.') - const message2 = Buffer.from("ethereum2"); - const encrypted2 = xx.encryptWithAd(nsInit.cs1, ad, message2); - const {plaintext: decrypted2} = xx.decryptWithAd(nsResp.cs1, ad, encrypted2); - assert.equal("ethereum2", decrypted2.toString("utf-8"), "Decrypted text not equal to original message."); - }); -}); + const message2 = Buffer.from('ethereum2') + const encrypted2 = xx.encryptWithAd(nsInit.cs1, ad, message2) + const { plaintext: decrypted2 } = xx.decryptWithAd(nsResp.cs1, ad, encrypted2) + assert.equal('ethereum2', decrypted2.toString('utf-8'), 'Decrypted text not equal to original message.') + }) +}) diff --git a/test/ik-handshake.spec.ts b/test/ik-handshake.spec.ts index cf304b8..0a8b43f 100644 --- a/test/ik-handshake.spec.ts +++ b/test/ik-handshake.spec.ts @@ -1,80 +1,80 @@ -import Wrap from "it-pb-rpc"; -import Duplex from 'it-pair/duplex'; -import {Buffer} from "buffer"; -import {assert, expect} from "chai"; +import Wrap from 'it-pb-rpc' +import Duplex from 'it-pair/duplex' +import { Buffer } from 'buffer' +import { assert, expect } from 'chai' -import {createPeerIdsFromFixtures} from "./fixtures/peer"; -import {generateKeypair, getPayload} from "../src/utils"; -import {IKHandshake} from "../src/handshake-ik"; +import { createPeerIdsFromFixtures } from './fixtures/peer' +import { generateKeypair, getPayload } from '../src/utils' +import { IKHandshake } from '../src/handshake-ik' -describe("IK Handshake", () => { - let peerA, peerB, fakePeer; +describe('IK Handshake', () => { + let peerA, peerB, fakePeer before(async () => { - [peerA, peerB, fakePeer] = await createPeerIdsFromFixtures(3); - }); + [peerA, peerB, fakePeer] = await createPeerIdsFromFixtures(3) + }) - it("should finish both stages as initiator and responder", async() => { + it('should finish both stages as initiator and responder', async () => { try { - const duplex = Duplex(); - const connectionFrom = Wrap(duplex[0]); - const connectionTo = Wrap(duplex[1]); + const duplex = Duplex() + const connectionFrom = Wrap(duplex[0]) + const connectionTo = Wrap(duplex[1]) - const prologue = Buffer.alloc(0); - const staticKeysInitiator = generateKeypair(); - const staticKeysResponder = generateKeypair(); + const prologue = Buffer.alloc(0) + const staticKeysInitiator = generateKeypair() + const staticKeysResponder = generateKeypair() - const initPayload = await getPayload(peerA, staticKeysInitiator.publicKey); - const handshakeInit = new IKHandshake(true, initPayload, prologue, staticKeysInitiator, connectionFrom, staticKeysResponder.publicKey, peerB); + const initPayload = await getPayload(peerA, staticKeysInitiator.publicKey) + const handshakeInit = new IKHandshake(true, initPayload, prologue, staticKeysInitiator, connectionFrom, staticKeysResponder.publicKey, peerB) - const respPayload = await getPayload(peerB, staticKeysResponder.publicKey); - const handshakeResp = new IKHandshake(false, respPayload, prologue, staticKeysResponder, connectionTo, staticKeysInitiator.publicKey); + const respPayload = await getPayload(peerB, staticKeysResponder.publicKey) + const handshakeResp = new IKHandshake(false, respPayload, prologue, staticKeysResponder, connectionTo, staticKeysInitiator.publicKey) - await handshakeInit.stage0(); - await handshakeResp.stage0(); + await handshakeInit.stage0() + await handshakeResp.stage0() - await handshakeResp.stage1(); - await handshakeInit.stage1(); + await handshakeResp.stage1() + await handshakeInit.stage1() // Test shared key if (handshakeInit.session.cs1 && handshakeResp.session.cs1 && handshakeInit.session.cs2 && handshakeResp.session.cs2) { - assert(handshakeInit.session.cs1.k.equals(handshakeResp.session.cs1.k)); - assert(handshakeInit.session.cs2.k.equals(handshakeResp.session.cs2.k)); + assert(handshakeInit.session.cs1.k.equals(handshakeResp.session.cs1.k)) + assert(handshakeInit.session.cs2.k.equals(handshakeResp.session.cs2.k)) } else { - assert(false); + assert(false) } // Test encryption and decryption - const encrypted = handshakeInit.encrypt(Buffer.from("encryptthis"), handshakeInit.session); - const {plaintext: decrypted} = handshakeResp.decrypt(encrypted, handshakeResp.session); - assert(decrypted.equals(Buffer.from("encryptthis"))); + const encrypted = handshakeInit.encrypt(Buffer.from('encryptthis'), handshakeInit.session) + const { plaintext: decrypted } = handshakeResp.decrypt(encrypted, handshakeResp.session) + assert(decrypted.equals(Buffer.from('encryptthis'))) } catch (e) { - console.error(e); - assert(false, e.message); + console.error(e) + assert(false, e.message) } - }); + }) - it("should throw error if responder's static key changed", async() => { + it("should throw error if responder's static key changed", async () => { try { - const duplex = Duplex(); - const connectionFrom = Wrap(duplex[0]); - const connectionTo = Wrap(duplex[1]); + const duplex = Duplex() + const connectionFrom = Wrap(duplex[0]) + const connectionTo = Wrap(duplex[1]) - const prologue = Buffer.alloc(0); - const staticKeysInitiator = generateKeypair(); - const staticKeysResponder = generateKeypair(); - const oldScammyKeys = generateKeypair(); + const prologue = Buffer.alloc(0) + const staticKeysInitiator = generateKeypair() + const staticKeysResponder = generateKeypair() + const oldScammyKeys = generateKeypair() - const initPayload = await getPayload(peerA, staticKeysInitiator.publicKey); - const handshakeInit = new IKHandshake(true, initPayload, prologue, staticKeysInitiator, connectionFrom, oldScammyKeys.publicKey, peerB); + const initPayload = await getPayload(peerA, staticKeysInitiator.publicKey) + const handshakeInit = new IKHandshake(true, initPayload, prologue, staticKeysInitiator, connectionFrom, oldScammyKeys.publicKey, peerB) - const respPayload = await getPayload(peerB, staticKeysResponder.publicKey); - const handshakeResp = new IKHandshake(false, respPayload, prologue, staticKeysResponder, connectionTo, staticKeysInitiator.publicKey); + const respPayload = await getPayload(peerB, staticKeysResponder.publicKey) + const handshakeResp = new IKHandshake(false, respPayload, prologue, staticKeysResponder, connectionTo, staticKeysInitiator.publicKey) - await handshakeInit.stage0(); - await handshakeResp.stage0(); + await handshakeInit.stage0() + await handshakeResp.stage0() } catch (e) { - expect(e.message).to.include("Error occurred while verifying initiator's signed payload"); + expect(e.message).to.include("Error occurred while verifying initiator's signed payload") } - }); -}); + }) +}) diff --git a/test/index.spec.ts b/test/index.spec.ts index f1287cf..7022064 100644 --- a/test/index.spec.ts +++ b/test/index.spec.ts @@ -1,11 +1,11 @@ -import { expect } from "chai"; -import { Noise } from "../src"; +import { expect } from 'chai' +import { Noise } from '../src' -describe("Index", () => { - it("should expose class with tag and required functions", () => { - const noise = new Noise(); - expect(noise.protocol).to.equal('/noise'); - expect(typeof(noise.secureInbound)).to.equal('function'); - expect(typeof(noise.secureOutbound)).to.equal('function'); +describe('Index', () => { + it('should expose class with tag and required functions', () => { + const noise = new Noise() + expect(noise.protocol).to.equal('/noise') + expect(typeof (noise.secureInbound)).to.equal('function') + expect(typeof (noise.secureOutbound)).to.equal('function') }) -}); +}) diff --git a/test/keycache.spec.ts b/test/keycache.spec.ts index f9b9cd0..487a446 100644 --- a/test/keycache.spec.ts +++ b/test/keycache.spec.ts @@ -1,34 +1,34 @@ -import { expect, assert } from "chai"; -import { KeyCache } from "../src/keycache"; -import {createPeerIds, createPeerIdsFromFixtures} from "./fixtures/peer"; +import { expect, assert } from 'chai' +import { KeyCache } from '../src/keycache' +import { createPeerIds, createPeerIdsFromFixtures } from './fixtures/peer' -describe("KeyCache", () => { - let peerA, peerB; +describe('KeyCache', () => { + let peerA, peerB before(async () => { - [peerA, peerB] = await createPeerIdsFromFixtures(2); - }); + [peerA, peerB] = await createPeerIdsFromFixtures(2) + }) - it("should store and load same key successfully", async() => { + it('should store and load same key successfully', async () => { try { - const key = Buffer.from("this is id 007"); - await KeyCache.store(peerA, key); - const result = await KeyCache.load(peerA); - assert(result.equals(key), "Stored and loaded key are not the same"); + const key = Buffer.from('this is id 007') + await KeyCache.store(peerA, key) + const result = await KeyCache.load(peerA) + assert(result.equals(key), 'Stored and loaded key are not the same') } catch (e) { - console.error(e); + console.error(e) assert(false, `Test failed - ${e.message}`) } - }); + }) - it("should return undefined if key not found", async() => { + it('should return undefined if key not found', async () => { try { - const [newPeer] = await createPeerIds(1); - const result = await KeyCache.load(newPeer); - assert(!result); + const [newPeer] = await createPeerIds(1) + const result = await KeyCache.load(newPeer) + assert(!result) } catch (e) { - console.error(e); + console.error(e) assert(false, `Test failed - ${e.message}`) } - }); -}); + }) +}) diff --git a/test/noise.spec.ts b/test/noise.spec.ts index 39dd061..dae1c0d 100644 --- a/test/noise.spec.ts +++ b/test/noise.spec.ts @@ -1,57 +1,57 @@ -import {assert, expect} from "chai"; -import DuplexPair from 'it-pair/duplex'; -import {createPeerIdsFromFixtures} from "./fixtures/peer"; -import Wrap from "it-pb-rpc"; -import sinon from "sinon"; -import BufferList from "bl"; -import {randomBytes} from 'libp2p-crypto'; -import {Buffer} from "buffer"; +import { assert, expect } from 'chai' +import DuplexPair from 'it-pair/duplex' +import { createPeerIdsFromFixtures } from './fixtures/peer' +import Wrap from 'it-pb-rpc' +import sinon from 'sinon' +import BufferList from 'bl' +import { randomBytes } from 'libp2p-crypto' +import { Buffer } from 'buffer' -import {Noise} from "../src"; -import {XXHandshake} from "../src/handshake-xx"; -import {createHandshakePayload, generateKeypair, getHandshakePayload, getPayload, signPayload} from "../src/utils"; -import {decode0, decode2, encode1, uint16BEDecode, uint16BEEncode} from "../src/encoder"; -import {XX} from "../src/handshakes/xx"; -import {getKeyPairFromPeerId} from "./utils"; -import {KeyCache} from "../src/keycache"; -import {NOISE_MSG_MAX_LENGTH_BYTES} from "../src/constants"; +import { Noise } from '../src' +import { XXHandshake } from '../src/handshake-xx' +import { createHandshakePayload, generateKeypair, getHandshakePayload, getPayload, signPayload } from '../src/utils' +import { decode0, decode2, encode1, uint16BEDecode, uint16BEEncode } from '../src/encoder' +import { XX } from '../src/handshakes/xx' +import { getKeyPairFromPeerId } from './utils' +import { KeyCache } from '../src/keycache' +import { NOISE_MSG_MAX_LENGTH_BYTES } from '../src/constants' -describe("Noise", () => { - let remotePeer, localPeer; - let sandbox = sinon.createSandbox(); +describe('Noise', () => { + let remotePeer, localPeer + const sandbox = sinon.createSandbox() before(async () => { - [localPeer, remotePeer] = await createPeerIdsFromFixtures(2); - }); + [localPeer, remotePeer] = await createPeerIdsFromFixtures(2) + }) - afterEach(function() { - sandbox.restore(); - }); + afterEach(function () { + sandbox.restore() + }) - it("should communicate through encrypted streams without noise pipes", async() => { + it('should communicate through encrypted streams without noise pipes', async () => { try { - const noiseInit = new Noise(undefined, undefined, false); - const noiseResp = new Noise(undefined, undefined, false); + const noiseInit = new Noise(undefined, undefined, false) + const noiseResp = new Noise(undefined, undefined, false) - const [inboundConnection, outboundConnection] = DuplexPair(); + const [inboundConnection, outboundConnection] = DuplexPair() const [outbound, inbound] = await Promise.all([ noiseInit.secureOutbound(localPeer, outboundConnection, remotePeer), - noiseResp.secureInbound(remotePeer, inboundConnection, localPeer), - ]); - const wrappedInbound = Wrap(inbound.conn); - const wrappedOutbound = Wrap(outbound.conn); + noiseResp.secureInbound(remotePeer, inboundConnection, localPeer) + ]) + const wrappedInbound = Wrap(inbound.conn) + const wrappedOutbound = Wrap(outbound.conn) - wrappedOutbound.writeLP(Buffer.from("test")); - const response = await wrappedInbound.readLP(); - expect(response.toString()).equal("test"); + wrappedOutbound.writeLP(Buffer.from('test')) + const response = await wrappedInbound.readLP() + expect(response.toString()).equal('test') } catch (e) { - assert(false, e.message); + assert(false, e.message) } - }); + }) - it("should test that secureOutbound is spec compliant", async() => { - const noiseInit = new Noise(undefined, undefined, false); - const [inboundConnection, outboundConnection] = DuplexPair(); + it('should test that secureOutbound is spec compliant', async () => { + const noiseInit = new Noise(undefined, undefined, false) + const [inboundConnection, outboundConnection] = DuplexPair() const [outbound, { wrapped, handshake }] = await Promise.all([ noiseInit.secureOutbound(localPeer, outboundConnection, remotePeer), @@ -63,304 +63,303 @@ describe("Noise", () => { lengthDecoder: uint16BEDecode, maxDataLength: NOISE_MSG_MAX_LENGTH_BYTES } - ); - const prologue = Buffer.alloc(0); - const staticKeys = generateKeypair(); - const xx = new XX(); + ) + const prologue = Buffer.alloc(0) + const staticKeys = generateKeypair() + const xx = new XX() - const payload = await getPayload(remotePeer, staticKeys.publicKey); - const handshake = new XXHandshake(false, payload, prologue, staticKeys, wrapped, localPeer, xx); + const payload = await getPayload(remotePeer, staticKeys.publicKey) + const handshake = new XXHandshake(false, payload, prologue, staticKeys, wrapped, localPeer, xx) - let receivedMessageBuffer = decode0((await wrapped.readLP()).slice()); + let receivedMessageBuffer = decode0((await wrapped.readLP()).slice()) // The first handshake message contains the initiator's ephemeral public key - expect(receivedMessageBuffer.ne.length).equal(32); - xx.recvMessage(handshake.session, receivedMessageBuffer); + expect(receivedMessageBuffer.ne.length).equal(32) + xx.recvMessage(handshake.session, receivedMessageBuffer) // Stage 1 - const { publicKey: libp2pPubKey } = getKeyPairFromPeerId(remotePeer); - const signedPayload = await signPayload(remotePeer, getHandshakePayload(staticKeys.publicKey)); - const handshakePayload = await createHandshakePayload(libp2pPubKey, signedPayload); + const { publicKey: libp2pPubKey } = getKeyPairFromPeerId(remotePeer) + const signedPayload = await signPayload(remotePeer, getHandshakePayload(staticKeys.publicKey)) + const handshakePayload = await createHandshakePayload(libp2pPubKey, signedPayload) - const messageBuffer = xx.sendMessage(handshake.session, handshakePayload); - wrapped.writeLP(encode1(messageBuffer)); + const messageBuffer = xx.sendMessage(handshake.session, handshakePayload) + wrapped.writeLP(encode1(messageBuffer)) // Stage 2 - finish handshake - receivedMessageBuffer = decode2((await wrapped.readLP()).slice()); - xx.recvMessage(handshake.session, receivedMessageBuffer); - return {wrapped, handshake}; - })(), - ]); + receivedMessageBuffer = decode2((await wrapped.readLP()).slice()) + xx.recvMessage(handshake.session, receivedMessageBuffer) + return { wrapped, handshake } + })() + ]) try { - const wrappedOutbound = Wrap(outbound.conn); - wrappedOutbound.write(new BufferList([Buffer.from("test")])); + const wrappedOutbound = Wrap(outbound.conn) + wrappedOutbound.write(new BufferList([Buffer.from('test')])) // Check that noise message is prefixed with 16-bit big-endian unsigned integer - const receivedEncryptedPayload = (await wrapped.read()).slice(); - const dataLength = receivedEncryptedPayload.readInt16BE(0); - const data = receivedEncryptedPayload.slice(2, dataLength + 2); - const {plaintext: decrypted, valid} = handshake.decrypt(data, handshake.session); + const receivedEncryptedPayload = (await wrapped.read()).slice() + const dataLength = receivedEncryptedPayload.readInt16BE(0) + const data = receivedEncryptedPayload.slice(2, dataLength + 2) + const { plaintext: decrypted, valid } = handshake.decrypt(data, handshake.session) // Decrypted data should match - assert(decrypted.equals(Buffer.from("test"))); - assert(valid); + assert(decrypted.equals(Buffer.from('test'))) + assert(valid) } catch (e) { - assert(false, e.message); + assert(false, e.message) } - }); + }) - - it("should test large payloads", async function() { - this.timeout(10000); + it('should test large payloads', async function () { + this.timeout(10000) try { - const noiseInit = new Noise(undefined, undefined, false); - const noiseResp = new Noise(undefined, undefined, false); + const noiseInit = new Noise(undefined, undefined, false) + const noiseResp = new Noise(undefined, undefined, false) - const [inboundConnection, outboundConnection] = DuplexPair(); + const [inboundConnection, outboundConnection] = DuplexPair() const [outbound, inbound] = await Promise.all([ noiseInit.secureOutbound(localPeer, outboundConnection, remotePeer), - noiseResp.secureInbound(remotePeer, inboundConnection, localPeer), - ]); - const wrappedInbound = Wrap(inbound.conn); - const wrappedOutbound = Wrap(outbound.conn); + noiseResp.secureInbound(remotePeer, inboundConnection, localPeer) + ]) + const wrappedInbound = Wrap(inbound.conn) + const wrappedOutbound = Wrap(outbound.conn) - const largePlaintext = randomBytes(100000); - wrappedOutbound.writeLP(largePlaintext); - const response = await wrappedInbound.read(100000); + const largePlaintext = randomBytes(100000) + wrappedOutbound.writeLP(largePlaintext) + const response = await wrappedInbound.read(100000) - expect(response.length).equals(largePlaintext.length); + expect(response.length).equals(largePlaintext.length) } catch (e) { - console.log(e); - assert(false, e.message); + console.log(e) + assert(false, e.message) } - }); + }) - it.skip("should communicate through encrypted streams with noise pipes", async() => { + it.skip('should communicate through encrypted streams with noise pipes', async () => { try { - const staticKeysInitiator = generateKeypair(); - const noiseInit = new Noise(staticKeysInitiator.privateKey); - const staticKeysResponder = generateKeypair(); - const noiseResp = new Noise(staticKeysResponder.privateKey); + const staticKeysInitiator = generateKeypair() + const noiseInit = new Noise(staticKeysInitiator.privateKey) + const staticKeysResponder = generateKeypair() + const noiseResp = new Noise(staticKeysResponder.privateKey) // Prepare key cache for noise pipes - KeyCache.store(localPeer, staticKeysInitiator.publicKey); - KeyCache.store(remotePeer, staticKeysResponder.publicKey); + KeyCache.store(localPeer, staticKeysInitiator.publicKey) + KeyCache.store(remotePeer, staticKeysResponder.publicKey) - const xxSpy = sandbox.spy(noiseInit, "performXXHandshake"); - const xxFallbackSpy = sandbox.spy(noiseInit, "performXXFallbackHandshake"); + const xxSpy = sandbox.spy(noiseInit, 'performXXHandshake') + const xxFallbackSpy = sandbox.spy(noiseInit, 'performXXFallbackHandshake') - const [inboundConnection, outboundConnection] = DuplexPair(); + const [inboundConnection, outboundConnection] = DuplexPair() const [outbound, inbound] = await Promise.all([ noiseInit.secureOutbound(localPeer, outboundConnection, remotePeer), - noiseResp.secureInbound(remotePeer, inboundConnection, localPeer), - ]); - const wrappedInbound = Wrap(inbound.conn); - const wrappedOutbound = Wrap(outbound.conn); + noiseResp.secureInbound(remotePeer, inboundConnection, localPeer) + ]) + const wrappedInbound = Wrap(inbound.conn) + const wrappedOutbound = Wrap(outbound.conn) - wrappedOutbound.writeLP(Buffer.from("test v2")); - const response = await wrappedInbound.readLP(); - expect(response.toString()).equal("test v2"); + wrappedOutbound.writeLP(Buffer.from('test v2')) + const response = await wrappedInbound.readLP() + expect(response.toString()).equal('test v2') - assert(xxSpy.notCalled); - assert(xxFallbackSpy.notCalled); + assert(xxSpy.notCalled) + assert(xxFallbackSpy.notCalled) } catch (e) { - console.error(e); - assert(false, e.message); + console.error(e) + assert(false, e.message) } - }); + }) - it.skip("IK -> XX fallback: initiator has invalid remote static key", async() => { + it.skip('IK -> XX fallback: initiator has invalid remote static key', async () => { try { - const staticKeysInitiator = generateKeypair(); - const noiseInit = new Noise(staticKeysInitiator.privateKey); - const noiseResp = new Noise(); - const xxSpy = sandbox.spy(noiseInit, "performXXFallbackHandshake"); + const staticKeysInitiator = generateKeypair() + const noiseInit = new Noise(staticKeysInitiator.privateKey) + const noiseResp = new Noise() + const xxSpy = sandbox.spy(noiseInit, 'performXXFallbackHandshake') // Prepare key cache for noise pipes - KeyCache.resetStorage(); - KeyCache.store(localPeer, staticKeysInitiator.publicKey); - KeyCache.store(remotePeer, generateKeypair().publicKey); + KeyCache.resetStorage() + KeyCache.store(localPeer, staticKeysInitiator.publicKey) + KeyCache.store(remotePeer, generateKeypair().publicKey) - const [inboundConnection, outboundConnection] = DuplexPair(); + const [inboundConnection, outboundConnection] = DuplexPair() const [outbound, inbound] = await Promise.all([ noiseInit.secureOutbound(localPeer, outboundConnection, remotePeer), - noiseResp.secureInbound(remotePeer, inboundConnection, localPeer), - ]); + noiseResp.secureInbound(remotePeer, inboundConnection, localPeer) + ]) - const wrappedInbound = Wrap(inbound.conn); - const wrappedOutbound = Wrap(outbound.conn); + const wrappedInbound = Wrap(inbound.conn) + const wrappedOutbound = Wrap(outbound.conn) - wrappedOutbound.writeLP(Buffer.from("test fallback")); - const response = await wrappedInbound.readLP(); - expect(response.toString()).equal("test fallback"); + wrappedOutbound.writeLP(Buffer.from('test fallback')) + const response = await wrappedInbound.readLP() + expect(response.toString()).equal('test fallback') - assert(xxSpy.calledOnce, "XX Fallback method was never called."); + assert(xxSpy.calledOnce, 'XX Fallback method was never called.') } catch (e) { - console.error(e); - assert(false, e.message); + console.error(e) + assert(false, e.message) } - }); + }) - //this didn't work before but we didn't verify decryption - it.skip("IK -> XX fallback: responder has disabled noise pipes", async() => { - try { - const staticKeysInitiator = generateKeypair(); - const noiseInit = new Noise(staticKeysInitiator.privateKey); - - const staticKeysResponder = generateKeypair(); - const noiseResp = new Noise(staticKeysResponder.privateKey, undefined, false); - const xxSpy = sandbox.spy(noiseInit, "performXXFallbackHandshake"); - - // Prepare key cache for noise pipes - KeyCache.store(localPeer, staticKeysInitiator.publicKey); - KeyCache.store(remotePeer, staticKeysResponder.publicKey); - - const [inboundConnection, outboundConnection] = DuplexPair(); - const [outbound, inbound] = await Promise.all([ - noiseInit.secureOutbound(localPeer, outboundConnection, remotePeer), - noiseResp.secureInbound(remotePeer, inboundConnection, localPeer), - ]); - - const wrappedInbound = Wrap(inbound.conn); - const wrappedOutbound = Wrap(outbound.conn); - - wrappedOutbound.writeLP(Buffer.from("test fallback")); - const response = await wrappedInbound.readLP(); - expect(response.toString()).equal("test fallback"); - - assert(xxSpy.calledOnce, "XX Fallback method was never called."); - } catch (e) { - console.error(e); - assert(false, e.message); - } - }); - - it.skip("Initiator starts with XX (pipes disabled), responder has enabled noise pipes", async() => { + // this didn't work before but we didn't verify decryption + it.skip('IK -> XX fallback: responder has disabled noise pipes', async () => { try { - const staticKeysInitiator = generateKeypair(); - const noiseInit = new Noise(staticKeysInitiator.privateKey, undefined, false); - const staticKeysResponder = generateKeypair(); + const staticKeysInitiator = generateKeypair() + const noiseInit = new Noise(staticKeysInitiator.privateKey) - const noiseResp = new Noise(staticKeysResponder.privateKey); - const xxInitSpy = sandbox.spy(noiseInit, "performXXHandshake"); - const xxRespSpy = sandbox.spy(noiseResp, "performXXFallbackHandshake"); + const staticKeysResponder = generateKeypair() + const noiseResp = new Noise(staticKeysResponder.privateKey, undefined, false) + const xxSpy = sandbox.spy(noiseInit, 'performXXFallbackHandshake') // Prepare key cache for noise pipes - KeyCache.store(localPeer, staticKeysInitiator.publicKey); - - const [inboundConnection, outboundConnection] = DuplexPair(); + KeyCache.store(localPeer, staticKeysInitiator.publicKey) + KeyCache.store(remotePeer, staticKeysResponder.publicKey) + const [inboundConnection, outboundConnection] = DuplexPair() const [outbound, inbound] = await Promise.all([ noiseInit.secureOutbound(localPeer, outboundConnection, remotePeer), - noiseResp.secureInbound(remotePeer, inboundConnection, localPeer), - ]); + noiseResp.secureInbound(remotePeer, inboundConnection, localPeer) + ]) - const wrappedInbound = Wrap(inbound.conn); - const wrappedOutbound = Wrap(outbound.conn); + const wrappedInbound = Wrap(inbound.conn) + const wrappedOutbound = Wrap(outbound.conn) - wrappedOutbound.writeLP(Buffer.from("test fallback")); - const response = await wrappedInbound.readLP(); - expect(response.toString()).equal("test fallback"); + wrappedOutbound.writeLP(Buffer.from('test fallback')) + const response = await wrappedInbound.readLP() + expect(response.toString()).equal('test fallback') - assert(xxInitSpy.calledOnce, "XX method was never called."); - assert(xxRespSpy.calledOnce, "XX Fallback method was never called."); + assert(xxSpy.calledOnce, 'XX Fallback method was never called.') } catch (e) { - console.error(e); - assert(false, e.message); + console.error(e) + assert(false, e.message) } - }); + }) - it.skip("IK: responder has no remote static key", async() => { + it.skip('Initiator starts with XX (pipes disabled), responder has enabled noise pipes', async () => { try { - const staticKeysInitiator = generateKeypair(); - const noiseInit = new Noise(staticKeysInitiator.privateKey); - const staticKeysResponder = generateKeypair(); + const staticKeysInitiator = generateKeypair() + const noiseInit = new Noise(staticKeysInitiator.privateKey, undefined, false) + const staticKeysResponder = generateKeypair() - const noiseResp = new Noise(staticKeysResponder.privateKey); - const ikInitSpy = sandbox.spy(noiseInit, "performIKHandshake"); - const xxFallbackInitSpy = sandbox.spy(noiseInit, "performXXFallbackHandshake"); - const ikRespSpy = sandbox.spy(noiseResp, "performIKHandshake"); + const noiseResp = new Noise(staticKeysResponder.privateKey) + const xxInitSpy = sandbox.spy(noiseInit, 'performXXHandshake') + const xxRespSpy = sandbox.spy(noiseResp, 'performXXFallbackHandshake') // Prepare key cache for noise pipes - KeyCache.resetStorage(); - KeyCache.store(remotePeer, staticKeysResponder.publicKey); + KeyCache.store(localPeer, staticKeysInitiator.publicKey) - const [inboundConnection, outboundConnection] = DuplexPair(); + const [inboundConnection, outboundConnection] = DuplexPair() const [outbound, inbound] = await Promise.all([ noiseInit.secureOutbound(localPeer, outboundConnection, remotePeer), - noiseResp.secureInbound(remotePeer, inboundConnection, localPeer), - ]); + noiseResp.secureInbound(remotePeer, inboundConnection, localPeer) + ]) - const wrappedInbound = Wrap(inbound.conn); - const wrappedOutbound = Wrap(outbound.conn); + const wrappedInbound = Wrap(inbound.conn) + const wrappedOutbound = Wrap(outbound.conn) - wrappedOutbound.writeLP(Buffer.from("test fallback")); - const response = await wrappedInbound.readLP(); - expect(response.toString()).equal("test fallback"); + wrappedOutbound.writeLP(Buffer.from('test fallback')) + const response = await wrappedInbound.readLP() + expect(response.toString()).equal('test fallback') - assert(ikInitSpy.calledOnce, "IK handshake was not called."); - assert(ikRespSpy.calledOnce, "IK handshake was not called."); - assert(xxFallbackInitSpy.notCalled, "XX Fallback method was called."); + assert(xxInitSpy.calledOnce, 'XX method was never called.') + assert(xxRespSpy.calledOnce, 'XX Fallback method was never called.') } catch (e) { - console.error(e); - assert(false, e.message); + console.error(e) + assert(false, e.message) } - }); + }) - it("should working without remote peer provided in incoming connection", async() => { + it.skip('IK: responder has no remote static key', async () => { try { - const staticKeysInitiator = generateKeypair(); - const noiseInit = new Noise(staticKeysInitiator.privateKey); - const staticKeysResponder = generateKeypair(); - const noiseResp = new Noise(staticKeysResponder.privateKey); + const staticKeysInitiator = generateKeypair() + const noiseInit = new Noise(staticKeysInitiator.privateKey) + const staticKeysResponder = generateKeypair() + + const noiseResp = new Noise(staticKeysResponder.privateKey) + const ikInitSpy = sandbox.spy(noiseInit, 'performIKHandshake') + const xxFallbackInitSpy = sandbox.spy(noiseInit, 'performXXFallbackHandshake') + const ikRespSpy = sandbox.spy(noiseResp, 'performIKHandshake') // Prepare key cache for noise pipes - KeyCache.store(localPeer, staticKeysInitiator.publicKey); - KeyCache.store(remotePeer, staticKeysResponder.publicKey); + KeyCache.resetStorage() + KeyCache.store(remotePeer, staticKeysResponder.publicKey) + + const [inboundConnection, outboundConnection] = DuplexPair() - const [inboundConnection, outboundConnection] = DuplexPair(); const [outbound, inbound] = await Promise.all([ noiseInit.secureOutbound(localPeer, outboundConnection, remotePeer), - noiseResp.secureInbound(remotePeer, inboundConnection), - ]); - const wrappedInbound = Wrap(inbound.conn); - const wrappedOutbound = Wrap(outbound.conn); + noiseResp.secureInbound(remotePeer, inboundConnection, localPeer) + ]) - wrappedOutbound.writeLP(Buffer.from("test v2")); - const response = await wrappedInbound.readLP(); - expect(response.toString()).equal("test v2"); + const wrappedInbound = Wrap(inbound.conn) + const wrappedOutbound = Wrap(outbound.conn) - assert(inbound.remotePeer.marshalPubKey().equals(localPeer.marshalPubKey())); - assert(outbound.remotePeer.marshalPubKey().equals(remotePeer.marshalPubKey())); + wrappedOutbound.writeLP(Buffer.from('test fallback')) + const response = await wrappedInbound.readLP() + expect(response.toString()).equal('test fallback') + + assert(ikInitSpy.calledOnce, 'IK handshake was not called.') + assert(ikRespSpy.calledOnce, 'IK handshake was not called.') + assert(xxFallbackInitSpy.notCalled, 'XX Fallback method was called.') } catch (e) { - console.error(e); - assert(false, e.message); + console.error(e) + assert(false, e.message) } - }); + }) - it("should accept and return early data from remote peer", async() => { + it('should working without remote peer provided in incoming connection', async () => { + try { + const staticKeysInitiator = generateKeypair() + const noiseInit = new Noise(staticKeysInitiator.privateKey) + const staticKeysResponder = generateKeypair() + const noiseResp = new Noise(staticKeysResponder.privateKey) + + // Prepare key cache for noise pipes + KeyCache.store(localPeer, staticKeysInitiator.publicKey) + KeyCache.store(remotePeer, staticKeysResponder.publicKey) + + const [inboundConnection, outboundConnection] = DuplexPair() + const [outbound, inbound] = await Promise.all([ + noiseInit.secureOutbound(localPeer, outboundConnection, remotePeer), + noiseResp.secureInbound(remotePeer, inboundConnection) + ]) + const wrappedInbound = Wrap(inbound.conn) + const wrappedOutbound = Wrap(outbound.conn) + + wrappedOutbound.writeLP(Buffer.from('test v2')) + const response = await wrappedInbound.readLP() + expect(response.toString()).equal('test v2') + + assert(inbound.remotePeer.marshalPubKey().equals(localPeer.marshalPubKey())) + assert(outbound.remotePeer.marshalPubKey().equals(remotePeer.marshalPubKey())) + } catch (e) { + console.error(e) + assert(false, e.message) + } + }) + + it('should accept and return early data from remote peer', async () => { try { const localPeerEarlyData = Buffer.from('early data') - const staticKeysInitiator = generateKeypair(); - const noiseInit = new Noise(staticKeysInitiator.privateKey, localPeerEarlyData); - const staticKeysResponder = generateKeypair(); - const noiseResp = new Noise(staticKeysResponder.privateKey); + const staticKeysInitiator = generateKeypair() + const noiseInit = new Noise(staticKeysInitiator.privateKey, localPeerEarlyData) + const staticKeysResponder = generateKeypair() + const noiseResp = new Noise(staticKeysResponder.privateKey) // Prepare key cache for noise pipes - KeyCache.store(localPeer, staticKeysInitiator.publicKey); - KeyCache.store(remotePeer, staticKeysResponder.publicKey); + KeyCache.store(localPeer, staticKeysInitiator.publicKey) + KeyCache.store(remotePeer, staticKeysResponder.publicKey) - const [inboundConnection, outboundConnection] = DuplexPair(); + const [inboundConnection, outboundConnection] = DuplexPair() const [outbound, inbound] = await Promise.all([ noiseInit.secureOutbound(localPeer, outboundConnection, remotePeer), - noiseResp.secureInbound(remotePeer, inboundConnection), - ]); + noiseResp.secureInbound(remotePeer, inboundConnection) + ]) assert(inbound.remoteEarlyData.equals(localPeerEarlyData)) assert(outbound.remoteEarlyData.equals(Buffer.alloc(0))) } catch (e) { - console.error(e); - assert(false, e.message); + console.error(e) + assert(false, e.message) } - }); -}); + }) +}) diff --git a/test/utils.ts b/test/utils.ts index 29a5b06..af3cf4e 100644 --- a/test/utils.ts +++ b/test/utils.ts @@ -1,14 +1,14 @@ -import {keys} from 'libp2p-crypto'; -import {KeyPair} from "../src/@types/libp2p"; -import PeerId from "peer-id"; +import { keys } from 'libp2p-crypto' +import { KeyPair } from '../src/@types/libp2p' +import PeerId from 'peer-id' -export async function generateEd25519Keys() { - return await keys.generateKeyPair('ed25519'); +export async function generateEd25519Keys () { + return await keys.generateKeyPair('ed25519') } -export function getKeyPairFromPeerId(peerId: PeerId): KeyPair { +export function getKeyPairFromPeerId (peerId: PeerId): KeyPair { return { privateKey: peerId.privKey.marshal().slice(0, 32), - publicKey: peerId.marshalPubKey(), + publicKey: peerId.marshalPubKey() } } diff --git a/test/xx-fallback-handshake.spec.ts b/test/xx-fallback-handshake.spec.ts index 9f3802f..0fff966 100644 --- a/test/xx-fallback-handshake.spec.ts +++ b/test/xx-fallback-handshake.spec.ts @@ -1,74 +1,74 @@ -import Wrap from "it-pb-rpc"; -import {Buffer} from "buffer"; -import Duplex from 'it-pair/duplex'; +import Wrap from 'it-pb-rpc' +import { Buffer } from 'buffer' +import Duplex from 'it-pair/duplex' import { generateKeypair, - getPayload, -} from "../src/utils"; -import {XXFallbackHandshake} from "../src/handshake-xx-fallback"; -import {createPeerIdsFromFixtures} from "./fixtures/peer"; -import {assert} from "chai"; -import {decode1, encode0, encode1} from "../src/encoder"; + getPayload +} from '../src/utils' +import { XXFallbackHandshake } from '../src/handshake-xx-fallback' +import { createPeerIdsFromFixtures } from './fixtures/peer' +import { assert } from 'chai' +import { decode1, encode0, encode1 } from '../src/encoder' -describe("XX Fallback Handshake", () => { - let peerA, peerB, fakePeer; +describe('XX Fallback Handshake', () => { + let peerA, peerB, fakePeer before(async () => { - [peerA, peerB] = await createPeerIdsFromFixtures(2); - }); + [peerA, peerB] = await createPeerIdsFromFixtures(2) + }) - it("should test that both parties can fallback to XX and finish handshake", async () => { + it('should test that both parties can fallback to XX and finish handshake', async () => { try { - const duplex = Duplex(); - const connectionFrom = Wrap(duplex[0]); - const connectionTo = Wrap(duplex[1]); + const duplex = Duplex() + const connectionFrom = Wrap(duplex[0]) + const connectionTo = Wrap(duplex[1]) - const prologue = Buffer.alloc(0); - const staticKeysInitiator = generateKeypair(); - const staticKeysResponder = generateKeypair(); - const ephemeralKeys = generateKeypair(); + const prologue = Buffer.alloc(0) + const staticKeysInitiator = generateKeypair() + const staticKeysResponder = generateKeypair() + const ephemeralKeys = generateKeypair() // Initial msg for responder is IK first message from initiator - const handshakePayload = await getPayload(peerA, staticKeysInitiator.publicKey); + const handshakePayload = await getPayload(peerA, staticKeysInitiator.publicKey) const initialMsgR = encode0({ ne: ephemeralKeys.publicKey, ns: Buffer.alloc(0), - ciphertext: handshakePayload, - }); + ciphertext: handshakePayload + }) - const respPayload = await getPayload(peerB, staticKeysResponder.publicKey); + const respPayload = await getPayload(peerB, staticKeysResponder.publicKey) const handshakeResp = - new XXFallbackHandshake(false, respPayload, prologue, staticKeysResponder, connectionTo, initialMsgR, peerA); + new XXFallbackHandshake(false, respPayload, prologue, staticKeysResponder, connectionTo, initialMsgR, peerA) - await handshakeResp.propose(); - await handshakeResp.exchange(); + await handshakeResp.propose() + await handshakeResp.exchange() // Initial message for initiator is XX Message B from responder // This is the point where initiator falls back from IK - const initialMsgI = await connectionFrom.readLP(); + const initialMsgI = await connectionFrom.readLP() const handshakeInit = - new XXFallbackHandshake(true, handshakePayload, prologue, staticKeysInitiator, connectionFrom, initialMsgI, peerB, ephemeralKeys); + new XXFallbackHandshake(true, handshakePayload, prologue, staticKeysInitiator, connectionFrom, initialMsgI, peerB, ephemeralKeys) - await handshakeInit.propose(); - await handshakeInit.exchange(); + await handshakeInit.propose() + await handshakeInit.exchange() - await handshakeInit.finish(); - await handshakeResp.finish(); + await handshakeInit.finish() + await handshakeResp.finish() - const sessionInitator = handshakeInit.session; - const sessionResponder = handshakeResp.session; + const sessionInitator = handshakeInit.session + const sessionResponder = handshakeResp.session // Test shared key if (sessionInitator.cs1 && sessionResponder.cs1 && sessionInitator.cs2 && sessionResponder.cs2) { - assert(sessionInitator.cs1.k.equals(sessionResponder.cs1.k)); - assert(sessionInitator.cs2.k.equals(sessionResponder.cs2.k)); + assert(sessionInitator.cs1.k.equals(sessionResponder.cs1.k)) + assert(sessionInitator.cs2.k.equals(sessionResponder.cs2.k)) } else { - assert(false); + assert(false) } } catch (e) { - console.error(e); - assert(false, e.message); + console.error(e) + assert(false, e.message) } - }); + }) }) diff --git a/test/xx-handshake.spec.ts b/test/xx-handshake.spec.ts index 17f0dbb..2c7ad13 100644 --- a/test/xx-handshake.spec.ts +++ b/test/xx-handshake.spec.ts @@ -1,121 +1,120 @@ -import {assert, expect} from "chai"; -import Duplex from 'it-pair/duplex'; -import {Buffer} from "buffer"; -import Wrap from "it-pb-rpc"; -import {XXHandshake} from "../src/handshake-xx"; -import {generateKeypair, getPayload} from "../src/utils"; -import {createPeerIdsFromFixtures} from "./fixtures/peer"; +import { assert, expect } from 'chai' +import Duplex from 'it-pair/duplex' +import { Buffer } from 'buffer' +import Wrap from 'it-pb-rpc' +import { XXHandshake } from '../src/handshake-xx' +import { generateKeypair, getPayload } from '../src/utils' +import { createPeerIdsFromFixtures } from './fixtures/peer' - -describe("XX Handshake", () => { - let peerA, peerB, fakePeer; +describe('XX Handshake', () => { + let peerA, peerB, fakePeer before(async () => { - [peerA, peerB, fakePeer] = await createPeerIdsFromFixtures(3); - }); + [peerA, peerB, fakePeer] = await createPeerIdsFromFixtures(3) + }) - it("should propose, exchange and finish handshake", async() => { + it('should propose, exchange and finish handshake', async () => { try { - const duplex = Duplex(); - const connectionFrom = Wrap(duplex[0]); - const connectionTo = Wrap(duplex[1]); + const duplex = Duplex() + const connectionFrom = Wrap(duplex[0]) + const connectionTo = Wrap(duplex[1]) - const prologue = Buffer.alloc(0); - const staticKeysInitiator = generateKeypair(); - const staticKeysResponder = generateKeypair(); + const prologue = Buffer.alloc(0) + const staticKeysInitiator = generateKeypair() + const staticKeysResponder = generateKeypair() - const initPayload = await getPayload(peerA, staticKeysInitiator.publicKey); - const handshakeInitator = new XXHandshake(true, initPayload, prologue, staticKeysInitiator, connectionFrom, peerB); + const initPayload = await getPayload(peerA, staticKeysInitiator.publicKey) + const handshakeInitator = new XXHandshake(true, initPayload, prologue, staticKeysInitiator, connectionFrom, peerB) - const respPayload = await getPayload(peerB, staticKeysResponder.publicKey); - const handshakeResponder = new XXHandshake(false, respPayload, prologue, staticKeysResponder, connectionTo, peerA); + const respPayload = await getPayload(peerB, staticKeysResponder.publicKey) + const handshakeResponder = new XXHandshake(false, respPayload, prologue, staticKeysResponder, connectionTo, peerA) - await handshakeInitator.propose(); - await handshakeResponder.propose(); + await handshakeInitator.propose() + await handshakeResponder.propose() - await handshakeResponder.exchange(); - await handshakeInitator.exchange(); + await handshakeResponder.exchange() + await handshakeInitator.exchange() - await handshakeInitator.finish(); - await handshakeResponder.finish(); + await handshakeInitator.finish() + await handshakeResponder.finish() - const sessionInitator = handshakeInitator.session; - const sessionResponder = handshakeResponder.session; + const sessionInitator = handshakeInitator.session + const sessionResponder = handshakeResponder.session // Test shared key if (sessionInitator.cs1 && sessionResponder.cs1 && sessionInitator.cs2 && sessionResponder.cs2) { - assert(sessionInitator.cs1.k.equals(sessionResponder.cs1.k)); - assert(sessionInitator.cs2.k.equals(sessionResponder.cs2.k)); + assert(sessionInitator.cs1.k.equals(sessionResponder.cs1.k)) + assert(sessionInitator.cs2.k.equals(sessionResponder.cs2.k)) } else { - assert(false); + assert(false) } // Test encryption and decryption - const encrypted = handshakeInitator.encrypt(Buffer.from("encryptthis"), handshakeInitator.session); - const {plaintext: decrypted, valid} = handshakeResponder.decrypt(encrypted, handshakeResponder.session); - assert(decrypted.equals(Buffer.from("encryptthis"))); - assert(valid); + const encrypted = handshakeInitator.encrypt(Buffer.from('encryptthis'), handshakeInitator.session) + const { plaintext: decrypted, valid } = handshakeResponder.decrypt(encrypted, handshakeResponder.session) + assert(decrypted.equals(Buffer.from('encryptthis'))) + assert(valid) } catch (e) { - assert(false, e.message); + assert(false, e.message) } - }); + }) - it("Initiator should fail to exchange handshake if given wrong public key in payload", async() => { + it('Initiator should fail to exchange handshake if given wrong public key in payload', async () => { try { - const duplex = Duplex(); - const connectionFrom = Wrap(duplex[0]); - const connectionTo = Wrap(duplex[1]); + const duplex = Duplex() + const connectionFrom = Wrap(duplex[0]) + const connectionTo = Wrap(duplex[1]) - const prologue = Buffer.alloc(0); - const staticKeysInitiator = generateKeypair(); - const staticKeysResponder = generateKeypair(); + const prologue = Buffer.alloc(0) + const staticKeysInitiator = generateKeypair() + const staticKeysResponder = generateKeypair() - const initPayload = await getPayload(peerA, staticKeysInitiator.publicKey); - const handshakeInitator = new XXHandshake(true, initPayload, prologue, staticKeysInitiator, connectionFrom, fakePeer); + const initPayload = await getPayload(peerA, staticKeysInitiator.publicKey) + const handshakeInitator = new XXHandshake(true, initPayload, prologue, staticKeysInitiator, connectionFrom, fakePeer) - const respPayload = await getPayload(peerB, staticKeysResponder.publicKey); - const handshakeResponder = new XXHandshake(false, respPayload, prologue, staticKeysResponder, connectionTo, peerA); + const respPayload = await getPayload(peerB, staticKeysResponder.publicKey) + const handshakeResponder = new XXHandshake(false, respPayload, prologue, staticKeysResponder, connectionTo, peerA) - await handshakeInitator.propose(); - await handshakeResponder.propose(); + await handshakeInitator.propose() + await handshakeResponder.propose() - await handshakeResponder.exchange(); - await handshakeInitator.exchange(); + await handshakeResponder.exchange() + await handshakeInitator.exchange() - assert(false, "Should throw exception"); + assert(false, 'Should throw exception') } catch (e) { expect(e.message).equals("Error occurred while verifying signed payload: Peer ID doesn't match libp2p public key.") } - }); + }) - it("Responder should fail to exchange handshake if given wrong public key in payload", async() => { + it('Responder should fail to exchange handshake if given wrong public key in payload', async () => { try { - const duplex = Duplex(); - const connectionFrom = Wrap(duplex[0]); - const connectionTo = Wrap(duplex[1]); + const duplex = Duplex() + const connectionFrom = Wrap(duplex[0]) + const connectionTo = Wrap(duplex[1]) - const prologue = Buffer.alloc(0); - const staticKeysInitiator = generateKeypair(); - const staticKeysResponder = generateKeypair(); + const prologue = Buffer.alloc(0) + const staticKeysInitiator = generateKeypair() + const staticKeysResponder = generateKeypair() - const initPayload = await getPayload(peerA, staticKeysInitiator.publicKey); - const handshakeInitator = new XXHandshake(true, initPayload, prologue, staticKeysInitiator, connectionFrom, peerB); + const initPayload = await getPayload(peerA, staticKeysInitiator.publicKey) + const handshakeInitator = new XXHandshake(true, initPayload, prologue, staticKeysInitiator, connectionFrom, peerB) - const respPayload = await getPayload(peerB, staticKeysResponder.publicKey); - const handshakeResponder = new XXHandshake(false, respPayload, prologue, staticKeysResponder, connectionTo, fakePeer); + const respPayload = await getPayload(peerB, staticKeysResponder.publicKey) + const handshakeResponder = new XXHandshake(false, respPayload, prologue, staticKeysResponder, connectionTo, fakePeer) - await handshakeInitator.propose(); - await handshakeResponder.propose(); + await handshakeInitator.propose() + await handshakeResponder.propose() - await handshakeResponder.exchange(); - await handshakeInitator.exchange(); + await handshakeResponder.exchange() + await handshakeInitator.exchange() - await handshakeInitator.finish(); - await handshakeResponder.finish(); + await handshakeInitator.finish() + await handshakeResponder.finish() - assert(false, "Should throw exception"); + assert(false, 'Should throw exception') } catch (e) { expect(e.message).equals("Error occurred while verifying signed payload: Peer ID doesn't match libp2p public key.") } - }); -}); + }) +}) From ca39bc5d99fcae28e3aeb0b7e309382679836ba0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marin=20Petruni=C4=87?= Date: Fri, 19 Jun 2020 13:06:31 +0200 Subject: [PATCH 03/11] lint fixes --- package.json | 8 +++++++- src/encoder.ts | 4 ++-- src/errors.ts | 4 ++-- src/handshake-xx-fallback.ts | 1 + src/handshakes/abstract-handshake.ts | 2 +- src/logger.ts | 2 +- src/noise.ts | 10 +++++----- src/utils.ts | 8 ++++---- test/fixtures/peer.ts | 10 +++++----- test/handshakes/ik.spec.ts | 13 ++++++------- test/handshakes/xx.spec.ts | 10 +++++----- test/ik-handshake.spec.ts | 5 ++--- test/keycache.spec.ts | 10 ++++------ test/noise.spec.ts | 18 +++++------------- test/utils.ts | 6 +++--- test/xx-fallback-handshake.spec.ts | 5 ++--- 16 files changed, 55 insertions(+), 61 deletions(-) diff --git a/package.json b/package.json index 920a0b8..e1e2eb2 100644 --- a/package.json +++ b/package.json @@ -50,6 +50,12 @@ "bn.js": "4.4.0" }, "eslintConfig": { - "extends": "./node_modules/aegir/src/config/eslintrc-ts.js" + "extends": "./node_modules/aegir/src/config/eslintrc-ts.js", + "rules": { + "@typescript-eslint/no-unused-vars": "error" + }, + "ignorePatterns": [ + "src/proto/payload.js" + ] } } diff --git a/src/encoder.ts b/src/encoder.ts index 08877f3..f60ea3a 100644 --- a/src/encoder.ts +++ b/src/encoder.ts @@ -2,14 +2,14 @@ import { Buffer } from 'buffer' import { bytes } from './@types/basic' import { MessageBuffer } from './@types/handshake' -export const uint16BEEncode = (value, target, offset) => { +export const uint16BEEncode = (value: number, target: bytes, offset: number): bytes => { target = target || Buffer.allocUnsafe(2) target.writeUInt16BE(value, offset) return target } uint16BEEncode.bytes = 2 -export const uint16BEDecode = data => { +export const uint16BEDecode = (data: bytes): number => { if (data.length < 2) throw RangeError('Could not decode int16BE') return data.readUInt16BE(0) } diff --git a/src/errors.ts b/src/errors.ts index 8a52f23..e04d520 100644 --- a/src/errors.ts +++ b/src/errors.ts @@ -1,7 +1,7 @@ export class FailedIKError extends Error { - public initialMsg; + public initialMsg: string; - constructor (initialMsg, message?: string) { + constructor (initialMsg: string, message?: string) { super(message) this.initialMsg = initialMsg diff --git a/src/handshake-xx-fallback.ts b/src/handshake-xx-fallback.ts index 4c19a21..10a08a1 100644 --- a/src/handshake-xx-fallback.ts +++ b/src/handshake-xx-fallback.ts @@ -32,6 +32,7 @@ export class XXFallbackHandshake extends XXHandshake { } // stage 0 + // eslint-disable-next-line require-await public async propose (): Promise { if (this.isInitiator) { this.xx.sendMessage(this.session, Buffer.alloc(0), this.ephemeralKeys) diff --git a/src/handshakes/abstract-handshake.ts b/src/handshakes/abstract-handshake.ts index 83a5d53..275152b 100644 --- a/src/handshakes/abstract-handshake.ts +++ b/src/handshakes/abstract-handshake.ts @@ -157,7 +157,7 @@ export abstract class AbstractHandshake { } } - protected split (ss: SymmetricState) { + protected split (ss: SymmetricState): {cs1: CipherState, cs2: CipherState} { const [tempk1, tempk2] = getHkdf(ss.ck, Buffer.alloc(0)) const cs1 = this.initializeKey(tempk1) const cs2 = this.initializeKey(tempk2) diff --git a/src/logger.ts b/src/logger.ts index 2cd1025..eda9715 100644 --- a/src/logger.ts +++ b/src/logger.ts @@ -1,7 +1,7 @@ import debug from 'debug' import { DUMP_SESSION_KEYS } from './constants' import { KeyPair } from './@types/libp2p' -import { NoiseSession, SymmetricState } from './@types/handshake' +import { NoiseSession } from './@types/handshake' export const logger = debug('libp2p:noise') diff --git a/src/noise.ts b/src/noise.ts index 1c97c0a..24d94b6 100644 --- a/src/noise.ts +++ b/src/noise.ts @@ -40,8 +40,8 @@ export class Noise implements INoiseConnection { /** * - * @param staticNoiseKey x25519 private key, reuse for faster handshakes - * @param earlyData + * @param {bytes} staticNoiseKey x25519 private key, reuse for faster handshakes + * @param {bytes} earlyData */ constructor (staticNoiseKey?: bytes, earlyData?: bytes) { this.earlyData = earlyData || Buffer.alloc(0) @@ -62,7 +62,7 @@ export class Noise implements INoiseConnection { /** * Encrypt outgoing data to the remote party (handshake as initiator) * @param {PeerId} localPeer - PeerId of the receiving peer - * @param connection - streaming iterable duplex that will be encrypted + * @param {any} connection - streaming iterable duplex that will be encrypted * @param {PeerId} remotePeer - PeerId of the remote peer. Used to validate the integrity of the remote peer. * @returns {Promise} */ @@ -93,7 +93,7 @@ export class Noise implements INoiseConnection { /** * Decrypt incoming data (handshake as responder). * @param {PeerId} localPeer - PeerId of the receiving peer. - * @param connection - streaming iterable duplex that will be encryption. + * @param {any} connection - streaming iterable duplex that will be encryption. * @param {PeerId} remotePeer - optional PeerId of the initiating peer, if known. This may only exist during transport upgrades. * @returns {Promise} */ @@ -124,7 +124,7 @@ export class Noise implements INoiseConnection { /** * If Noise pipes supported, tries IK handshake first with XX as fallback if it fails. * If noise pipes disabled or remote peer static key is unknown, use XX. - * @param params + * @param {HandshakeParams} params */ private async performHandshake (params: HandshakeParams): Promise { const payload = await getPayload(params.localPeer, this.staticKeys.publicKey, this.earlyData) diff --git a/src/utils.ts b/src/utils.ts index 144b4b3..b39b07f 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -36,11 +36,11 @@ export async function getPayload ( ) } -export async function createHandshakePayload ( +export function createHandshakePayload ( libp2pPublicKey: bytes, signedPayload: bytes, earlyData?: bytes -): Promise { +): bytes { const payloadInit = NoiseHandshakePayloadProto.create({ identityKey: libp2pPublicKey, identitySig: signedPayload, @@ -51,14 +51,14 @@ export async function createHandshakePayload ( } export async function signPayload (peerId: PeerId, payload: bytes): Promise { - return peerId.privKey.sign(payload) + return await peerId.privKey.sign(payload) } export async function getPeerIdFromPayload (payload: pb.INoiseHandshakePayload): Promise { return await PeerId.createFromPubKey(Buffer.from(payload.identityKey as Uint8Array)) } -export async function decodePayload (payload: bytes|Uint8Array): Promise { +export function decodePayload (payload: bytes|Uint8Array): pb.INoiseHandshakePayload { return NoiseHandshakePayloadProto.toObject( NoiseHandshakePayloadProto.decode(Buffer.from(payload)) ) as INoisePayload diff --git a/test/fixtures/peer.ts b/test/fixtures/peer.ts index 9b7b0fb..15f394a 100644 --- a/test/fixtures/peer.ts +++ b/test/fixtures/peer.ts @@ -19,16 +19,16 @@ const peers = [{ pubKey: 'CAESIMbnikZaPciAMZhUXqDRVCs7VFOBtmlIk26g0GgOotDA' }] -export async function createPeerIdsFromFixtures (length) { - return Promise.all( +export async function createPeerIdsFromFixtures (length:number): Promise { + return await Promise.all( Array.from({ length }).map((_, i) => PeerId.createFromJSON(peers[i])) ) } -export async function createPeerIds (length) { - const peerIds: any[] = [] +export async function createPeerIds (length: number): Promise { + const peerIds: PeerId[] = [] for (let i = 0; i < length; i++) { - const id = await PeerId.create({ keyType: 'ed25519', bits: 256 }) + const id = await PeerId.create({ keyType: 'Ed25519', bits: 256 }) peerIds.push(id) } diff --git a/test/handshakes/ik.spec.ts b/test/handshakes/ik.spec.ts index 07b1b3a..f33eb54 100644 --- a/test/handshakes/ik.spec.ts +++ b/test/handshakes/ik.spec.ts @@ -29,7 +29,7 @@ describe('IK handshake', () => { // initiator creates payload const initSignedPayload = await libp2pInitKeys.sign(getHandshakePayload(kpInitiator.publicKey)) - const libp2pInitPrivKey = libp2pInitKeys.marshal().slice(0, 32) + libp2pInitKeys.marshal().slice(0, 32) const libp2pInitPubKey = libp2pInitKeys.marshal().slice(32, 64) const payloadInitEnc = await createHandshakePayload(libp2pInitPubKey, initSignedPayload) @@ -40,12 +40,12 @@ describe('IK handshake', () => { expect(messageBuffer.ne.length).not.equal(0) // responder receives message - const plaintext = ikR.recvMessage(responderSession, messageBuffer) + ikR.recvMessage(responderSession, messageBuffer) /* Stage 1 */ // responder creates payload - const libp2pRespPrivKey = libp2pRespKeys.marshal().slice(0, 32) + libp2pRespKeys.marshal().slice(0, 32) const libp2pRespPubKey = libp2pRespKeys.marshal().slice(32, 64) const respSignedPayload = await libp2pRespKeys.sign(getHandshakePayload(kpResponder.publicKey)) const payloadRespEnc = await createHandshakePayload(libp2pRespPubKey, respSignedPayload) @@ -54,12 +54,11 @@ describe('IK handshake', () => { const messageBuffer2 = ikR.sendMessage(responderSession, message1) // initiator receives message - const plaintext2 = ikI.recvMessage(initiatorSession, messageBuffer2) + ikI.recvMessage(initiatorSession, messageBuffer2) - assert(initiatorSession.cs1.k.equals(responderSession.cs1.k)) - assert(initiatorSession.cs2.k.equals(responderSession.cs2.k)) + assert(initiatorSession?.cs1?.k.equals(responderSession?.cs1?.k || new Uint8Array())) + assert(initiatorSession?.cs2?.k.equals(responderSession?.cs2?.k || new Uint8Array())) } catch (e) { - console.error(e) return assert(false, e.message) } }) diff --git a/test/handshakes/xx.spec.ts b/test/handshakes/xx.spec.ts index 9b3836e..c2d345c 100644 --- a/test/handshakes/xx.spec.ts +++ b/test/handshakes/xx.spec.ts @@ -14,15 +14,15 @@ describe('XX Handshake', () => { const xx = new XX() const kpInitiator: KeyPair = await generateKeypair() - const kpResponder: KeyPair = await generateKeypair() + await generateKeypair() - const session = await xx.initSession(true, prologue, kpInitiator) + await xx.initSession(true, prologue, kpInitiator) } catch (e) { assert(false, e.message) } }) - it('Test get HKDF', async () => { + it('Test get HKDF', () => { const ckBytes = Buffer.from('4e6f6973655f58585f32353531395f58436861436861506f6c795f53484132353600000000000000000000000000000000000000000000000000000000000000', 'hex') const ikm = Buffer.from('a3eae50ea37a47e8a7aa0c7cd8e16528670536dcd538cebfd724fb68ce44f1910ad898860666227d4e8dd50d22a9a64d1c0a6f47ace092510161e9e442953da3', 'hex') const ck = Buffer.alloc(32) @@ -54,7 +54,7 @@ describe('XX Handshake', () => { /* STAGE 0 */ // initiator creates payload - const libp2pInitPrivKey = libp2pInitKeys.marshal().slice(0, 32) + libp2pInitKeys.marshal().slice(0, 32) const libp2pInitPubKey = libp2pInitKeys.marshal().slice(32, 64) const payloadInitEnc = await createHandshakePayload(libp2pInitPubKey, initSignedPayload) @@ -71,7 +71,7 @@ describe('XX Handshake', () => { /* STAGE 1 */ // responder creates payload - const libp2pRespPrivKey = libp2pRespKeys.marshal().slice(0, 32) + libp2pRespKeys.marshal().slice(0, 32) const libp2pRespPubKey = libp2pRespKeys.marshal().slice(32, 64) const payloadRespEnc = await createHandshakePayload(libp2pRespPubKey, respSignedPayload) diff --git a/test/ik-handshake.spec.ts b/test/ik-handshake.spec.ts index 0a8b43f..3388e84 100644 --- a/test/ik-handshake.spec.ts +++ b/test/ik-handshake.spec.ts @@ -8,10 +8,10 @@ import { generateKeypair, getPayload } from '../src/utils' import { IKHandshake } from '../src/handshake-ik' describe('IK Handshake', () => { - let peerA, peerB, fakePeer + let peerA, peerB before(async () => { - [peerA, peerB, fakePeer] = await createPeerIdsFromFixtures(3) + [peerA, peerB] = await createPeerIdsFromFixtures(3) }) it('should finish both stages as initiator and responder', async () => { @@ -49,7 +49,6 @@ describe('IK Handshake', () => { const { plaintext: decrypted } = handshakeResp.decrypt(encrypted, handshakeResp.session) assert(decrypted.equals(Buffer.from('encryptthis'))) } catch (e) { - console.error(e) assert(false, e.message) } }) diff --git a/test/keycache.spec.ts b/test/keycache.spec.ts index 487a446..6c175eb 100644 --- a/test/keycache.spec.ts +++ b/test/keycache.spec.ts @@ -1,12 +1,12 @@ -import { expect, assert } from 'chai' +import { assert } from 'chai' import { KeyCache } from '../src/keycache' import { createPeerIds, createPeerIdsFromFixtures } from './fixtures/peer' describe('KeyCache', () => { - let peerA, peerB + let peerA before(async () => { - [peerA, peerB] = await createPeerIdsFromFixtures(2) + [peerA] = await createPeerIdsFromFixtures(2) }) it('should store and load same key successfully', async () => { @@ -14,9 +14,8 @@ describe('KeyCache', () => { const key = Buffer.from('this is id 007') await KeyCache.store(peerA, key) const result = await KeyCache.load(peerA) - assert(result.equals(key), 'Stored and loaded key are not the same') + assert(result?.equals(key), 'Stored and loaded key are not the same') } catch (e) { - console.error(e) assert(false, `Test failed - ${e.message}`) } }) @@ -27,7 +26,6 @@ describe('KeyCache', () => { const result = await KeyCache.load(newPeer) assert(!result) } catch (e) { - console.error(e) assert(false, `Test failed - ${e.message}`) } }) diff --git a/test/noise.spec.ts b/test/noise.spec.ts index dae1c0d..e0c7fe8 100644 --- a/test/noise.spec.ts +++ b/test/noise.spec.ts @@ -30,8 +30,8 @@ describe('Noise', () => { it('should communicate through encrypted streams without noise pipes', async () => { try { - const noiseInit = new Noise(undefined, undefined, false) - const noiseResp = new Noise(undefined, undefined, false) + const noiseInit = new Noise(undefined, undefined) + const noiseResp = new Noise(undefined, undefined) const [inboundConnection, outboundConnection] = DuplexPair() const [outbound, inbound] = await Promise.all([ @@ -50,7 +50,7 @@ describe('Noise', () => { }) it('should test that secureOutbound is spec compliant', async () => { - const noiseInit = new Noise(undefined, undefined, false) + const noiseInit = new Noise(undefined, undefined) const [inboundConnection, outboundConnection] = DuplexPair() const [outbound, { wrapped, handshake }] = await Promise.all([ @@ -111,8 +111,8 @@ describe('Noise', () => { it('should test large payloads', async function () { this.timeout(10000) try { - const noiseInit = new Noise(undefined, undefined, false) - const noiseResp = new Noise(undefined, undefined, false) + const noiseInit = new Noise(undefined, undefined) + const noiseResp = new Noise(undefined, undefined) const [inboundConnection, outboundConnection] = DuplexPair() const [outbound, inbound] = await Promise.all([ @@ -128,7 +128,6 @@ describe('Noise', () => { expect(response.length).equals(largePlaintext.length) } catch (e) { - console.log(e) assert(false, e.message) } }) @@ -162,7 +161,6 @@ describe('Noise', () => { assert(xxSpy.notCalled) assert(xxFallbackSpy.notCalled) } catch (e) { - console.error(e) assert(false, e.message) } }) @@ -194,7 +192,6 @@ describe('Noise', () => { assert(xxSpy.calledOnce, 'XX Fallback method was never called.') } catch (e) { - console.error(e) assert(false, e.message) } }) @@ -228,7 +225,6 @@ describe('Noise', () => { assert(xxSpy.calledOnce, 'XX Fallback method was never called.') } catch (e) { - console.error(e) assert(false, e.message) } }) @@ -263,7 +259,6 @@ describe('Noise', () => { assert(xxInitSpy.calledOnce, 'XX method was never called.') assert(xxRespSpy.calledOnce, 'XX Fallback method was never called.') } catch (e) { - console.error(e) assert(false, e.message) } }) @@ -301,7 +296,6 @@ describe('Noise', () => { assert(ikRespSpy.calledOnce, 'IK handshake was not called.') assert(xxFallbackInitSpy.notCalled, 'XX Fallback method was called.') } catch (e) { - console.error(e) assert(false, e.message) } }) @@ -332,7 +326,6 @@ describe('Noise', () => { assert(inbound.remotePeer.marshalPubKey().equals(localPeer.marshalPubKey())) assert(outbound.remotePeer.marshalPubKey().equals(remotePeer.marshalPubKey())) } catch (e) { - console.error(e) assert(false, e.message) } }) @@ -358,7 +351,6 @@ describe('Noise', () => { assert(inbound.remoteEarlyData.equals(localPeerEarlyData)) assert(outbound.remoteEarlyData.equals(Buffer.alloc(0))) } catch (e) { - console.error(e) assert(false, e.message) } }) diff --git a/test/utils.ts b/test/utils.ts index af3cf4e..4042ef9 100644 --- a/test/utils.ts +++ b/test/utils.ts @@ -1,9 +1,9 @@ -import { keys } from 'libp2p-crypto' +import { keys, PrivateKey } from 'libp2p-crypto' import { KeyPair } from '../src/@types/libp2p' import PeerId from 'peer-id' -export async function generateEd25519Keys () { - return await keys.generateKeyPair('ed25519') +export async function generateEd25519Keys (): Promise { + return await keys.generateKeyPair('Ed25519', 32) } export function getKeyPairFromPeerId (peerId: PeerId): KeyPair { diff --git a/test/xx-fallback-handshake.spec.ts b/test/xx-fallback-handshake.spec.ts index 0fff966..6dabb02 100644 --- a/test/xx-fallback-handshake.spec.ts +++ b/test/xx-fallback-handshake.spec.ts @@ -9,10 +9,10 @@ import { import { XXFallbackHandshake } from '../src/handshake-xx-fallback' import { createPeerIdsFromFixtures } from './fixtures/peer' import { assert } from 'chai' -import { decode1, encode0, encode1 } from '../src/encoder' +import { encode0 } from '../src/encoder' describe('XX Fallback Handshake', () => { - let peerA, peerB, fakePeer + let peerA, peerB before(async () => { [peerA, peerB] = await createPeerIdsFromFixtures(2) @@ -67,7 +67,6 @@ describe('XX Fallback Handshake', () => { assert(false) } } catch (e) { - console.error(e) assert(false, e.message) } }) From e16e25cbef3b96eab14ffd313c362df79e36b8fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marin=20Petruni=C4=87?= Date: Fri, 19 Jun 2020 13:12:23 +0200 Subject: [PATCH 04/11] add missing karma plugin --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index e1e2eb2..ed5b04d 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,7 @@ "@types/mocha": "^5.2.7", "aegir": "ipfs/aegir#feat/cosmiconfig", "chai": "^4.2.0", + "karma-mocha-webworker": "^1.3.0", "mocha": "^6.2.2", "sinon": "^8.1.0" }, From 153f51ae5a403ec90ae42181aa7f185d7bace801 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marin=20Petruni=C4=87?= Date: Fri, 19 Jun 2020 13:23:18 +0200 Subject: [PATCH 05/11] fix type errors --- src/@types/it-length-prefixed/index.d.ts | 13 ++++++------- src/encoder.ts | 5 +++-- src/errors.ts | 8 +++++--- 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/src/@types/it-length-prefixed/index.d.ts b/src/@types/it-length-prefixed/index.d.ts index 9dc8269..99de1ad 100644 --- a/src/@types/it-length-prefixed/index.d.ts +++ b/src/@types/it-length-prefixed/index.d.ts @@ -1,7 +1,6 @@ -declare module "it-length-prefixed" { - /* eslint-disable @typescript-eslint/interface-name-prefix */ - import BufferList from "bl"; - import {Buffer} from "buffer" +declare module 'it-length-prefixed' { + import BufferList from 'bl' + import { Buffer } from 'buffer' interface LengthDecoderFunction { (data: Buffer | BufferList): number; @@ -9,7 +8,7 @@ declare module "it-length-prefixed" { } interface LengthEncoderFunction { - (value: Buffer, target: number, offset: number): number|Buffer; + (value: number, target: Buffer, offset: number): number|Buffer; bytes: number; } @@ -33,7 +32,7 @@ declare module "it-length-prefixed" { MAX_DATA_LENGTH: number; } - export const encode: Encoder; - export const decode: Decoder; + export const encode: Encoder + export const decode: Decoder } diff --git a/src/encoder.ts b/src/encoder.ts index f60ea3a..3afc00a 100644 --- a/src/encoder.ts +++ b/src/encoder.ts @@ -1,15 +1,16 @@ import { Buffer } from 'buffer' import { bytes } from './@types/basic' import { MessageBuffer } from './@types/handshake' +import BufferList from 'bl' -export const uint16BEEncode = (value: number, target: bytes, offset: number): bytes => { +export const uint16BEEncode = (value: number, target: Buffer, offset: number): Buffer => { target = target || Buffer.allocUnsafe(2) target.writeUInt16BE(value, offset) return target } uint16BEEncode.bytes = 2 -export const uint16BEDecode = (data: bytes): number => { +export const uint16BEDecode = (data: Buffer | BufferList): number => { if (data.length < 2) throw RangeError('Could not decode int16BE') return data.readUInt16BE(0) } diff --git a/src/errors.ts b/src/errors.ts index e04d520..5738e3a 100644 --- a/src/errors.ts +++ b/src/errors.ts @@ -1,7 +1,9 @@ -export class FailedIKError extends Error { - public initialMsg: string; +import BufferList from 'bl' - constructor (initialMsg: string, message?: string) { +export class FailedIKError extends Error { + public initialMsg: string|BufferList|Buffer; + + constructor (initialMsg: string|BufferList|Buffer, message?: string) { super(message) this.initialMsg = initialMsg From d01d6f428a3032bcf7a2a8a0901d456e83670fcb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marin=20Petruni=C4=87?= Date: Fri, 19 Jun 2020 13:32:32 +0200 Subject: [PATCH 06/11] fix error because original types are invalid --- src/noise.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/noise.ts b/src/noise.ts index 24d94b6..390450a 100644 --- a/src/noise.ts +++ b/src/noise.ts @@ -70,6 +70,9 @@ export class Noise implements INoiseConnection { const wrappedConnection = Wrap( connection, { + // wrong types in repo + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore lengthEncoder: uint16BEEncode, lengthDecoder: uint16BEDecode, maxDataLength: NOISE_MSG_MAX_LENGTH_BYTES @@ -101,6 +104,9 @@ export class Noise implements INoiseConnection { const wrappedConnection = Wrap( connection, { + // wrong types in repo + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore lengthEncoder: uint16BEEncode, lengthDecoder: uint16BEDecode, maxDataLength: NOISE_MSG_MAX_LENGTH_BYTES From 9dc300c65ef19efbb09b66915f86e8195ab86e53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marin=20Petruni=C4=87?= Date: Tue, 23 Jun 2020 10:12:58 +0200 Subject: [PATCH 07/11] fix tests and Pr comments --- package.json | 8 ++++---- yarn.lock | 13 ++++--------- 2 files changed, 8 insertions(+), 13 deletions(-) diff --git a/package.json b/package.json index ed5b04d..39c678c 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "libp2p-noise", "version": "1.1.2", "main": "dist/src/index.js", - "types": "dist/src/dist/index.d.ts", + "types": "dist/src/index.d.ts", "files": [ "dist", "src" @@ -19,16 +19,16 @@ "build": "aegir build --ts", "lint": "aegir lint --ts", "lint:fix": "aegir lint --ts --fix", - "test": "aegir test --ts", + "test": "aegir test --ts --node true", "test:node": "aegir test -t node --ts", - "test:browser": "aegir test -t browser --ts", + "test:browser": "aegir test -t browser --node true --ts", "proto:gen": "pbjs -t static-module -o ./src/proto/payload.js ./src/proto/payload.proto && pbts -o ./src/proto/payload.d.ts ./src/proto/payload.js && yarn run lint --fix" }, "devDependencies": { "@types/bl": "^2.1.0", "@types/chai": "^4.2.4", "@types/mocha": "^5.2.7", - "aegir": "ipfs/aegir#feat/cosmiconfig", + "aegir": "25.0.0", "chai": "^4.2.0", "karma-mocha-webworker": "^1.3.0", "mocha": "^6.2.2", diff --git a/yarn.lock b/yarn.lock index 3bf756c..da52fa9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1803,9 +1803,10 @@ add-stream@^1.0.0: resolved "https://registry.yarnpkg.com/add-stream/-/add-stream-1.0.0.tgz#6a7990437ca736d5e1288db92bd3266d5f5cb2aa" integrity sha1-anmQQ3ynNtXhKI25K9MmbV9csqo= -aegir@ipfs/aegir#feat/cosmiconfig: - version "24.0.0" - resolved "https://codeload.github.com/ipfs/aegir/tar.gz/15d895f22055023a78d704c8beabbd45c35a8f61" +aegir@25.0.0: + version "25.0.0" + resolved "https://registry.yarnpkg.com/aegir/-/aegir-25.0.0.tgz#9275c4dba0717355ee20c1c35cb27f474fadcca9" + integrity sha512-VP1ACVfnUj/k/kwc/W74IOFKVurPsN3BmWxtbxVpr7hLkOoi3/OYBaaROeVndmUiOHihye1PLQUAMpHROgRpeg== dependencies: "@babel/cli" "^7.10.1" "@babel/core" "^7.10.2" @@ -1849,7 +1850,6 @@ aegir@ipfs/aegir#feat/cosmiconfig: eslint-plugin-node "^11.0.0" eslint-plugin-promise "^4.2.1" eslint-plugin-standard "^4.0.1" - esm "^3.2.25" execa "^4.0.0" extract-zip "^2.0.1" findup-sync "^4.0.0" @@ -4595,11 +4595,6 @@ eslint@^6.3.0: text-table "^0.2.0" v8-compile-cache "^2.0.3" -esm@^3.2.25: - version "3.2.25" - resolved "https://registry.yarnpkg.com/esm/-/esm-3.2.25.tgz#342c18c29d56157688ba5ce31f8431fbb795cc10" - integrity sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA== - espree@^6.1.2: version "6.2.1" resolved "https://registry.yarnpkg.com/espree/-/espree-6.2.1.tgz#77fc72e1fd744a2052c20f38a5b575832e82734a" From c928cc1514e6dadbf03da145c5c98711d2c2000b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marin=20Petruni=C4=87?= Date: Tue, 23 Jun 2020 10:18:05 +0200 Subject: [PATCH 08/11] add node globals in ci --- .travis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 33aa9fc..351aaff 100644 --- a/.travis.yml +++ b/.travis.yml @@ -29,13 +29,13 @@ jobs: name: chrome addons: chrome: stable - script: npx aegir test -t browser -t webworker --ts + script: npx aegir test -t browser -t webworker --node true --ts - stage: test name: firefox addons: firefox: latest - script: npx aegir test -t browser -t webworker --ts -- --browsers FirefoxHeadless + script: npx aegir test -t browser -t webworker --ts --node true -- --browsers FirefoxHeadless - stage: test name: electron-main @@ -47,7 +47,7 @@ jobs: name: electron-renderer os: osx script: - - npx aegir test -t electron-renderer --bail --ts + - npx aegir test -t electron-renderer --node true --bail --ts notifications: email: false From fd1cc28f416226722a1151cb7e46b533c24c8940 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marin=20Petruni=C4=87?= Date: Tue, 23 Jun 2020 10:56:03 +0200 Subject: [PATCH 09/11] publish codecov only from single matrix --- .travis.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 351aaff..fd12189 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,7 +15,9 @@ os: - windows script: npx nyc -s yarn run test:node --bail -after_success: npx nyc report --reporter=text-lcov > coverage.lcov && npx codecov +after_success: + - npm install -g travis-deploy-once + - travis-deploy-once "npx nyc report --reporter=text-lcov > coverage.lcov && npx codecov" jobs: include: From e9bc0dbe44e80a5281ddff21d5e9163b5c8f6dd5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marin=20Petruni=C4=87?= Date: Tue, 23 Jun 2020 11:11:39 +0200 Subject: [PATCH 10/11] run codecov only on linux --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index fd12189..555ec9d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,7 +17,7 @@ os: script: npx nyc -s yarn run test:node --bail after_success: - npm install -g travis-deploy-once - - travis-deploy-once "npx nyc report --reporter=text-lcov > coverage.lcov && npx codecov" + - if [ "$TRAVIS_OS_NAME" = "linux" ]; then travis-deploy-once "npx nyc report --reporter=text-lcov > coverage.lcov && npx codecov"; fi jobs: include: From 40b547a6b1c2e0d60f841a439a0334c1bbb31a25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marin=20Petruni=C4=87?= Date: Tue, 23 Jun 2020 12:00:01 +0200 Subject: [PATCH 11/11] fix travis windows --- .travis.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.travis.yml b/.travis.yml index 555ec9d..fc1a2fb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,6 +5,9 @@ stages: - test - cov +env: + - YARN_GPG=no + node_js: - '12' - '14'