mirror of
https://github.com/fluencelabs/js-libp2p-noise
synced 2025-06-10 20:11:39 +00:00
Address PR comments
This commit is contained in:
6
src/@types/it-pair/index.d.ts
vendored
Normal file
6
src/@types/it-pair/index.d.ts
vendored
Normal 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
24
src/@types/libp2p.ts
Normal 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,
|
||||
}
|
@ -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> {
|
||||
|
||||
}
|
||||
|
@ -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> {
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1 @@
|
||||
import { Noise } from './noise';
|
||||
|
||||
export {
|
||||
Noise,
|
||||
}
|
||||
export * from "./noise";
|
||||
|
63
src/noise.ts
63
src/noise.ts
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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,
|
||||
}
|
@ -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();
|
||||
|
@ -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';
|
||||
|
||||
|
||||
|
@ -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');
|
||||
})
|
||||
|
@ -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": [
|
||||
|
Reference in New Issue
Block a user