X25519 key agreement protocol implementation for secure key exchange using Curve25519 elliptic curve cryptography
—
High-level X25519 key agreement protocol using ephemeral key pairs with offer/accept pattern for interactive key exchange between two parties.
Interactive key agreement protocol implementing the standard offer/accept handshake pattern.
/**
* X25519 key agreement using ephemeral key pairs
*
* Note: This protocol is vulnerable to man-in-the-middle attacks unless
* combined with authentication methods such as public key signatures.
*/
class X25519KeyAgreement implements KeyAgreement {
/** Length of offer messages in bytes */
readonly offerMessageLength: number;
/** Length of accept messages in bytes */
readonly acceptMessageLength: number;
/** Length of shared keys in bytes */
readonly sharedKeyLength: number;
/** Length of saved state in bytes */
readonly savedStateLength: number;
/**
* Create new key agreement instance
* @param secretSeed - Optional 32-byte seed for deterministic keys
* @param prng - Optional random source for key generation
*/
constructor(secretSeed?: Uint8Array, prng?: RandomSource);
/** Initiate key agreement by generating offer message */
offer(): Uint8Array;
/** Accept offer and generate response message */
accept(offerMsg: Uint8Array): Uint8Array;
/** Complete key agreement using accept message */
finish(acceptMsg: Uint8Array): this;
/** Get the established shared key */
getSharedKey(): Uint8Array;
/** Save current state for serialization */
saveState(): Uint8Array;
/** Restore state from saved data */
restoreState(savedState: Uint8Array): this;
/** Securely wipe sensitive data from memory */
clean(): void;
}Usage Examples:
import { X25519KeyAgreement } from "@stablelib/x25519/keyagreement";
// Server-side (offering party)
const server = new X25519KeyAgreement();
const offerMessage = server.offer();
// Send offerMessage to client...
// Client-side (accepting party)
const client = new X25519KeyAgreement();
const acceptMessage = client.accept(offerMessage);
// Send acceptMessage back to server...
// Server completes the handshake
server.finish(acceptMessage);
// Both parties now have the same shared key
const serverKey = server.getSharedKey();
const clientKey = client.getSharedKey();
// Clean up sensitive data
server.clean();
client.clean();Initiates key agreement by generating the offer message containing the offerer's public key.
/**
* Initiate key agreement by generating offer message
* @returns 32-byte offer message containing public key
* @throws Error if offer() is called multiple times on same instance
*/
offer(): Uint8Array;Accepts an offer message and generates the response message, computing the shared key internally.
/**
* Accept offer and generate response message
* @param offerMsg - 32-byte offer message from the offering party
* @returns 32-byte accept message containing public key
* @throws Error if called by the offering party or if message length is incorrect
*/
accept(offerMsg: Uint8Array): Uint8Array;Completes the key agreement protocol using the accept message from the accepting party.
/**
* Complete key agreement using accept message
* @param acceptMsg - 32-byte accept message from accepting party
* @returns this instance for method chaining
* @throws Error if message length is incorrect, no offer state exists, or finish was already called
*/
finish(acceptMsg: Uint8Array): this;Retrieves the established shared key after successful key agreement.
/**
* Get the established shared key
* @returns 32-byte shared key
* @throws Error if no shared key has been established
*/
getSharedKey(): Uint8Array;Methods for serializing and restoring key agreement state.
/**
* Save current state for serialization
* @returns 32-byte state data
*/
saveState(): Uint8Array;
/**
* Restore state from saved data
* @param savedState - 32-byte saved state data
* @returns this instance for method chaining
*/
restoreState(savedState: Uint8Array): this;Usage Examples:
import { X25519KeyAgreement } from "@stablelib/x25519/keyagreement";
// Save and restore state
const keyAgreement = new X25519KeyAgreement();
const savedState = keyAgreement.saveState();
// Later...
const restoredKeyAgreement = new X25519KeyAgreement();
restoredKeyAgreement.restoreState(savedState);Securely wipe sensitive data from memory.
/**
* Securely wipe sensitive data from memory
* Clears secret keys and shared keys using secure wiping
*/
clean(): void;/** Length of offer messages in bytes */
const OFFER_MESSAGE_LENGTH: 32;
/** Length of accept messages in bytes */
const ACCEPT_MESSAGE_LENGTH: 32;
/** Length of saved state in bytes */
const SAVED_STATE_LENGTH: 32;
/** Length of secret seed in bytes */
const SECRET_SEED_LENGTH: 32;/** Interface implemented by X25519KeyAgreement */
interface KeyAgreement {
readonly offerMessageLength: number;
readonly acceptMessageLength: number;
readonly sharedKeyLength: number;
readonly savedStateLength: number;
offer(): Uint8Array;
accept(offerMsg: Uint8Array): Uint8Array;
finish(acceptMsg: Uint8Array): this;
getSharedKey(): Uint8Array;
saveState(): Uint8Array;
restoreState(savedState: Uint8Array): this;
clean(): void;
}The key agreement protocol follows this sequence:
offer() to generate offer messageaccept(offerMessage) to generate accept messagefinish(acceptMessage) to complete handshakegetSharedKey() to get identical shared secretclean() to wipe sensitive dataInstall with Tessl CLI
npx tessl i tessl/npm-stablelib--x25519