Keys
OneAsymmetricKey, RFC 5958) or a public key as SPKI (RFC 5280 sec. 4.1.2.7), encrypt / decrypt a private key under RFC 8018 PBES2 (EncryptedPrivateKeyInfo, PBKDF2 + AES-CBC-Pad), and generate / publicFromPrivate over every algorithm the WebCrypto engine drives -- RSA, EC, Ed25519/Ed448, X25519/X448, and the FIPS post-quantum ML-DSA / ML-KEM. Unencrypted export / import DELEGATES to the WebCrypto exportKey / importKey PKCS#8 / SPKI encoders (which already emit each algorithm's AlgorithmIdentifier.parameters correctly -- RSA NULL, EC namedCurve, Ed/X ABSENT), so the wrapper never re-encodes an AlgorithmIdentifier. PBES2 encrypt / decrypt composes the one shared lib/pbes2.js home (the same PBKDF2 + AES-CBC primitives pki.cms uses). Parsing lives at pki.schema.pkcs8.parse.pki.key.encrypt
pki.key.encrypt(privateKey, password, opts?) -> Promise<Buffer|string>
Encrypt a PKCS#8 private key into an RFC 5958 EncryptedPrivateKeyInfo under RFC 8018 PBES2 (PBKDF2 + AES-CBC-Pad). privateKey is a DER Buffer, a PRIVATE KEY PEM string, or an extractable private CryptoKey; password is a string (UTF-8-encoded, byte-identical to OpenSSL), Buffer, or Uint8Array. The plaintext is the DER PrivateKeyInfo, validated as a well-formed PKCS#8 structure before encryption (never encrypt opaque bytes), and the produced EncryptedPrivateKeyInfo is re-parsed before return.
The PBKDF2 prf equal to the default (hmacWithSHA1) is omitted from the parameters (X.690 sec. 11.5), keyLength is omitted (the AES cipher OID fixes the key size), and the salt / iteration count are bounded -- so the output is byte-exact with OpenSSL's pkcs8 -topk8 -v2. A bad input throws a typed KeyError.
Options
- `cipher` (string) -- `aes-256-cbc` (default), `aes-192-cbc`, or `aes-128-cbc`.
- `prf` (string) -- `hmacWithSHA256` (default), `hmacWithSHA384`, `hmacWithSHA512`, or `hmacWithSHA1`.
- `iterations` (number) -- PBKDF2 iteration count, default 600000 (bounded by the decryptor's cap).
- `salt` (Buffer) -- an explicit PBKDF2 salt (default 16 random octets).
- `pem` (boolean) -- return an `ENCRYPTED PRIVATE KEY` PEM string instead of DER.
Example
async function example() {
var pair = await pki.key.generate("Ed25519");
var der = await pki.key.export(pair.privateKey);
var enc = await pki.key.encrypt(der, "s3cr3t", { pem: true });
var back = await pki.key.decrypt(enc, "s3cr3t");
}
example();
References
- spec RFC 5958 sec. 3
- spec RFC 8018
pki.key.decrypt
pki.key.decrypt(encrypted, password, opts?) -> Promise<Buffer|string>
Decrypt an RFC 5958 EncryptedPrivateKeyInfo (DER Buffer or ENCRYPTED PRIVATE KEY PEM) under RFC 8018 PBES2, returning the inner PrivateKeyInfo (re-validated via pki.schema.pkcs8.parse). Only PBES2 with a PBKDF2 key-derivation function and an AES-CBC encryption scheme is accepted; PBES1, PBMAC1, scrypt, and any other encryptionAlgorithm fail closed with key/unsupported-algorithm.
The salt and iteration count are attacker-controlled work: both caps are enforced BEFORE any derivation (opts.maxIterations may lower the cap, never raise it), and a wrong-length IV or malformed parameter set is a typed key/bad-algorithm-parameters. A MAC-less PBES2-CBC decrypt is not a padding oracle -- a wrong password and a valid-pad-but-not-a-PrivateKeyInfo both surface the single uniform key/decrypt-failed.
Options
- `maxIterations` (number) -- lower the PBKDF2 iteration cap for this decrypt (downward-only).
- `pem` (boolean) -- return a `PRIVATE KEY` PEM string instead of DER.
Example
async function example() {
var pair = await pki.key.generate("Ed25519");
var enc = await pki.key.encrypt(await pki.key.export(pair.privateKey), "s3cr3t", { pem: true });
var der = await pki.key.decrypt(enc, "s3cr3t");
}
example();
References
- spec RFC 5958 sec. 3
- spec RFC 8018 sec. 6.2
- spec RFC 8018 sec. 8
- defends
pbes2-padding-oracle (CWE-208) - defends
pbkdf2-work-dos (CWE-400)
pki.key.export
pki.key.export(key, opts?) -> Promise<Buffer|string>
Export an extractable CryptoKey to DER (or PEM): a private key as PKCS#8 OneAsymmetricKey, a public key as SubjectPublicKeyInfo. The encoding is delegated to the WebCrypto exportKey PKCS#8 / SPKI encoder, so the algorithm-specific AlgorithmIdentifier.parameters are byte-correct -- RSA carries an explicit NULL, EC a namedCurve OID, and Ed25519 / Ed448 / X25519 / X448 omit parameters (RFC 8410 sec. 3); the wrapper never re-encodes the AlgorithmIdentifier.
Options
- `format` (string) -- `der` (default) or `pem`.
- `label` (string) -- the PEM label (defaults `PRIVATE KEY` / `PUBLIC KEY` by key type).
Example
async function example() {
var pair = await pki.key.generate("Ed25519");
var spkiPem = await pki.key.export(pair.publicKey, { format: "pem" });
}
example();
References
- spec RFC 5958
- spec RFC 5280 sec. 4.1.2.7
- spec RFC 8410 sec. 3
pki.key.import
pki.key.import(input, opts?) -> Promise<CryptoKey>
Import a DER / PEM PKCS#8 private key, SPKI public key, or (with opts.password) an ENCRYPTED PRIVATE KEY -- auto-detecting the structure -- into a CryptoKey. The WebCrypto algorithm is inferred from the key's OID for the algorithms that name exactly one (Ed25519 / Ed448 / X25519 / X448 / ML-DSA / ML-KEM / SLH-DSA); RSA and EC are ambiguous between signing and key agreement, so opts.algorithm must be supplied for them (import fails closed rather than guess a use). Default key usages follow the algorithm and key type.
Options
- `algorithm` (string | object) -- the WebCrypto algorithm (required for RSA / EC; overrides inference).
- `usages` (string[]) -- key usages (default derived from the algorithm and public/private type).
- `extractable` (boolean) -- default false.
- `password` (string | Buffer) -- decrypt an `ENCRYPTED PRIVATE KEY` first.
Example
async function example() {
var pair = await pki.key.generate("Ed25519");
var spki = await pki.key.export(pair.publicKey);
var pub = await pki.key.import(spki); // Ed25519 -- algorithm inferred
}
example();
References
- spec RFC 5958
- spec RFC 5280 sec. 4.1.2.7
- spec RFC 8018
pki.key.generate
pki.key.generate(algorithm, opts?) -> Promise<{ privateKey, publicKey }>
Generate an asymmetric key pair over the WebCrypto engine: RSA, ECDSA / ECDH, Ed25519 / Ed448, X25519 / X448, and the FIPS post-quantum ML-DSA / ML-KEM. algorithm is a WebCrypto algorithm string or object; usages default to the algorithm's natural set (sign/verify, deriveBits/deriveKey, or encapsulate/ decapsulate) and keys are extractable by default. Returns the { privateKey, publicKey } CryptoKey pair.
Options
- `extractable` (boolean) -- default true.
- `usages` (string[]) -- override the default key usages.
Example
async function example() {
var pair = await pki.key.generate("Ed25519");
var pkcs8 = await pki.key.export(pair.privateKey);
}
example();
References
- spec W3C WebCrypto
- spec FIPS 203
- spec FIPS 204
pki.key.publicFromPrivate
pki.key.publicFromPrivate(privateKey, opts?) -> Promise<Buffer|string>
Derive the SubjectPublicKeyInfo (SPKI) public key from a PKCS#8 private key (DER Buffer, PRIVATE KEY PEM, or extractable private CryptoKey). The derivation is delegated to the node key engine, which infers the algorithm from the key structure, so no AlgorithmIdentifier is re-encoded -- Ed25519 stays parameters-absent, RSA keeps its NULL, EC keeps its namedCurve.
Options
- `pem` (boolean) -- return a `PUBLIC KEY` PEM string instead of DER.
Example
async function example() {
var pair = await pki.key.generate("Ed25519");
var spki = await pki.key.publicFromPrivate(await pki.key.export(pair.privateKey));
}
example();
References
- spec RFC 5280 sec. 4.1.2.7
- spec RFC 8410 sec. 3