denoland/deno · error · Error

Invalid key pair

Error message

Invalid key pair

What it means

computeSecret() rethrows 'Invalid key pair' as a plain Error when the native op_node_ecdh_compute_secret op fails with exactly that message. The peer public key passed structural validation, but the actual scalar-multiply/DH derivation failed for the (private, peerPublic) combination — OpenSSL's way of saying the pair cannot produce a shared secret.

Source

Thrown at ext/node/polyfills/internal/crypto/diffiehellman.ts:1473

    } else {
      const parts = getViewParts(otherPublicKey);
      otherBuf = Buffer.from(parts.ab, parts.off, parts.len);
    }

    const secretBuf = Buffer.alloc(this.#curve.sharedSecretSize);

    try {
      op_node_ecdh_compute_secret(
        this.#curve.name,
        this.#privbuf,
        this.#pubbuf,
        otherBuf,
        secretBuf,
      );
    } catch (e) {
      const err = e as any;
      if (err && err.message === "Invalid key pair") {
        throw new Error("Invalid key pair");
      }
      throw new ERR_CRYPTO_ECDH_INVALID_PUBLIC_KEY();
    }

    return ecdhEncode(secretBuf, outputEncoding ?? "buffer");
  }

  generateKeys(
    encoding?: any,
    format: any = "uncompressed",
  ): Buffer | string {
    validateEcdhFormat(format);
    const pubbuf = Buffer.alloc(
      format == "compressed"
        ? this.#curve.publicKeySizeCompressed
        : this.#curve.publicKeySize,
    );
    const privbuf = Buffer.alloc(this.#curve.privateKeySize);

View on GitHub (pinned to 9ad36f7a2c)

Solutions

  1. Re-verify the peer public key on the wire: recompute length and prefix, and re-send/re-fetch the key from the peer
  2. Confirm both sides really use the same curve — a same-length key from a different curve can reach the op and fail here
  3. Wrap computeSecret in try/catch and treat this message as 'bad peer key': abort the handshake and request re-keying rather than crashing

Example fix

// before
const secret = ecdh.computeSecret(peerPub);

// after
try {
  const secret = ecdh.computeSecret(peerPub);
} catch (e) {
  if (e.message === 'Invalid key pair') throw new Error('peer sent unusable public key');
  throw e;
}
Defensive patterns

Strategy: try-catch

Try / catch

try {
  const secret = ecdh.computeSecret(peerPub);
} catch (e) {
  if (e.message === 'Invalid key pair') {
    throw new Error('peer public key unusable; request re-key');
  }
  throw e;
}

Prevention

When it happens

Trigger: A peer public key that is well-formed for the curve but mathematically unusable with your private key (e.g. yields the point at infinity), or key bytes that happen to have a valid length/prefix but do not decode to a valid point during derivation.

Common situations: Interop bugs where a peer transmits truncated or corrupted key material of the right size; test suites feeding random buffers as 'public keys'; hand-rolled key serialization that mangles one byte.

Related errors


AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20). Data as JSON: /api/errors/df8a6f6378c77d3c. Report an issue: GitHub.