{"record":{"id":"4c91c4d5f0fdd966","repo":"denoland/deno","slug":"err-crypto-invalid-keylen","errorCode":"ERR_CRYPTO_INVALID_KEYLEN","errorMessage":"Unspecified validation error","messagePattern":"Unspecified validation error","errorType":"exception","errorClass":"NodeError","httpStatus":null,"severity":"error","filePath":"ext/node/polyfills/internal/crypto/diffiehellman.ts","lineNumber":267,"sourceCode":"    } else {\n      generator = this.#generator.readUint32BE();\n    }\n\n    if (generator != 2 && generator != 5) {\n      throw new NodeError(\"ERR_OSSL_DH_BAD_GENERATOR\", \"bad generator\");\n    }\n\n    return generator;\n  }\n\n  computeSecret(\n    otherPublicKey: ArrayBufferView | string,\n    inputEncoding?: any,\n    outputEncoding?: any,\n  ): Buffer | string {\n    const buf = getArrayBufferOrView(otherPublicKey, \"key\", inputEncoding);\n    if (buf.length === 0) {\n      throw new NodeError(\n        \"ERR_CRYPTO_INVALID_KEYLEN\",\n        \"Unspecified validation error\",\n      );\n    }\n\n    const sharedSecret = op_node_dh_compute_secret(\n      this.#prime,\n      this.#privateKey,\n      buf,\n    );\n\n    // Zero-pad the shared secret to the length of the prime, per RFC 4346\n    let secretBuf = Buffer.from(TypedArrayPrototypeGetBuffer(sharedSecret));\n    const primeLen = this.#prime.length;\n    if (secretBuf.length < primeLen) {\n      const padded = Buffer.alloc(primeLen);\n      secretBuf.copy(padded, primeLen - secretBuf.length);\n      secretBuf = padded;","sourceCodeStart":249,"sourceCodeEnd":285,"githubUrl":"https://github.com/denoland/deno/blob/9ad36f7a2cce60488e6ec52283efb32efddaf93a/ext/node/polyfills/internal/crypto/diffiehellman.ts#L249-L285","documentation":"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'.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Decode and check peer key length > 0 before calling computeSecret","Verify the input encoding matches how the peer serialized the key","Validate handshake message shape (required fields present, lengths plausible) before the DH layer"],"exampleFix":"// before\nconst secret = dh.computeSecret(peerKeyB64, 'base64'); // empty input throws\n\n// after\nconst peer = Buffer.from(peerKeyB64, 'base64');\nif (peer.length === 0) throw new Error('empty peer public key');\nconst secret = dh.computeSecret(peer);","handlingStrategy":"validation","validationCode":"const peer = Buffer.from(otherPublicKey, inputEncoding);\nif (peer.length === 0) throw new Error('empty peer public key');\nconst secret = dh.computeSecret(peer);","typeGuard":"function isNonEmptyKeyBytes(v) { return (ArrayBuffer.isView(v) && v.byteLength > 0) || (typeof v === 'string' && v.length > 0); }","tryCatchPattern":"try { secret = dh.computeSecret(peer); } catch (e) { if (e?.code === 'ERR_CRYPTO_INVALID_KEYLEN') { /* peer key was empty/corrupt — request retransmission */ } else throw e; }","preventionTips":["Validate handshake messages have a non-empty key field before touching DH","Confirm both sides agree on the key encoding (base64 vs hex) before decoding","Check decoded byte length against the expected size for the group/curve"],"tags":["crypto","diffiehellman","key-exchange","validation"],"backgroundTag":"empty-key-material","analyzedSha":"9ad36f7a2cce60488e6ec52283efb32efddaf93a","analyzedAt":"2026-08-20T13:07:44.778Z","schemaVersion":2},"datasetVersion":"2026-08-21T13:17:26.733Z"}