gchq/CyberChef · error · OperationError

Invalid block cipher mode: ${mode}

Error message

Invalid block cipher mode: ${mode}

What it means

Thrown by encryptTwofish() in Twofish.mjs (the encrypt switch `default` branch) when `mode` is not one of ECB, CBC, CFB, OFB, CTR. After padding is applied (for ECB/CBC) the function dispatches on mode; an unknown value is rejected rather than encrypting under an unspecified behaviour. Note the pad-then-dispatch ordering means a bad mode still triggers padding work first.

Source

Thrown at src/core/lib/Twofish.mjs:514

                const block = paddedMessage.slice(i, i + BLOCKSIZE);
                cipherText.push(...xorBlocks(ivBlock, block));
            }
            return cipherText.slice(0, messageLength);
        }

        case "CTR": {
            let counter = [...iv];
            for (let i = 0; i < paddedMessage.length; i += BLOCKSIZE) {
                const encrypted = encryptBlock(counter, keyData);
                const block = paddedMessage.slice(i, i + BLOCKSIZE);
                cipherText.push(...xorBlocks(encrypted, block));
                counter = incrementCounter(counter);
            }
            return cipherText.slice(0, messageLength);
        }

        default:
            throw new OperationError(`Invalid block cipher mode: ${mode}`);
    }

    return cipherText;
}

/**
 * Decrypt using Twofish cipher with specified block mode
 *
 * @param {number[]} cipherText - Ciphertext as byte array
 * @param {number[]} key - Key (16, 24, or 32 bytes)
 * @param {number[]} iv - IV (16 bytes, not used for ECB)
 * @param {string} mode - Block cipher mode ("ECB", "CBC", "CFB", "OFB", "CTR")
 * @param {string} padding - Padding type ("NO", "PKCS5", "ZERO", "RANDOM", "BIT")
 * @returns {number[]} - Plaintext as byte array
 */
export function decryptTwofish(cipherText, key, iv, mode = "ECB", padding = "PKCS5") {
    const originalLength = cipherText.length;
    if (originalLength === 0) return [];

View on GitHub (pinned to 4290ea7539)

Solutions

  1. Pass one of the exactly-cased supported modes: "ECB", "CBC", "CFB", "OFB", "CTR".
  2. Normalise the value (trim + toUpperCase) and validate against the whitelist before calling encryptTwofish.
  3. If you need an AEAD mode like GCM, Twofish is not implemented here — use a different cipher or library.

Example fix

// before
encryptTwofish(msg, key, iv, "gcm", "PKCS5");
// after
encryptTwofish(msg, key, iv, "CTR", "PKCS5");
Defensive patterns

Strategy: validation

Validate before calling

const MODES = ["ECB", "CBC", "CFB", "OFB", "CTR"];
const safeMode = String(mode ?? "").trim().toUpperCase();
if (!MODES.includes(safeMode)) {
    throw new Error(`Unsupported Twofish mode: '${mode}'. Use one of ${MODES.join(", ")}`);
}
encryptTwofish(msg, key, iv, safeMode, padding);

Type guard

function isTwofishMode(m) {
    return typeof m === "string" &&
        ["ECB", "CBC", "CFB", "OFB", "CTR"].includes(m);
}

Try / catch

try {
    ct = encryptTwofish(msg, key, iv, mode, padding);
} catch (e) {
    if (e instanceof OperationError && /Invalid block cipher mode/.test(e.message)) {
        return { error: `Mode '${mode}' not supported by Twofish.` };
    }
    throw e;
}

Prevention

When it happens

Trigger: Calling encryptTwofish() with a mode string other than the exact supported tokens: typos, wrong casing ("cbc"), unsupported modes ("GCM", "CCM", "PCBC"), or undefined. Distinct from the TEA equivalent only by library.

Common situations: Recipe/config value not whitelisted; cross-cipher copy of a mode constant; refactor that introduced a new spelling; default parameter overridden with an invalid value.

Related errors


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