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—extractabledefaults totrue. Key pair usages are['deriveBits', 'deriveKey'].deriveBits—lengthBitsdefaults to256(= 32 bytes). GuardsprivateKey.algorithm.name === 'X25519'.deriveKey—extractabledefaults tofalse. GuardsprivateKey.algorithm.name === 'X25519'.importKey—'raw'format imports a 32-byte public key.extractabledefaults tofalsefor'pkcs8',trueotherwise.exportKey— Guardskey.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 resolvefalse— checkisAvailable()and probegenerateKey()to confirm support before use.- No-throw contract: every operation is
asyncand resolves to a result orfalse. Rejections fromcrypto.subtleare caught and logged viaconsole.error('[crypto] FAIL: …'). - All constants and guards are defined inside
factory()for Worker serializability (no-factory-capturerule).
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