diff --git a/src/constants.ts b/src/constants.ts index d17e594..9b34786 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -1,3 +1,6 @@ export const NOISE_MSG_MAX_LENGTH_BYTES = 65535; export const NOISE_MSG_MAX_LENGTH_BYTES_WITHOUT_TAG = NOISE_MSG_MAX_LENGTH_BYTES - 16; +export const DUMP_SESSION_KEYS = process.env.DUMP_SESSION_KEYS; + + diff --git a/src/handshake-ik.ts b/src/handshake-ik.ts index 983cf2e..e67c2c7 100644 --- a/src/handshake-ik.ts +++ b/src/handshake-ik.ts @@ -8,7 +8,14 @@ import {Buffer} from "buffer"; import {decode0, decode1, encode0, encode1} from "./encoder"; import {decodePayload, getPeerIdFromPayload, verifySignedPayload} from "./utils"; import {FailedIKError} from "./errors"; -import {logger} from "./logger"; +import { + logger, + logLocalStaticKeys, + logRemoteStaticKey, + logLocalEphemeralKeys, + logRemoteEphemeralKey, + logCipherState +} from "./logger"; import PeerId from "peer-id"; export class IKHandshake implements IHandshake { @@ -45,11 +52,14 @@ export class IKHandshake implements IHandshake { } public async stage0(): Promise { + logLocalStaticKeys(this.session.hs.s) + logRemoteStaticKey(this.session.hs.rs) if (this.isInitiator) { logger("IK Stage 0 - Initiator sending message..."); const messageBuffer = this.ik.sendMessage(this.session, this.payload); this.connection.writeLP(encode1(messageBuffer)); logger("IK Stage 0 - Initiator sent message."); + logLocalEphemeralKeys(this.session.hs.e) } else { logger("IK Stage 0 - Responder receiving message..."); const receivedMsg = await this.connection.readLP(); @@ -64,6 +74,7 @@ export class IKHandshake implements IHandshake { this.remotePeer = this.remotePeer || await getPeerIdFromPayload(decodedPayload); await verifySignedPayload(this.session.hs.rs, decodedPayload, this.remotePeer); logger("IK Stage 0 - Responder successfully verified payload!"); + logRemoteEphemeralKey(this.session.hs.re) } catch (e) { logger("Responder breaking up with IK handshake in stage 0."); @@ -87,6 +98,7 @@ export class IKHandshake implements IHandshake { this.remotePeer = this.remotePeer || await getPeerIdFromPayload(decodedPayload); await verifySignedPayload(receivedMessageBuffer.ns.slice(0, 32), decodedPayload, this.remotePeer); logger("IK Stage 1 - Initiator successfully verified payload!"); + logRemoteEphemeralKey(this.session.hs.re) } catch (e) { logger("Initiator breaking up with IK handshake in stage 1."); throw new FailedIKError(receivedMsg, `Error occurred while verifying responder's signed payload: ${e.message}`); @@ -96,7 +108,9 @@ export class IKHandshake implements IHandshake { const messageBuffer = this.ik.sendMessage(this.session, this.payload); this.connection.writeLP(encode0(messageBuffer)); logger("IK Stage 1 - Responder sent message..."); + logLocalEphemeralKeys(this.session.hs.e) } + logCipherState(this.session) } public decrypt(ciphertext: bytes, session: NoiseSession): {plaintext: bytes; valid: boolean} { diff --git a/src/handshake-xx-fallback.ts b/src/handshake-xx-fallback.ts index 6217bc5..f56df5c 100644 --- a/src/handshake-xx-fallback.ts +++ b/src/handshake-xx-fallback.ts @@ -3,8 +3,8 @@ import {XXHandshake} from "./handshake-xx"; import {XX} from "./handshakes/xx"; import {KeyPair} from "./@types/libp2p"; import {bytes, bytes32} from "./@types/basic"; -import {decodePayload, getPeerIdFromPayload, verifySignedPayload,} from "./utils"; -import {logger} from "./logger"; +import {decodePayload, getPeerIdFromPayload, verifySignedPayload} from "./utils"; +import {logger, logLocalEphemeralKeys, logRemoteEphemeralKey, logRemoteStaticKey} from "./logger"; import {WrappedConnection} from "./noise"; import {decode0, decode1} from "./encoder"; import PeerId from "peer-id"; @@ -36,6 +36,7 @@ export class XXFallbackHandshake extends XXHandshake { if (this.isInitiator) { this.xx.sendMessage(this.session, Buffer.alloc(0), this.ephemeralKeys); logger("XX Fallback Stage 0 - Initialized state as the first message was sent by initiator."); + logLocalEphemeralKeys(this.session.hs.e) } else { logger("XX Fallback Stage 0 - Responder decoding initial msg from IK."); const receivedMessageBuffer = decode0(this.initialMsg); @@ -48,6 +49,7 @@ export class XXFallbackHandshake extends XXHandshake { throw new Error("xx fallback stage 0 decryption validation fail"); } logger("XX Fallback Stage 0 - Responder used received message from IK."); + logRemoteEphemeralKey(this.session.hs.re) } } @@ -60,6 +62,8 @@ export class XXFallbackHandshake extends XXHandshake { throw new Error("xx fallback stage 1 decryption validation fail"); } logger('XX Fallback Stage 1 - Initiator used received message from IK.'); + logRemoteEphemeralKey(this.session.hs.re) + logRemoteStaticKey(this.session.hs.rs) logger("Initiator going to check remote's signature..."); try { diff --git a/src/handshake-xx.ts b/src/handshake-xx.ts index 41360e5..bbcbab1 100644 --- a/src/handshake-xx.ts +++ b/src/handshake-xx.ts @@ -10,7 +10,14 @@ import { getPeerIdFromPayload, verifySignedPayload, } from "./utils"; -import { logger } from "./logger"; +import { + logger, + logLocalStaticKeys, + logLocalEphemeralKeys, + logRemoteEphemeralKey, + logRemoteStaticKey, + logCipherState, +} from "./logger"; import {decode0, decode1, decode2, encode0, encode1, encode2} from "./encoder"; import { WrappedConnection } from "./noise"; import PeerId from "peer-id"; @@ -50,11 +57,13 @@ export class XXHandshake implements IHandshake { // stage 0 public async propose(): Promise { + logLocalStaticKeys(this.session.hs.s) if (this.isInitiator) { logger("Stage 0 - Initiator starting to send first message."); const messageBuffer = this.xx.sendMessage(this.session, Buffer.alloc(0)); this.connection.writeLP(encode0(messageBuffer)); logger("Stage 0 - Initiator finished sending first message."); + logLocalEphemeralKeys(this.session.hs.e) } else { logger("Stage 0 - Responder waiting to receive first message..."); const receivedMessageBuffer = decode0((await this.connection.readLP()).slice()); @@ -63,6 +72,7 @@ export class XXHandshake implements IHandshake { throw new Error("xx handshake stage 0 validation fail"); } logger("Stage 0 - Responder received first message."); + logRemoteEphemeralKey(this.session.hs.re) } } @@ -76,6 +86,8 @@ export class XXHandshake implements IHandshake { throw new Error("xx handshake stage 1 validation fail"); } logger('Stage 1 - Initiator received the message.'); + logRemoteEphemeralKey(this.session.hs.re) + logRemoteStaticKey(this.session.hs.rs) logger("Initiator going to check remote's signature..."); try { @@ -91,6 +103,7 @@ export class XXHandshake implements IHandshake { const messageBuffer = this.xx.sendMessage(this.session, this.payload); this.connection.writeLP(encode1(messageBuffer)); logger('Stage 1 - Responder sent the second handshake message with signed payload.') + logLocalEphemeralKeys(this.session.hs.e) } } @@ -118,6 +131,7 @@ export class XXHandshake implements IHandshake { throw new Error(`Error occurred while verifying signed payload: ${e.message}`); } } + logCipherState(this.session) } public encrypt(plaintext: bytes, session: NoiseSession): bytes { diff --git a/src/logger.ts b/src/logger.ts index 150e061..5f7c026 100644 --- a/src/logger.ts +++ b/src/logger.ts @@ -1,2 +1,47 @@ import debug from "debug"; +import {DUMP_SESSION_KEYS} from './constants'; +import { KeyPair } from "./@types/libp2p"; +import { NoiseSession, SymmetricState } from "./@types/handshake"; + export const logger = debug('libp2p:noise'); + +let keyLogger; +if(DUMP_SESSION_KEYS){ + keyLogger = logger +} +else { + keyLogger = () => {} +} + +export function logLocalStaticKeys(s: KeyPair): void { + keyLogger(`LOCAL_STATIC_PUBLIC_KEY ${s.publicKey.toString('hex')}`) + keyLogger(`LOCAL_STATIC_PRIVATE_KEY ${s.privateKey.toString('hex')}`) +} + +export function logLocalEphemeralKeys(e: KeyPair|undefined): void { + if(e){ + keyLogger(`LOCAL_PUBLIC_EPHEMERAL_KEY ${e.publicKey.toString('hex')}`) + keyLogger(`LOCAL_PRIVATE_EPHEMERAL_KEY ${e.privateKey.toString('hex')}`) + } + else{ + keyLogger('Missing local ephemeral keys.') + } +} + +export function logRemoteStaticKey(rs: Buffer): void { + keyLogger(`REMOTE_STATIC_PUBLIC_KEY ${rs.toString('hex')}`) +} + +export function logRemoteEphemeralKey(re: Buffer): void { + keyLogger(`REMOTE_EPHEMERAL_PUBLIC_KEY ${re.toString('hex')}`) +} + +export function logCipherState(session: NoiseSession): void { + if(session.cs1 && session.cs2){ + keyLogger(`CIPHER_STATE_1 ${session.cs1.n} ${session.cs1.k.toString('hex')}`) + keyLogger(`CIPHER_STATE_2 ${session.cs2.n} ${session.cs2.k.toString('hex')}`) + } + else{ + keyLogger('Missing cipher state.') + } +}