denoland/deno · error · ERR_CRYPTO_INVALID_KEYLEN
ERR_CRYPTO_INVALID_KEYLEN
ERR_CRYPTO_INVALID_KEYLEN
Error message
Invalid key length
What it means
HKDF (RFC 5869) can output at most 255 times the hash digest length, because HKDF-Expand runs at most 255 iterations of the HMAC loop. The polyfill enforces this in validateParameters (ext/node/polyfills/internal/crypto/hkdf.ts:95-98): if hashSize * 255 < length it throws ERR_CRYPTO_INVALID_KEYLEN ('Invalid key length') before any native op runs.
Source
Thrown at ext/node/polyfills/internal/crypto/hkdf.ts:97
salt = toRawBytes(toBuf(salt));
info = toRawBytes(toBuf(info));
validateInteger(length, "length", 0, kMaxLength);
if (TypedArrayPrototypeGetByteLength(info) > 1024) {
throw new ERR_OUT_OF_RANGE(
"info",
"must not contain more than 1024 bytes",
TypedArrayPrototypeGetByteLength(info),
);
}
validateAlgorithm(hash);
const size = op_node_get_hash_size(hash);
if (typeof size === "number" && size * 255 < length) {
throw new ERR_CRYPTO_INVALID_KEYLEN();
}
return {
hash,
key,
salt,
info,
length,
};
},
);
function prepareKey(key: any) {
if (isKeyObject(key)) {
return key;
}
if (isAnyArrayBuffer(key)) {View on GitHub (pinned to 9ad36f7a2c)
Solutions
- Cap length at 255 * hashSize: 8160 for sha256, 5100 for sha1, 10200 for sha384, 16320 for sha512.
- Derive a master key once, then derive independent subkeys with distinct short info labels.
- If you need long random material, derive a 32-byte key and use it to seed a stream/XOF (e.g. ChaCha, shake256) instead.
- Validate/clamp the length parameter at your API boundary before it reaches hkdf.
Example fix
// before
crypto.hkdfSync('sha256', ikm, salt, info, 10000); // > 255*32 -> ERR_CRYPTO_INVALID_KEYLEN
// after
const MAX = 255 * crypto.createHash('sha256').digest().length; // 8160
crypto.hkdfSync('sha256', ikm, salt, info, Math.min(10000, MAX));
// or split into labeled subkeys:
const enc = crypto.hkdfSync('sha256', ikm, salt, Buffer.from('enc'), 32);
const mac = crypto.hkdfSync('sha256', ikm, salt, Buffer.from('mac'), 32); Defensive patterns
Strategy: validation
Validate before calling
const HKDF_MAX = { sha1: 5100, sha256: 8160, sha384: 10200, sha512: 16320 };
function assertHkdfLength(digest, length) {
const max = 255 * crypto.createHash(digest).digest().length;
if (!(Number.isInteger(length) && length >= 0 && length <= max)) {
throw new RangeError(`hkdf length for ${digest} must be 0..${max}, got ${length}`);
}
}
assertHkdfLength('sha256', wanted);
crypto.hkdfSync('sha256', ikm, salt, info, wanted); Try / catch
try {
okm = crypto.hkdfSync(digest, ikm, salt, info, length);
} catch (e) {
if (e.code === 'ERR_CRYPTO_INVALID_KEYLEN') {
throw new Error(`HKDF output capped at ${255 * hashBytes} bytes; derive subkeys with distinct info labels instead`);
}
throw e;
} Prevention
- Derive fixed-size subkeys (e.g. 32 bytes each) with distinct info labels rather than one huge output.
- Clamp any user- or config-supplied length against 255 * hashSize before calling hkdf.
- Remember the caps: sha256 8160, sha512 16320, sha1 5100 bytes.
When it happens
Trigger: crypto.hkdfSync('sha256', ikm, salt, info, 8161) (255*32 = 8160 for SHA-256); requesting 64 KiB or more of output material from hkdf; hkdf with sha1 (max 5100 bytes) or sha512 (max 16320 bytes) and a length above that bound.
Common situations: Deriving many subkeys or a whole file-encryption key bundle in one hkdf call; porting code from libraries that chunk HKDF output automatically; parameterizing output length from user input or config without an upper bound.
Related errors
- ERR_OUT_OF_RANGE
- ERR_INVALID_ARG_TYPE
- ERR_CRYPTO_INVALID_DIGEST
- HKDF keys are not extractable
- Unsupported key usage for an HKDF key
AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20).
Data as JSON: /api/errors/dbd15642ec5d7bb9.
Report an issue: GitHub.