{"record":{"id":"5475e82082903f88","repo":"gchq/CyberChef","slug":"invalid-key-length-key-length-bytes-xsalsa20","errorCode":null,"errorMessage":"Invalid key length: ${key.length} bytes.\n\nXSalsa20 uses a key of 16 or 32 bytes (128 or 256 bits).","messagePattern":"Invalid key length: (.+?) bytes\\.\n\nXSalsa20 uses a key of 16 or 32 bytes \\(128 or 256 bits\\)\\.","errorType":"validation","errorClass":"OperationError","httpStatus":null,"severity":"error","filePath":"src/core/operations/XSalsa20.mjs","lineNumber":80,"sourceCode":"                \"value\": [\"Raw\", \"Hex\"]\n            }\n        ];\n    }\n\n    /**\n     * @param {string} input\n     * @param {Object[]} args\n     * @returns {string}\n     */\n    run(input, args) {\n        const key = Utils.convertToByteArray(args[0].string, args[0].option),\n            nonceType = args[1].option,\n            rounds = parseInt(args[3], 10),\n            inputType = args[4],\n            outputType = args[5];\n\n        if (key.length !== 16 && key.length !== 32) {\n            throw new OperationError(`Invalid key length: ${key.length} bytes.\n\nXSalsa20 uses a key of 16 or 32 bytes (128 or 256 bits).`);\n        }\n\n        let counter, nonce;\n        if (nonceType === \"Integer\") {\n            nonce = Utils.intToByteArray(parseInt(args[1].string, 10), 8, \"little\");\n        } else {\n            nonce = Utils.convertToByteArray(args[1].string, args[1].option);\n            if (!(nonce.length === 24)) {\n                throw new OperationError(`Invalid nonce length: ${nonce.length} bytes.\n\nXSalsa20 uses a nonce of 24 bytes (192 bits).`);\n            }\n        }\n        counter = Utils.intToByteArray(args[2], 8, \"little\");\n\n        const xsalsaKey = hsalsa20(key, nonce.slice(0, 16), rounds);","sourceCodeStart":62,"sourceCodeEnd":98,"githubUrl":"https://github.com/gchq/CyberChef/blob/4290ea753912378913b1f3f54e0fc5720afeda5d/src/core/operations/XSalsa20.mjs#L62-L98","documentation":"Thrown by XSalsa20.run when the converted key byte array is neither 16 nor 32 bytes long. XSalsa20 accepts only a 128-bit or 256-bit key; any other length is rejected before nonce handling and before hsalsa20/key-stream generation.","triggerScenarios":"args[0].string interpreted via args[0].option (Hex/UTF8/Base64/etc.) produces a byte array whose length is not 16 or 32. Example: a 24-character hex string is only 12 bytes; a 32-char UTF8 key is 32 bytes (valid) but a 16-char UTF8 key is 16 bytes (valid) — anything in between or outside fails.","commonSituations":"Mismatch between the declared key format and the actual data (Hex vs UTF8 selected wrongly); pasting a Base64 key while 'Hex' is selected; trimming/padding the key; using an AES-128 (16-byte) key with the intent of 256-bit.","solutions":["Confirm the key is exactly 16 or 32 bytes when decoded: count raw bytes, not characters.","Verify the 'Key format' option (args[0].option) matches how the key is encoded — re-paste the key in the matching format.","Generate a fresh 32-byte key (e.g. 64 hex chars) and select 'Hex', or 32 UTF8 chars and select 'UTF8'.","If your key source is shorter, expand it via a KDF rather than zero-padding."],"exampleFix":"// before: 24 hex chars = 12 bytes -> invalid\nchef.bake(data, [{op:\"XSalsa20\", args:[{string:\"a1b2...24hex\",option:\"Hex\"}, ...]}]);\n// after: 64 hex chars = 32 bytes -> valid\nchef.bake(data, [{op:\"XSalsa20\", args:[{string:\"<64 hex chars>\",option:\"Hex\"}, ...]}]);","handlingStrategy":"validation","validationCode":"function xsalsa20KeyRecipe(keyStr, keyOption) {\n  const key = Utils.convertToByteArray(keyStr, keyOption);\n  if (key.length !== 16 && key.length !== 32) throw new Error(`XSalsa20 key must be 16 or 32 bytes, got ${key.length}`);\n  return [{string:keyStr, option:keyOption}];\n}","typeGuard":"const isXsalsa20KeyLen = (bytes) => bytes.length === 16 || bytes.length === 32;","tryCatchPattern":"try { chef.bake(data, recipe); } catch (e) { if (/Invalid key length/.test(e.message) && /XSalsa20/.test(e.message)) { /* fix key/option */ } else throw e; }","preventionTips":["Decode the key and assert byte length before building the recipe.","Keep key format option in sync with the key encoding.","Generate keys with a trusted RNG at 16/32 bytes."],"tags":["xsalsa20","crypto","key-length","operation-args"],"backgroundTag":null,"analyzedSha":"4290ea753912378913b1f3f54e0fc5720afeda5d","analyzedAt":"2026-08-13T06:05:50.210Z","schemaVersion":2},"datasetVersion":"2026-08-13T09:17:06.757Z"}