Keys

The key-material lifecycle: export / import a private key as PKCS#8 (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

since 0.3.10 experimental
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

pki.key.decrypt

since 0.3.10 experimental
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

pki.key.export

since 0.3.10 experimental
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

pki.key.import

since 0.3.10 experimental
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

pki.key.generate

since 0.3.10 experimental
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

pki.key.publicFromPrivate

since 0.3.10 experimental
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