js-libp2p-noise/src/noise.ts
2019-11-20 22:52:08 +01:00

84 lines
3.0 KiB
TypeScript

import { x25519 } from 'bcrypto';
import { Buffer } from "buffer";
import Wrap from 'it-pb-rpc';
import { Handshake } from "./handshake";
import { createHandshakePayload, generateKeypair, getHandshakePayload, signPayload } from "./utils";
import { decryptStreams, encryptStreams } from "./crypto";
import { bytes } from "./@types/basic";
import { NoiseConnection, PeerId, KeyPair, SecureOutbound } from "./@types/libp2p";
import { Duplex } from "./@types/it-pair";
export class Noise implements NoiseConnection {
public protocol = "/noise";
private readonly privateKey: bytes;
private staticKeys: KeyPair;
private earlyData?: bytes;
constructor(privateKey: bytes, staticNoiseKey?: bytes, earlyData?: bytes) {
this.privateKey = privateKey;
this.earlyData = earlyData;
if (staticNoiseKey) {
const publicKey = x25519.publicKeyCreate(staticNoiseKey);
this.staticKeys = {
privateKey: staticNoiseKey,
publicKey,
}
} else {
// todo: generate new static key
}
}
/**
* 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 wrappedConnection = Wrap(connection);
const remotePublicKey = Buffer.from(remotePeer.pubKey);
const session = await this.createSecureConnection(wrappedConnection, remotePublicKey, true);
return {
conn: session,
remotePeer,
}
}
/**
* 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,
remotePublicKey: bytes,
isInitiator: boolean,
) : Promise<Duplex> {
if (!this.staticKeys) {
this.staticKeys = await generateKeypair();
}
const payload = getHandshakePayload(this.staticKeys.publicKey);
const signedPayload = signPayload(this.staticKeys.privateKey, payload);
const handshakePayload = await createHandshakePayload(this.staticKeys, signedPayload);
const prologue = Buffer.from(this.protocol);
const handshake = new Handshake('XX', remotePublicKey, prologue, handshakePayload, this.staticKeys, connection);
const session = await handshake.propose(isInitiator);
return await encryptStreams(connection, session);
}
}