2019-11-11 15:39:09 +01:00
|
|
|
import { x25519 } from 'bcrypto';
|
2019-11-11 21:58:04 +01:00
|
|
|
import { Buffer } from "buffer";
|
2019-11-11 15:39:09 +01:00
|
|
|
|
2019-11-08 14:03:34 +01:00
|
|
|
import { bytes } from "./types/basic";
|
2019-11-11 21:58:04 +01:00
|
|
|
import { InsecureConnection, NoiseConnection, PeerId, SecureConnection, KeyPair } from "./types/libp2p";
|
2019-11-08 14:03:34 +01:00
|
|
|
|
2019-11-11 21:58:04 +01:00
|
|
|
import { Handshake } from "./handshake";
|
|
|
|
import { generateKeypair, signPayload } from "./utils";
|
2019-11-12 14:07:25 +01:00
|
|
|
import { encryptStreams } from "./crypto";
|
2019-11-11 21:58:04 +01:00
|
|
|
|
|
|
|
export class Noise implements NoiseConnection {
|
2019-11-11 15:39:09 +01:00
|
|
|
private readonly privateKey: bytes;
|
2019-11-12 14:02:59 +01:00
|
|
|
private staticKeys: KeyPair;
|
2019-11-11 15:39:09 +01:00
|
|
|
private earlyData?: bytes;
|
|
|
|
|
2019-11-08 14:03:34 +01:00
|
|
|
constructor(privateKey: bytes, staticNoiseKey?: bytes, earlyData?: bytes) {
|
2019-11-11 15:39:09 +01:00
|
|
|
this.privateKey = privateKey;
|
|
|
|
this.earlyData = earlyData;
|
2019-11-08 14:03:34 +01:00
|
|
|
|
2019-11-11 15:39:09 +01:00
|
|
|
if (staticNoiseKey) {
|
|
|
|
const publicKey = x25519.publicKeyCreate(staticNoiseKey);
|
|
|
|
this.staticKeys = {
|
|
|
|
privateKey: staticNoiseKey,
|
|
|
|
publicKey,
|
|
|
|
}
|
2019-11-12 14:02:59 +01:00
|
|
|
} else {
|
|
|
|
// todo: generate new static key
|
2019-11-11 15:39:09 +01:00
|
|
|
}
|
2019-11-08 14:03:34 +01:00
|
|
|
}
|
|
|
|
|
2019-11-11 21:58:04 +01:00
|
|
|
public protocol() {
|
2019-11-08 14:03:34 +01:00
|
|
|
return '/noise';
|
|
|
|
}
|
|
|
|
|
2019-11-11 21:58:04 +01:00
|
|
|
// 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) {
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// decrypt incoming data (handshake as responder)
|
|
|
|
public async secureInbound(connection: InsecureConnection) : Promise<SecureConnection> {
|
|
|
|
}
|
|
|
|
|
|
|
|
private async createSecureConnection(
|
|
|
|
connection: InsecureConnection,
|
|
|
|
remotePublicKey: bytes,
|
|
|
|
isInitiator: boolean,
|
|
|
|
) : Promise<SecureConnection> {
|
2019-11-11 15:39:09 +01:00
|
|
|
if (!this.staticKeys) {
|
2019-11-11 21:58:04 +01:00
|
|
|
this.staticKeys = await generateKeypair();
|
2019-11-11 15:39:09 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
let signedPayload;
|
|
|
|
if (this.earlyData) {
|
|
|
|
const payload = Buffer.concat([this.earlyData, this.staticKeys.publicKey])
|
|
|
|
signedPayload = await signPayload(this.privateKey, payload);
|
|
|
|
}
|
2019-11-08 14:03:34 +01:00
|
|
|
|
2019-11-11 21:58:04 +01:00
|
|
|
const prologue = Buffer.from(this.protocol());
|
|
|
|
const session = await Handshake.runXX(isInitiator, remotePublicKey, prologue, signedPayload, this.staticKeys);
|
|
|
|
|
2019-11-12 14:07:25 +01:00
|
|
|
await encryptStreams(connection.streams(), session);
|
2019-11-12 14:02:59 +01:00
|
|
|
|
2019-11-11 21:58:04 +01:00
|
|
|
return {
|
2019-11-12 14:02:59 +01:00
|
|
|
...connection,
|
2019-11-11 21:58:04 +01:00
|
|
|
initiator: isInitiator,
|
|
|
|
prologue,
|
2019-11-12 14:07:25 +01:00
|
|
|
localKey: Buffer.alloc(0), // get libp2p public key,
|
2019-11-11 21:58:04 +01:00
|
|
|
xxNoiseSession: session,
|
|
|
|
xxComplete: true,
|
|
|
|
noiseKeypair: this.staticKeys,
|
|
|
|
}
|
2019-11-08 14:03:34 +01:00
|
|
|
}
|
|
|
|
|
2019-11-11 21:58:04 +01:00
|
|
|
|
2019-11-08 14:03:34 +01:00
|
|
|
}
|