{"record":{"id":"a9a229669bd69de6","repo":"gchq/CyberChef","slug":"l-must-be-non-negative","errorCode":null,"errorMessage":"L must be non-negative","messagePattern":"L must be non-negative","errorType":"exception","errorClass":"OperationError","httpStatus":null,"severity":"error","filePath":"src/core/operations/DeriveHKDFKey.mjs","lineNumber":112,"sourceCode":"    }\n\n    /**\n     * @param {ArrayBuffer} input\n     * @param {Object[]} args\n     * @returns {ArrayBuffer}\n     */\n    run(input, args) {\n        const argSalt = Utils.convertToByteString(args[0].string || \"\", args[0].option),\n            info = Utils.convertToByteString(args[1].string || \"\", args[1].option),\n            hashFunc = args[2].toLowerCase(),\n            extractMode = args[3],\n            L = args[4],\n            IKM = Utils.arrayBufferToStr(input, false),\n            hasher = CryptoApi.getHasher(hashFunc),\n            HashLen = hasher.finalize().length;\n\n        if (L < 0) {\n            throw new OperationError(\"L must be non-negative\");\n        }\n        if (L > 255 * HashLen) {\n            throw new OperationError(\"L too large (maximum length for \" + args[2] + \" is \" + (255 * HashLen) + \")\");\n        }\n\n        const hmacHash = function(key, data) {\n            hasher.reset();\n            const mac = CryptoApi.getHmac(key, hasher);\n            mac.update(data);\n            return mac.finalize();\n        };\n        const salt = extractMode === \"with salt\" ? argSalt : \"\\0\".repeat(HashLen);\n        const PRK = extractMode === \"skip\" ? IKM : hmacHash(salt, IKM);\n        let T = \"\";\n        let result = \"\";\n        for (let i = 1; i <= 255 && result.length < L; i++) {\n            const TNext = hmacHash(PRK, T + info + String.fromCharCode(i));\n            result += TNext;","sourceCodeStart":94,"sourceCodeEnd":130,"githubUrl":"https://github.com/gchq/CyberChef/blob/4290ea753912378913b1f3f54e0fc5720afeda5d/src/core/operations/DeriveHKDFKey.mjs#L94-L130","documentation":"Thrown by Derive HKDF Key run() when L (the requested output length in octets) is negative. HKDF (RFC 5869) defines L as a non-negative integer; the operation's UI sets min:0 on the number argument, but a programmatic call or a hand-edited recipe can pass a negative value. The guard runs before any HKDF computation.","triggerScenarios":"Passing args[4] < 0 to run(). Possible via programmatic invocation, an imported recipe with a bad number, or a UI bug that allows a negative number through despite min:0.","commonSituations":"Automation/Node-API passing an unvalidated length; a recipe file with a corrupted L value; chaining an operation whose numeric output can be negative into this op's L argument.","solutions":["Set L to a non-negative value (0 returns an empty string, typical KDF lengths are 16/32/64).","Validate the length upstream before invoking run().","If the UI allows a negative value to slip through, report it as a UI min-enforcement bug; meanwhile clamp to 0."],"exampleFix":"// before\nconst args = [salt, info, \"SHA256\", \"with salt\", -16];\nop.run(input, args); // throws\n\n// after\nconst args = [salt, info, \"SHA256\", \"with salt\", 16];\nop.run(input, args);","handlingStrategy":"validation","validationCode":"function isValidHkdfLength(L) {\n    return Number.isInteger(L) && L >= 0;\n}","typeGuard":"/** @returns {boolean} */\nfunction isNonNegativeInt(L) {\n    return Number.isInteger(L) && L >= 0;\n}","tryCatchPattern":"try {\n    out = deriveHkdfKey.run(input, args);\n} catch (e) {\n    if (e instanceof OperationError && /L must be non-negative/.test(e.message)) {\n        args[4] = Math.max(0, Math.floor(args[4]));\n        out = deriveHkdfKey.run(input, args);\n    } else throw e;\n}","preventionTips":["Clamp L to a non-negative integer before invoking.","Validate numeric operation args when building recipes dynamically.","Prefer typical KDF lengths (16/32/64) unless more material is genuinely needed."],"tags":["crypto","hkdf","validation","argument"],"backgroundTag":null,"analyzedSha":"4290ea753912378913b1f3f54e0fc5720afeda5d","analyzedAt":"2026-08-13T06:05:50.210Z","schemaVersion":2},"datasetVersion":"2026-08-13T09:17:06.757Z"}