From 7d22967197790bc3473749e4e61c8710f23b7b87 Mon Sep 17 00:00:00 2001 From: Belma Gutlic Date: Mon, 13 Jan 2020 16:33:58 +0100 Subject: [PATCH] Use static key caching --- src/handshake-ik.ts | 7 ++----- src/handshake-xx.ts | 4 ++++ src/handshakes/xx.ts | 1 - src/keycache.ts | 4 ++-- src/noise.ts | 26 ++++++++++++++++---------- test/noise.test.ts | 10 +++++----- 6 files changed, 29 insertions(+), 23 deletions(-) diff --git a/src/handshake-ik.ts b/src/handshake-ik.ts index f13e711..9ce370a 100644 --- a/src/handshake-ik.ts +++ b/src/handshake-ik.ts @@ -24,6 +24,7 @@ export class IKHandshake implements IHandshake { staticKeypair: KeyPair, connection: WrappedConnection, remotePeer: PeerId, + remoteStaticKey: bytes, handshake?: IK, ) { this.isInitiator = isInitiator; @@ -34,11 +35,7 @@ export class IKHandshake implements IHandshake { this.remotePeer = remotePeer; this.ik = handshake || new IK(); - - // Dummy data - // TODO: Load remote static keys if found - const remoteStaticKeys = this.staticKeypair; - this.session = this.ik.initSession(this.isInitiator, this.prologue, this.staticKeypair, remoteStaticKeys.publicKey); + this.session = this.ik.initSession(this.isInitiator, this.prologue, this.staticKeypair, remoteStaticKey); } public decrypt(ciphertext: Buffer, session: NoiseSession): Buffer { diff --git a/src/handshake-xx.ts b/src/handshake-xx.ts index 7f6f1bf..5f42238 100644 --- a/src/handshake-xx.ts +++ b/src/handshake-xx.ts @@ -114,6 +114,10 @@ export class XXHandshake implements IHandshake { return this.xx.decryptWithAd(cs, Buffer.alloc(0), ciphertext); } + public getRemoteStaticKey(): bytes { + return this.session.hs.rs; + } + private getCS(session: NoiseSession, encryption = true) { if (!session.cs1 || !session.cs2) { throw new Error("Handshake not completed properly, cipher state does not exist."); diff --git a/src/handshakes/xx.ts b/src/handshakes/xx.ts index 110dc7e..6362bab 100644 --- a/src/handshakes/xx.ts +++ b/src/handshakes/xx.ts @@ -145,7 +145,6 @@ export class XX extends AbstractHandshake { session.h = h; session.cs1 = cs1; session.cs2 = cs2; - delete session.hs; } else if (session.mc.gtn(2)) { if (session.i) { if (!session.cs1) { diff --git a/src/keycache.ts b/src/keycache.ts index 8c0241f..ea65a94 100644 --- a/src/keycache.ts +++ b/src/keycache.ts @@ -20,11 +20,11 @@ class Keycache { } } - public async load(peerId: PeerId): Promise { + public async load(peerId: PeerId): Promise { const release = await this.mutex.acquire(); let key; try { - key = this.storage.get(peerId.id); + key = this.storage.get(peerId.id) || null; } finally { release(); } diff --git a/src/noise.ts b/src/noise.ts index 0810f67..0a2a7a0 100644 --- a/src/noise.ts +++ b/src/noise.ts @@ -16,6 +16,8 @@ import { bytes } from "./@types/basic"; import { INoiseConnection, PeerId, KeyPair, SecureOutbound } from "./@types/libp2p"; import { Duplex } from "./@types/it-pair"; import {IHandshake} from "./@types/handshake-interface"; +import {KeyCache} from "./keycache"; +import {logger} from "./logger"; export type WrappedConnection = ReturnType; @@ -104,14 +106,21 @@ export class Noise implements INoiseConnection { * @param remotePeer */ private async performHandshake(params: HandshakeParams): Promise { - // TODO: Implement noise pipes const payload = await getPayload(params.localPeer, this.staticKeys.publicKey, this.earlyData); - if (false) { - let IKhandshake; + let foundRemoteStaticKey: bytes|null = null; + if (this.useNoisePipes && params.isInitiator) { + logger("Initiator using noise pipes. Going to load cached static key..."); + foundRemoteStaticKey = await KeyCache.load(params.remotePeer); + logger(`Static key has been found: ${!!foundRemoteStaticKey}`) + } + + if (foundRemoteStaticKey) { + // Try IK first + const { remotePeer, connection, isInitiator } = params; + const IKhandshake = new IKHandshake(isInitiator, payload, this.prologue, this.staticKeys, connection, remotePeer, foundRemoteStaticKey); try { - IKhandshake = await this.performIKHandshake(params, payload); - return IKhandshake; + return await this.performIKHandshake(IKhandshake, payload); } catch (e) { // XX fallback const ephemeralKeys = IKhandshake.getRemoteEphemeralKeys(); @@ -156,7 +165,7 @@ export class Noise implements INoiseConnection { await handshake.finish(); if (this.useNoisePipes) { - + await KeyCache.store(remotePeer, handshake.getRemoteStaticKey()); } } catch (e) { throw new Error(`Error occurred during XX handshake: ${e.message}`); @@ -166,12 +175,9 @@ export class Noise implements INoiseConnection { } private async performIKHandshake( - params: HandshakeParams, + handshake: IKHandshake, payload: bytes, ): Promise { - const { isInitiator, remotePeer, connection } = params; - const handshake = new IKHandshake(isInitiator, payload, this.prologue, this.staticKeys, connection, remotePeer); - // TODO return handshake; diff --git a/test/noise.test.ts b/test/noise.test.ts index dcf790f..872f825 100644 --- a/test/noise.test.ts +++ b/test/noise.test.ts @@ -26,8 +26,8 @@ describe("Noise", () => { it("should communicate through encrypted streams", async() => { try { - const noiseInit = new Noise(); - const noiseResp = new Noise(); + const noiseInit = new Noise(undefined, undefined, false); + const noiseResp = new Noise(undefined, undefined, false); const [inboundConnection, outboundConnection] = DuplexPair(); const [outbound, inbound] = await Promise.all([ @@ -46,7 +46,7 @@ describe("Noise", () => { }); it("should test that secureOutbound is spec compliant", async() => { - const noiseInit = new Noise(); + const noiseInit = new Noise(undefined, undefined, false); const [inboundConnection, outboundConnection] = DuplexPair(); const [outbound, { wrapped, handshake }] = await Promise.all([ @@ -99,8 +99,8 @@ describe("Noise", () => { it("should test large payloads", async() => { try { - const noiseInit = new Noise(); - const noiseResp = new Noise(); + const noiseInit = new Noise(undefined, undefined, false); + const noiseResp = new Noise(undefined, undefined, false); const [inboundConnection, outboundConnection] = DuplexPair(); const [outbound, inbound] = await Promise.all([