Address PR comments

This commit is contained in:
morrigan
2019-11-20 13:23:36 +01:00
parent 4d09d63a4a
commit ca4e2777ff
12 changed files with 104 additions and 110 deletions

6
src/@types/it-pair/index.d.ts vendored Normal file
View File

@ -0,0 +1,6 @@
export type Duplex = [Stream, Stream];
type Stream = {
sink(source: Iterable<any>),
source: Object,
}

24
src/@types/libp2p.ts Normal file
View File

@ -0,0 +1,24 @@
import { bytes, bytes32 } from "./basic";
import { Duplex } from "it-pair";
export interface KeyPair {
publicKey: bytes32,
privateKey: bytes32,
}
export type PeerId = {
id: string,
privKey: string,
pubKey: string,
};
export interface NoiseConnection {
remoteEarlyData?(): bytes,
secureOutbound(localPeer: PeerId, insecure: any, remotePeer: PeerId): Promise<SecureOutbound>,
secureInbound(remotePeer: PeerId, insecure: any): Promise<SecureOutbound>,
}
export type SecureOutbound = {
conn: Duplex,
remotePeer: PeerId,
}

View File

@ -1,13 +1,13 @@
import { Duplex } from "./types/libp2p";
import { Duplex } from "it-pair";
import { NoiseSession } from "./xx";
// Send encrypted payload from the user to stream
export async function encryptStreams(streams: Duplex, session: NoiseSession) : Promise<void> {
export async function encryptStreams(streams: Duplex, session: NoiseSession) : Promise<Duplex> {
}
// Decrypt received payload from the stream and pipe to user
export async function decryptStreams(streams: Duplex, session: NoiseSession) : Promise<void> {
export async function decryptStreams(streams: Duplex, session: NoiseSession) : Promise<Duplex> {
}

View File

@ -1,19 +1,43 @@
import { bytes, bytes32 } from "./types/basic";
import { bytes, bytes32 } from "./@types/basic";
import { NoiseSession, XXHandshake } from "./xx";
import { KeyPair } from "./types/libp2p";
import { KeyPair, PeerId } from "./@types/libp2p";
type handshakeType = "XX";
export class Handshake {
static async runXX(
isInitiator: boolean,
private type: handshakeType;
private remotePublicKey: bytes;
private signedPayload: bytes;
private prologue: bytes32;
private staticKeys: KeyPair;
constructor(
type: handshakeType,
remotePublicKey: bytes,
prologue: bytes32,
signedPayload: bytes,
staticKeys: KeyPair,
) : Promise<NoiseSession> {
) {
this.type = type;
this.remotePublicKey = remotePublicKey;
this.signedPayload = signedPayload;
this.prologue = prologue;
this.staticKeys = staticKeys;
}
async propose(isInitiator: boolean) : Promise<NoiseSession> {
const xx = new XXHandshake();
const nsInit = await xx.initSession(isInitiator, prologue, staticKeys, remotePublicKey);
const nsInit = await xx.initSession(isInitiator, this.prologue, this.staticKeys, this.remotePublicKey);
// TODO: exchange handshake messages and confirm handshake
return nsInit;
}
async exchange() : Promise<NoiseSession> {
}
async finish() : Promise<NoiseSession> {
}
}

View File

@ -1,5 +1 @@
import { Noise } from './noise';
export {
Noise,
}
export * from "./noise";

View File

@ -1,14 +1,17 @@
import { x25519 } from 'bcrypto';
import { Buffer } from "buffer";
import { bytes } from "./types/basic";
import { InsecureConnection, NoiseConnection, PeerId, SecureConnection, KeyPair } from "./types/libp2p";
import { bytes } from "./@types/basic";
import {NoiseConnection, PeerId, KeyPair, SecureOutbound} from "./@types/libp2p";
import { Handshake } from "./handshake";
import { generateKeypair, signPayload } from "./utils";
import { encryptStreams } from "./crypto";
import { decryptStreams, encryptStreams } from "./crypto";
import {Duplex} from "./@types/it-pair";
export class Noise implements NoiseConnection {
public protocol = "/noise";
private readonly privateKey: bytes;
private staticKeys: KeyPair;
private earlyData?: bytes;
@ -28,29 +31,38 @@ export class Noise implements NoiseConnection {
}
}
public protocol() {
return '/noise';
}
// encrypt outgoing data to the remote party (handshake as initiator)
public async secureOutbound(connection: InsecureConnection, remotePeer: PeerId) : Promise<SecureConnection> {
try {
const remotePublicKey = Buffer.from(remotePeer.pubKey);
const session = await this.createSecureConnection(connection, remotePublicKey, true);
} catch (e) {
/**
* 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 {PeerId} remotePeer - PeerId of the remote peer. Used to validate the integrity of the remote peer.
* @returns {Promise<SecureOutbound>}
*/
public async secureOutbound(localPeer: PeerId, connection: any, remotePeer: PeerId) : Promise<SecureOutbound> {
const remotePublicKey = Buffer.from(remotePeer.pubKey);
const session = await this.createSecureConnection(connection, remotePublicKey, true);
return {
conn: session,
remotePeer,
}
}
// decrypt incoming data (handshake as responder)
public async secureInbound(connection: InsecureConnection) : Promise<SecureConnection> {
/**
* Decrypt incoming data (handshake as responder).
* @param {PeerId} localPeer - PeerId of the receiving peer.
* @param 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<SecureOutbound>}
*/
public async secureInbound(localPeer: PeerId, connection: any, remotePeer?: PeerId) : Promise<SecureOutbound> {
}
private async createSecureConnection(
connection: InsecureConnection,
connection: Duplex,
remotePublicKey: bytes,
isInitiator: boolean,
) : Promise<SecureConnection> {
) : Promise<Duplex> {
if (!this.staticKeys) {
this.staticKeys = await generateKeypair();
}
@ -61,20 +73,11 @@ export class Noise implements NoiseConnection {
signedPayload = await signPayload(this.privateKey, payload);
}
const prologue = Buffer.from(this.protocol());
const session = await Handshake.runXX(isInitiator, remotePublicKey, prologue, signedPayload, this.staticKeys);
const prologue = Buffer.from(this.protocol);
const handshake = new Handshake('XX', remotePublicKey, prologue, signedPayload, this.staticKeys)
const session = await handshake.propose(isInitiator);
await encryptStreams(connection.streams(), session);
return {
...connection,
initiator: isInitiator,
prologue,
localKey: Buffer.alloc(0), // get libp2p public key,
xxNoiseSession: session,
xxComplete: true,
noiseKeypair: this.staticKeys,
}
return await encryptStreams(connection, session);
}

View File

@ -1,60 +0,0 @@
import { bytes, bytes32 } from "./basic";
import { NoiseSession } from "../xx";
export interface KeyPair {
publicKey: bytes32,
privateKey: bytes32,
}
export type PeerId = {
id: string,
privKey: string,
pubKey: string,
};
type PeerInfo = {
noiseKey: bytes32,
libp2pKey: bytes,
};
type ConnectionStats = {
direction: "inbound" | "outbound",
encryption: string,
}
// Also seen as Pair
export type Stream = {
sink(source: Iterable<any>),
source: Object,
}
export type Duplex = [Stream, Stream];
export interface InsecureConnection {
localPeer: PeerId,
remotePeer: PeerId,
local: PeerInfo,
remote: PeerInfo,
stats: ConnectionStats,
streams(): Duplex,
addStream(muxedStream: any) : Stream,
}
export interface NoiseConnection {
remoteEarlyData?(): bytes,
secureOutbound(insecure: InsecureConnection, remotePeer: PeerId): Promise<SecureConnection>,
secureInbound(insecure: InsecureConnection): Promise<SecureConnection>,
}
export interface SecureConnection {
initiator: boolean,
prologue: bytes32,
localKey: bytes,
xxNoiseSession: NoiseSession,
xxComplete: boolean,
noiseKeypair: KeyPair,
}

View File

@ -1,8 +1,8 @@
import { x25519 } from 'bcrypto';
import * as crypto from 'libp2p-crypto';
import { KeyPair } from "./types/libp2p";
import { bytes } from "./types/basic";
import { KeyPair } from "./@types/libp2p";
import { bytes } from "./@types/basic";
export async function generateKeypair() : Promise<KeyPair> {
const privateKey = x25519.privateKeyGenerate();

View File

@ -2,8 +2,8 @@ import { Buffer } from 'buffer';
import { AEAD, x25519, HKDF, SHA256 } from 'bcrypto';
import { BN } from 'bn.js';
import { bytes32, uint32, uint64, bytes } from './types/basic'
import { KeyPair } from './types/libp2p'
import { bytes32, uint32, uint64, bytes } from './@types/basic'
import { KeyPair } from './@types/libp2p'
import { generateKeypair } from './utils';

View File

@ -4,7 +4,7 @@ import { Noise } from "../src";
describe("Index", () => {
it("should expose class with tag and required functions", () => {
const noise = new Noise(Buffer.from("privatekey"));
expect(noise.protocol()).to.equal('/noise');
expect(noise.protocol).to.equal('/noise');
expect(typeof(noise.secureInbound)).to.equal('function');
expect(typeof(noise.secureOutbound)).to.equal('function');
})

View File

@ -7,7 +7,8 @@
"noImplicitAny": false,
"typeRoots": [
"./node_modules/@types",
"./node_modules/bn.js-typings/index.d.ts"
"./node_modules/bn.js-typings/index.d.ts",
"./src/@types"
]
},
"include": [