gchq/CyberChef · error · OperationError

Invalid key length: ${key.length} bytes. XSalsa20 uses a ke

Error message

Invalid key length: ${key.length} bytes.

XSalsa20 uses a key of 16 or 32 bytes (128 or 256 bits).

What it means

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.

Source

Thrown at src/core/operations/XSalsa20.mjs:80

                "value": ["Raw", "Hex"]
            }
        ];
    }

    /**
     * @param {string} input
     * @param {Object[]} args
     * @returns {string}
     */
    run(input, args) {
        const key = Utils.convertToByteArray(args[0].string, args[0].option),
            nonceType = args[1].option,
            rounds = parseInt(args[3], 10),
            inputType = args[4],
            outputType = args[5];

        if (key.length !== 16 && key.length !== 32) {
            throw new OperationError(`Invalid key length: ${key.length} bytes.

XSalsa20 uses a key of 16 or 32 bytes (128 or 256 bits).`);
        }

        let counter, nonce;
        if (nonceType === "Integer") {
            nonce = Utils.intToByteArray(parseInt(args[1].string, 10), 8, "little");
        } else {
            nonce = Utils.convertToByteArray(args[1].string, args[1].option);
            if (!(nonce.length === 24)) {
                throw new OperationError(`Invalid nonce length: ${nonce.length} bytes.

XSalsa20 uses a nonce of 24 bytes (192 bits).`);
            }
        }
        counter = Utils.intToByteArray(args[2], 8, "little");

        const xsalsaKey = hsalsa20(key, nonce.slice(0, 16), rounds);

View on GitHub (pinned to 4290ea7539)

Solutions

  1. Confirm the key is exactly 16 or 32 bytes when decoded: count raw bytes, not characters.
  2. Verify the 'Key format' option (args[0].option) matches how the key is encoded — re-paste the key in the matching format.
  3. Generate a fresh 32-byte key (e.g. 64 hex chars) and select 'Hex', or 32 UTF8 chars and select 'UTF8'.
  4. If your key source is shorter, expand it via a KDF rather than zero-padding.

Example fix

// before: 24 hex chars = 12 bytes -> invalid
chef.bake(data, [{op:"XSalsa20", args:[{string:"a1b2...24hex",option:"Hex"}, ...]}]);
// after: 64 hex chars = 32 bytes -> valid
chef.bake(data, [{op:"XSalsa20", args:[{string:"<64 hex chars>",option:"Hex"}, ...]}]);
Defensive patterns

Strategy: validation

Validate before calling

function xsalsa20KeyRecipe(keyStr, keyOption) {
  const key = Utils.convertToByteArray(keyStr, keyOption);
  if (key.length !== 16 && key.length !== 32) throw new Error(`XSalsa20 key must be 16 or 32 bytes, got ${key.length}`);
  return [{string:keyStr, option:keyOption}];
}

Type guard

const isXsalsa20KeyLen = (bytes) => bytes.length === 16 || bytes.length === 32;

Try / catch

try { chef.bake(data, recipe); } catch (e) { if (/Invalid key length/.test(e.message) && /XSalsa20/.test(e.message)) { /* fix key/option */ } else throw e; }

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of gchq/CyberChef@4290ea7539 (2026-08-13). Data as JSON: /api/errors/5475e82082903f88. Report an issue: GitHub.