gchq/CyberChef · error · OperationError
Invalid nonce length: ${nonce.length} bytes. XSalsa20 uses
Error message
Invalid nonce length: ${nonce.length} bytes.
XSalsa20 uses a nonce of 24 bytes (192 bits). What it means
Thrown by XSalsa20.run in the non-Integer nonce branch when the decoded nonce byte array is not exactly 24 bytes. XSalsa20 requires a 192-bit (24-byte) nonce; the 'Integer' option derives an 8-byte nonce from args[1].string and is handled separately, so this check only applies to user-supplied nonce formats (Hex/UTF8/Base64...).
Source
Thrown at src/core/operations/XSalsa20.mjs:91
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);
const output = [];
input = Utils.convertToByteArray(input, inputType);
let counterAsInt = Utils.byteArrayToInt(counter, "little");
for (let i = 0; i < input.length; i += 64) {
counter = Utils.intToByteArray(counterAsInt, 8, "little");
const stream = salsa20Block(xsalsaKey, nonce.slice(16, 24), counter, rounds);
for (let j = 0; j < 64 && i + j < input.length; j++) {
output.push(input[i + j] ^ stream[j]);
}View on GitHub (pinned to 4290ea7539)
Solutions
- Provide exactly 24 bytes of nonce (48 hex characters, 24 UTF8 bytes, or 32 Base64 chars).
- Confirm args[1].option matches the nonce encoding.
- Use the 'Integer' nonce option if you want to specify a small counter as a number instead of raw bytes.
Example fix
// before: 24 hex chars -> 12-byte nonce
args:[{string:"<key>",option:"Hex"},{string:"aabb...24hex",option:"Hex"}, ...]
// after: 48 hex chars -> 24-byte nonce
args:[{string:"<key>",option:"Hex"},{string:"<48 hex chars>",option:"Hex"}, ...] Defensive patterns
Strategy: validation
Validate before calling
function xsalsa20NonceRecipe(nonceStr, nonceOption) {
if (nonceOption === "Integer") return {string:nonceStr, option:nonceOption};
const n = Utils.convertToByteArray(nonceStr, nonceOption);
if (n.length !== 24) throw new Error(`XSalsa20 nonce must be 24 bytes, got ${n.length}`);
return {string:nonceStr, option:nonceOption};
} Type guard
const isXsalsa20NonceLen = (bytes) => bytes.length === 24;
Try / catch
try { chef.bake(data, recipe); } catch (e) { if (/Invalid nonce length/.test(e.message) && /XSalsa20/.test(e.message)) { /* fix nonce */ } else throw e; } Prevention
- Use 24-byte (192-bit) nonces; do not reuse Salsa20's 12-byte nonce.
- Match the nonce format option to the encoding.
- Prefer the Integer nonce option only for counter-style nonces.
When it happens
Trigger: nonceType (args[1].option) is not 'Integer', so Utils.convertToByteArray is used; the resulting nonce is not 24 bytes. Example: a 24-character hex nonce is only 12 bytes (invalid); 48 hex chars = 24 bytes (valid).
Common situations: Selecting Hex for the nonce but supplying a UTF8-length nonce (or vice versa); reusing a 12-byte Salsa20 nonce with XSalsa20; truncating the nonce during copy-paste.
Related errors
- Invalid key length: ${key.length} bytes. XSalsa20 uses a ke
- Invalid nonce length: ${nonce.length} bytes. Ascon-AEAD128
- Invalid nonce length: ${nonce.length} bytes. Ascon-AEAD128
- Invalid key length: ${key.length} bytes XTEA requires a key
- Invalid IV length: ${iv.length} bytes XTEA uses an IV lengt
AI-assisted analysis of gchq/CyberChef@4290ea7539 (2026-08-13).
Data as JSON: /api/errors/38ccb6dc190a26e6.
Report an issue: GitHub.