crypto.pbkdf2: ERR_OUT_OF_RANGE says ">= 1 and <= 2147483647", Node says ">= 1 && <= 2147483647"
crypto.pbkdf2 and crypto.pbkdf2Sync word the range of iterations and keylen differently from Node. A differential run against Node v26.3.0 found it. No user reported it.
const crypto = require("crypto");
for (const args of [["a", "b", 0, 1, "sha1"], ["a", "b", 1, -1, "sha1"]]) {
try { crypto.pbkdf2Sync(...args); } catch (e) { console.log(e.code, "|", e.message); }
}| message | |
|---|---|
| Node v26.3.0 | The value of "iterations" is out of range. It must be >= 1 && <= 2147483647. Received 0 |
| Bun 1.4.3-canary (main b64b63069c) | The value of "iterations" is out of range. It must be >= 1 and <= 2147483647. Received 0 |
| Node v26.3.0 | The value of "keylen" is out of range. It must be >= 0 && <= 2147483647. Received -1 |
| Bun 1.4.3-canary | The value of "keylen" is out of range. It must be >= 0 and <= 2147483647. Received -1 |
Node validates both arguments with validateInt32, which writes >= ${min} && <= ${max}. The and form is the wording of Node's Buffer and zlib bounds errors.
The cause is in src/runtime/crypto/PBKDF2.rs. Both checks call throw_range_error with RangeErrorOptions { min, max }, and the shared Rust formatter writes >= min and <= max for that form. fd_jsc.rs and node_crypto_binding.rs pass the range as msg (>= a && <= b) where Node uses a validator, and #40737 does the same for validators.rs. #40737 does not touch PBKDF2.rs.
test/js/node/crypto/pbkdf2.test.ts (lines 132 and 215) pins the and form for keylen, so a fix has to update those two expectations.
Source: oven-sh/bun