denoland/deno · error · NodeError

ERR_CRYPTO_INVALID_KEYLEN

ERR_CRYPTO_INVALID_KEYLEN

Error message

Unspecified validation error

What it means

computeSecret (diffiehellman.ts:267) throws ERR_CRYPTO_INVALID_KEYLEN with message 'Unspecified validation error' when the peer public key buffer is empty. The length check runs before the native DH op, matching Node's rejection of zero-length peer keys; the code name is generic but here it always means 'empty otherPublicKey'.

Source

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

    } else {
      generator = this.#generator.readUint32BE();
    }

    if (generator != 2 && generator != 5) {
      throw new NodeError("ERR_OSSL_DH_BAD_GENERATOR", "bad generator");
    }

    return generator;
  }

  computeSecret(
    otherPublicKey: ArrayBufferView | string,
    inputEncoding?: any,
    outputEncoding?: any,
  ): Buffer | string {
    const buf = getArrayBufferOrView(otherPublicKey, "key", inputEncoding);
    if (buf.length === 0) {
      throw new NodeError(
        "ERR_CRYPTO_INVALID_KEYLEN",
        "Unspecified validation error",
      );
    }

    const sharedSecret = op_node_dh_compute_secret(
      this.#prime,
      this.#privateKey,
      buf,
    );

    // Zero-pad the shared secret to the length of the prime, per RFC 4346
    let secretBuf = Buffer.from(TypedArrayPrototypeGetBuffer(sharedSecret));
    const primeLen = this.#prime.length;
    if (secretBuf.length < primeLen) {
      const padded = Buffer.alloc(primeLen);
      secretBuf.copy(padded, primeLen - secretBuf.length);
      secretBuf = padded;

View on GitHub (pinned to 9ad36f7a2c)

Solutions

  1. Decode and check peer key length > 0 before calling computeSecret
  2. Verify the input encoding matches how the peer serialized the key
  3. Validate handshake message shape (required fields present, lengths plausible) before the DH layer

Example fix

// before
const secret = dh.computeSecret(peerKeyB64, 'base64'); // empty input throws

// after
const peer = Buffer.from(peerKeyB64, 'base64');
if (peer.length === 0) throw new Error('empty peer public key');
const secret = dh.computeSecret(peer);
Defensive patterns

Strategy: validation

Validate before calling

const peer = Buffer.from(otherPublicKey, inputEncoding);
if (peer.length === 0) throw new Error('empty peer public key');
const secret = dh.computeSecret(peer);

Type guard

function isNonEmptyKeyBytes(v) { return (ArrayBuffer.isView(v) && v.byteLength > 0) || (typeof v === 'string' && v.length > 0); }

Try / catch

try { secret = dh.computeSecret(peer); } catch (e) { if (e?.code === 'ERR_CRYPTO_INVALID_KEYLEN') { /* peer key was empty/corrupt — request retransmission */ } else throw e; }

Prevention

When it happens

Trigger: dh.computeSecret('') or computeSecret(Buffer.alloc(0)); a peer key string that decoded (base64/hex) to zero bytes; undefined passed as otherPublicKey and coerced by getArrayBufferOrView into empty input.

Common situations: Handshake messages with a missing key field; encoding mismatch (peer sent hex, receiver decodes base64) yielding empty/garbage output; truncated key-exchange payloads over the wire.

Related errors


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