mirror of
https://github.com/fluencelabs/js-libp2p-noise
synced 2025-06-15 07:31:29 +00:00
Create handshake interface to support performing different handshakes
This commit is contained in:
8
src/@types/handshake-interface.ts
Normal file
8
src/@types/handshake-interface.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import {bytes} from "./basic";
|
||||||
|
import {NoiseSession} from "./handshake";
|
||||||
|
|
||||||
|
export interface HandshakeInterface {
|
||||||
|
session: NoiseSession;
|
||||||
|
encrypt(plaintext: bytes, session: NoiseSession): bytes;
|
||||||
|
decrypt(ciphertext: bytes, session: NoiseSession): bytes;
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
import { Buffer } from "buffer";
|
import { Buffer } from "buffer";
|
||||||
import { Handshake } from "./handshake-xx";
|
import {HandshakeInterface} from "./@types/handshake-interface";
|
||||||
|
|
||||||
interface ReturnEncryptionWrapper {
|
interface ReturnEncryptionWrapper {
|
||||||
(source: Iterable<Uint8Array>): AsyncIterableIterator<Uint8Array>;
|
(source: Iterable<Uint8Array>): AsyncIterableIterator<Uint8Array>;
|
||||||
@ -8,7 +8,7 @@ interface ReturnEncryptionWrapper {
|
|||||||
const maxPlaintextLength = 65519;
|
const maxPlaintextLength = 65519;
|
||||||
|
|
||||||
// Returns generator that encrypts payload from the user
|
// Returns generator that encrypts payload from the user
|
||||||
export function encryptStream(handshake: Handshake): ReturnEncryptionWrapper {
|
export function encryptStream(handshake: HandshakeInterface): ReturnEncryptionWrapper {
|
||||||
return async function * (source) {
|
return async function * (source) {
|
||||||
for await (const chunk of source) {
|
for await (const chunk of source) {
|
||||||
const chunkBuffer = Buffer.from(chunk.buffer, chunk.byteOffset, chunk.length);
|
const chunkBuffer = Buffer.from(chunk.buffer, chunk.byteOffset, chunk.length);
|
||||||
@ -28,7 +28,7 @@ export function encryptStream(handshake: Handshake): ReturnEncryptionWrapper {
|
|||||||
|
|
||||||
|
|
||||||
// Decrypt received payload to the user
|
// Decrypt received payload to the user
|
||||||
export function decryptStream(handshake: Handshake): ReturnEncryptionWrapper {
|
export function decryptStream(handshake: HandshakeInterface): ReturnEncryptionWrapper {
|
||||||
return async function * (source) {
|
return async function * (source) {
|
||||||
for await (const chunk of source) {
|
for await (const chunk of source) {
|
||||||
const chunkBuffer = Buffer.from(chunk.buffer, chunk.byteOffset, chunk.length);
|
const chunkBuffer = Buffer.from(chunk.buffer, chunk.byteOffset, chunk.length);
|
||||||
|
@ -4,7 +4,7 @@ import {KeyPair, PeerId} from "./@types/libp2p";
|
|||||||
import {WrappedConnection} from "./noise";
|
import {WrappedConnection} from "./noise";
|
||||||
import {IKHandshake} from "./handshakes/ik";
|
import {IKHandshake} from "./handshakes/ik";
|
||||||
|
|
||||||
export class Handshake {
|
export class Handshake { // implements HandshakeHandler
|
||||||
public isInitiator: boolean;
|
public isInitiator: boolean;
|
||||||
public session: NoiseSession;
|
public session: NoiseSession;
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@ import { XXHandshake } from "./handshakes/xx";
|
|||||||
import { KeyPair, PeerId } from "./@types/libp2p";
|
import { KeyPair, PeerId } from "./@types/libp2p";
|
||||||
import { bytes, bytes32 } from "./@types/basic";
|
import { bytes, bytes32 } from "./@types/basic";
|
||||||
import { NoiseSession } from "./@types/handshake";
|
import { NoiseSession } from "./@types/handshake";
|
||||||
|
import {HandshakeInterface} from "./@types/handshake-interface";
|
||||||
import {
|
import {
|
||||||
createHandshakePayload,
|
createHandshakePayload,
|
||||||
getHandshakePayload,
|
getHandshakePayload,
|
||||||
@ -15,7 +16,7 @@ import { logger } from "./logger";
|
|||||||
import { decodeMessageBuffer, encodeMessageBuffer } from "./encoder";
|
import { decodeMessageBuffer, encodeMessageBuffer } from "./encoder";
|
||||||
import { WrappedConnection } from "./noise";
|
import { WrappedConnection } from "./noise";
|
||||||
|
|
||||||
export class Handshake {
|
export class Handshake implements HandshakeInterface {
|
||||||
public isInitiator: boolean;
|
public isInitiator: boolean;
|
||||||
public session: NoiseSession;
|
public session: NoiseSession;
|
||||||
|
|
||||||
@ -50,7 +51,7 @@ export class Handshake {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// stage 0
|
// stage 0
|
||||||
async propose(): Promise<void> {
|
public async propose(): Promise<void> {
|
||||||
if (this.isInitiator) {
|
if (this.isInitiator) {
|
||||||
logger("Stage 0 - Initiator starting to send first message.");
|
logger("Stage 0 - Initiator starting to send first message.");
|
||||||
const messageBuffer = this.xx.sendMessage(this.session, Buffer.alloc(0));
|
const messageBuffer = this.xx.sendMessage(this.session, Buffer.alloc(0));
|
||||||
@ -65,7 +66,7 @@ export class Handshake {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// stage 1
|
// stage 1
|
||||||
async exchange(): Promise<void> {
|
public async exchange(): Promise<void> {
|
||||||
if (this.isInitiator) {
|
if (this.isInitiator) {
|
||||||
logger('Stage 1 - Initiator waiting to receive first message from responder...');
|
logger('Stage 1 - Initiator waiting to receive first message from responder...');
|
||||||
const receivedMessageBuffer = decodeMessageBuffer((await this.connection.readLP()).slice());
|
const receivedMessageBuffer = decodeMessageBuffer((await this.connection.readLP()).slice());
|
||||||
@ -97,7 +98,7 @@ export class Handshake {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// stage 2
|
// stage 2
|
||||||
async finish(earlyData?: bytes): Promise<void> {
|
public async finish(earlyData?: bytes): Promise<void> {
|
||||||
if (this.isInitiator) {
|
if (this.isInitiator) {
|
||||||
logger('Stage 2 - Initiator sending third handshake message.');
|
logger('Stage 2 - Initiator sending third handshake message.');
|
||||||
const signedPayload = signPayload(this.libp2pPrivateKey, getHandshakePayload(this.staticKeys.publicKey));
|
const signedPayload = signPayload(this.libp2pPrivateKey, getHandshakePayload(this.staticKeys.publicKey));
|
||||||
|
26
src/noise.ts
26
src/noise.ts
@ -6,13 +6,15 @@ import ensureBuffer from 'it-buffer';
|
|||||||
import pipe from 'it-pipe';
|
import pipe from 'it-pipe';
|
||||||
import lp from 'it-length-prefixed';
|
import lp from 'it-length-prefixed';
|
||||||
|
|
||||||
import { Handshake } from "./handshake-xx";
|
import { Handshake as XX } from "./handshake-xx";
|
||||||
import { generateKeypair } from "./utils";
|
import { generateKeypair } from "./utils";
|
||||||
import { uint16BEDecode, uint16BEEncode } from "./encoder";
|
import { uint16BEDecode, uint16BEEncode } from "./encoder";
|
||||||
import { decryptStream, encryptStream } from "./crypto";
|
import { decryptStream, encryptStream } from "./crypto";
|
||||||
import { bytes } from "./@types/basic";
|
import { bytes } from "./@types/basic";
|
||||||
import { NoiseConnection, PeerId, KeyPair, SecureOutbound } from "./@types/libp2p";
|
import { NoiseConnection, PeerId, KeyPair, SecureOutbound } from "./@types/libp2p";
|
||||||
import { Duplex } from "./@types/it-pair";
|
import { Duplex } from "./@types/it-pair";
|
||||||
|
import {XXHandshake} from "./handshakes/xx";
|
||||||
|
import {HandshakeInterface} from "./@types/handshake-interface";
|
||||||
|
|
||||||
export type WrappedConnection = ReturnType<typeof Wrap>;
|
export type WrappedConnection = ReturnType<typeof Wrap>;
|
||||||
|
|
||||||
@ -89,24 +91,22 @@ export class Noise implements NoiseConnection {
|
|||||||
isInitiator: boolean,
|
isInitiator: boolean,
|
||||||
libp2pPublicKey: bytes,
|
libp2pPublicKey: bytes,
|
||||||
remotePeer: PeerId,
|
remotePeer: PeerId,
|
||||||
): Promise<Handshake> {
|
): Promise<HandshakeInterface> {
|
||||||
if (false) {
|
|
||||||
// TODO: Implement noise pipes
|
// TODO: Implement noise pipes
|
||||||
|
|
||||||
|
if (false) {
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
return await this.performXXHandshake(connection, isInitiator, libp2pPublicKey, remotePeer)
|
const prologue = Buffer.from(this.protocol);
|
||||||
|
const handshake = new XX(isInitiator, this.privateKey, libp2pPublicKey, prologue, this.staticKeys, connection, remotePeer);
|
||||||
|
|
||||||
|
return await this.performXXHandshake(handshake);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async performXXHandshake(
|
private async performXXHandshake(
|
||||||
connection: WrappedConnection,
|
handshake: XX
|
||||||
isInitiator: boolean,
|
): Promise<HandshakeInterface> {
|
||||||
libp2pPublicKey: bytes,
|
|
||||||
remotePeer: PeerId,
|
|
||||||
): Promise<Handshake> {
|
|
||||||
const prologue = Buffer.from(this.protocol);
|
|
||||||
const handshake = new Handshake(isInitiator, this.privateKey, libp2pPublicKey, prologue, this.staticKeys, connection, remotePeer);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await handshake.propose();
|
await handshake.propose();
|
||||||
await handshake.exchange();
|
await handshake.exchange();
|
||||||
@ -120,7 +120,7 @@ export class Noise implements NoiseConnection {
|
|||||||
|
|
||||||
private async createSecureConnection(
|
private async createSecureConnection(
|
||||||
connection: WrappedConnection,
|
connection: WrappedConnection,
|
||||||
handshake: Handshake,
|
handshake: HandshakeInterface,
|
||||||
): Promise<Duplex> {
|
): Promise<Duplex> {
|
||||||
// Create encryption box/unbox wrapper
|
// Create encryption box/unbox wrapper
|
||||||
const [secure, user] = DuplexPair();
|
const [secure, user] = DuplexPair();
|
||||||
|
Reference in New Issue
Block a user