import type { GossipMessage } from "./gossip.js"; /** * A gossip message with authentication fields for HMAC verification * and replay protection. Fields are optional to maintain backward * compatibility with unauthenticated messages. */ export interface AuthenticatedGossipMessage extends GossipMessage { /** Hex-encoded random nonce for replay protection. */ nonce?: string; /** Hex-encoded HMAC-SHA256 digest of the message contents + nonce. */ hmac?: string; } /** * Pluggable authentication interface for securing gossip communication * between cluster nodes. Transport-level security (encryption + auth) * is handled by CurveZMQ at the socket layer, driven by the cookie. */ export interface Authenticator { /** Adds `nonce` and `hmac` fields to a gossip message. */ signGossip(message: GossipMessage): AuthenticatedGossipMessage; /** Verifies HMAC integrity and checks nonce has not been replayed. */ verifyGossip(message: AuthenticatedGossipMessage): boolean; } export declare function z85Encode(data: Buffer): string; export declare function z85Decode(str: string): Buffer; export interface CurveKeyPair { publicKey: string; secretKey: string; } /** * Derives an HMAC key for gossip signing and a CurveZMQ keypair for * transport encryption from a shared cookie using HKDF-SHA256. * * Uses domain-separated info strings to prevent cross-protocol key reuse: * - "gossip-hmac" → 32-byte HMAC key for gossip UDP * - "curve-seed" → 32-byte seed → X25519 keypair for ZeroMQ CURVE */ export declare function deriveKeys(cookie: string, salt?: string): { hmacKey: Buffer; curveKeyPair: CurveKeyPair; }; interface CookieAuthenticatorOptions { nonceTtlMs?: number; nonceCacheMaxSize?: number; salt?: string; } /** * HMAC-SHA256 cookie-based authenticator inspired by Erlang's distribution * cookie. Uses HKDF-derived keys for gossip message signing and provides * CurveZMQ keypairs for transport encryption. * * Security properties: * - HKDF-SHA256 key derivation with domain-separated info strings * - HMAC-SHA256 for gossip message integrity * - Random nonce per message for replay protection * - `crypto.timingSafeEqual()` for all comparisons (timing attack resistant) * - Nonce cache with TTL eviction to bound memory usage * - CurveZMQ keypair for transport-level encryption + authentication */ export declare class CookieAuthenticator implements Authenticator { private readonly hmacKey; private readonly nonceTtlMs; private readonly nonceCacheMaxSize; private readonly nonceCache; /** CurveZMQ keypair derived from the cookie, for transport encryption. */ readonly curveKeyPair: CurveKeyPair; constructor(cookie: string, options?: CookieAuthenticatorOptions); signGossip(message: GossipMessage): AuthenticatedGossipMessage; verifyGossip(message: AuthenticatedGossipMessage): boolean; private computeGossipHmac; private evictExpiredNonces; private evictOverflowNonces; } /** * SHA-256 fingerprint of a Z85-encoded public key. * Returns hex-encoded hash for display purposes (never exposes raw secrets). */ export declare function fingerprint(z85PublicKey: string): string; /** * Keyring-based authenticator that supports cookie rotation without restart. * Wraps a primary and optional secondary CookieAuthenticator. * * Rotation workflow (Consul-style): * 1. install(newCookie) — add to keyring, dual-accept gossip HMAC * 2. activate() — swap primary, return new curveKeyPair for transport * 3. remove() — purge old key from keyring * * Implements the Authenticator interface so GossipUDP/GossipProtocol * see no difference — the reference stays the same, only internal state changes. */ export declare class KeyringAuthenticator implements Authenticator { private primary; private secondary?; private readonly salt; constructor(cookie: string, options?: CookieAuthenticatorOptions); /** * Add a new cookie to the keyring. Does not change signing behavior — * outgoing messages are still signed with the current primary key. * Incoming messages are verified against both primary and secondary. */ install(cookie: string): void; /** * Promote the installed cookie to primary. The previous primary becomes * secondary (still accepted for verification during the grace window). * Returns the new curveKeyPair for transport socket recreation. */ activate(): CurveKeyPair; /** * Remove the secondary (old) cookie from the keyring. * After this, only messages signed with the current primary key are accepted. * Idempotent — safe to call when no secondary exists. */ remove(): void; /** * List SHA-256 fingerprints of installed keys (primary first, then secondary). * Never exposes raw cookies or key material. */ list(): string[]; /** Current primary curve keypair for transport. */ get curveKeyPair(): CurveKeyPair; signGossip(message: GossipMessage): AuthenticatedGossipMessage; verifyGossip(message: AuthenticatedGossipMessage): boolean; } /** * No-op authenticator that accepts all messages without verification. * Used internally when no authentication is configured. */ export declare class NullAuthenticator implements Authenticator { signGossip(message: GossipMessage): AuthenticatedGossipMessage; verifyGossip(_message: AuthenticatedGossipMessage): boolean; } export {}; //# sourceMappingURL=auth.d.ts.map