WebCrypto X25519 (RFC 7748) key agreement over crypto.subtle.

Module webcryptoX25519 | Source packages/front/fw/src/crypto/webcrypto/x25519.js | Deps none | Worker-safe yes

Resolve

const webcryptoX25519 = runtime.resolve('webcryptoX25519');
// Returns: { isAvailable, generateKey, deriveBits, deriveKey, importKey, exportKey }

API

Method Signature Returns
isAvailable () => boolean true if crypto.subtle is present.
generateKey (extractable?: boolean) => Promise<CryptoKeyPair|false> X25519 key pair; false on error.
deriveBits (privateKey: CryptoKey, publicKey: CryptoKey, lengthBits?: number) => Promise<Uint8Array|false> Raw shared-secret bytes (default 256 bits = 32 bytes); false on error.
deriveKey (privateKey: CryptoKey, publicKey: CryptoKey, derivedKeyAlg: object, usages: KeyUsage[], extractable?: boolean) => Promise<CryptoKey|false> Derived symmetric CryptoKey; false on error.
importKey (format: 'raw'|'spki'|'pkcs8'|'jwk', keyData: Uint8Array|object, usages: KeyUsage[], extractable?: boolean) => Promise<CryptoKey|false> Imported CryptoKey; false on error or invalid format.
exportKey (format: 'raw'|'spki'|'pkcs8'|'jwk', key: CryptoKey) => Promise<Uint8Array|object|false> DER/raw → Uint8Array; 'jwk' → object; false on error.

Parameter details

  • generateKey — extractable defaults to true. Key pair usages are ['deriveBits', 'deriveKey'].
  • deriveBits — lengthBits defaults to 256 (= 32 bytes). Guards privateKey.algorithm.name === 'X25519'.
  • deriveKey — extractable defaults to false. Guards privateKey.algorithm.name === 'X25519'.
  • importKey — 'raw' format imports a 32-byte public key. extractable defaults to false for 'pkcs8', true otherwise.
  • exportKey — Guards key.algorithm.name === 'X25519'. Invalid format or non-X25519 key → false.

Examples

const wc = runtime.resolve('webcryptoX25519');

// Key agreement between two parties.
const pairA = await wc.generateKey();
const pairB = await wc.generateKey();

// Both sides derive the same 32-byte shared secret.
const secretAB = await wc.deriveBits(pairA.privateKey, pairB.publicKey);
const secretBA = await wc.deriveBits(pairB.privateKey, pairA.publicKey);
// secretAB and secretBA are equal — the Diffie-Hellman property.

// Derive an AES-GCM key from the shared secret.
const aesKey = await wc.deriveKey(
    pairA.privateKey,
    pairB.publicKey,
    { name: 'AES-GCM', length: 256 },
    ['encrypt', 'decrypt']
);

// Export and re-import a public key as raw bytes.
const rawPub = await wc.exportKey('raw', pairA.publicKey); // Uint8Array, 32 bytes
const pub2   = await wc.importKey('raw', rawPub, [], true);

// Graceful degradation check.
if (!wc.isAvailable()) {
    // Fall back to pure-JS x25519 module.
}

Worker Usage

// webcryptoX25519 is worker-safe: crypto.subtle is available in Web Workers.
const worker = fw.createWorker(async (fw) => {
    const wc = fw.resolve('webcryptoX25519');
    const pair = await wc.generateKey();
    // Use pair inside the worker...
});

Notes

  • Implements RFC 7748 §5 (Elliptic Curves for Diffie-Hellman Key Agreement) using 'X25519' as the WebCrypto algorithm name.
  • 'X25519' is a newer WebCrypto algorithm (Chrome 113+, Firefox 130+, Node 22+, Bun 1.1+). Older runtimes cause all operations to resolve false — check isAvailable() and probe generateKey() to confirm support before use.
  • No-throw contract: every operation is async and resolves to a result or false. Rejections from crypto.subtle are caught and logged via console.error('[crypto] FAIL: …').
  • All constants and guards are defined inside factory() for Worker serializability (no-factory-capture rule).

See also

  • x25519.md — pure-JS X25519 (default, no WebCrypto dependency)
  • ed25519.md — WebCrypto Ed25519 signatures (related Curve25519 variant)
  • ecc.md — WebCrypto ECDH/ECDSA over NIST P-curves