gchq/CyberChef · error · OperationError

Letter ${letter} is not included in LS47

Error message

Letter ${letter} is not included in LS47

What it means

Thrown by the internal findIx helper in LS47.mjs when a character is not present in the LS47 tile alphabet. LS47 uses a fixed 49-character 7x7 grid: `_abcdefghijklmnopqrstuvwxyz.0123456789,-+*/:?!'()`. findIx linearly scans the tiles array; a character outside that set, or any lookup before tiles have been populated, throws. OperationError.

Source

Thrown at src/core/lib/LS47.mjs:72

 * @returns {string}
 */
function rotateRight(key, row, n) {
    const mid = key.slice(row * 7, (row + 1) * 7);
    n = (7 - n % 7) % 7;
    return key.slice(0, 7 * row) + mid.slice(n) + mid.slice(0, n) + key.slice(7 * (row + 1));
}

/**
 * Finds the position of a letter in the tiles.
 *
 * @param {string} letter
 * @returns {string}
 */
function findIx(letter) {
    for (let i = 0; i < tiles.length; i++)
        if (tiles[i][0] === letter)
            return tiles[i][1];
    throw new OperationError("Letter " + letter + " is not included in LS47");
}

/**
 * Derives key from the input password.
 *
 * @param {string} password
 * @returns {string}
 */
export function deriveKey(password) {
    let i = 0;
    let k = letters;
    for (const c of password) {
        const [row, col] = findIx(c);
        k = rotateDown(rotateRight(k, i, col), i, row);
        i = (i + 1) % 7;
    }
    return k;
}

View on GitHub (pinned to 4290ea7539)

Solutions

  1. Call initTiles() once before any encrypt/decrypt/deriveKey call.
  2. Sanitise input so every character is in the LS47 alphabet (lowercase the text; strip or reject unsupported symbols/whitespace).
  3. Validate the input string against the alphabet before processing.

Example fix

// before
initTiles(); // forgotten, or input has uppercase
deriveKey("P@ssword");

// after
import { initTiles } from "./LS47.mjs";
initTiles();
const ALPHABET = "_abcdefghijklmnopqrstuvwxyz.0123456789,-+*/:?!'()";
const clean = [..."Password"].map(c => ALPHABET.includes(c.toLowerCase()) ? c.toLowerCase() : "").join("");
deriveKey(clean);
Defensive patterns

Strategy: validation

Validate before calling

import { initTiles } from "./LS47.mjs";
initTiles(); // MUST run before any encrypt/decrypt/deriveKey
const LS47_ALPHABET = "_abcdefghijklmnopqrstuvwxyz.0123456789,-+*/:?!'()";
function sanitizeLS47(input) {
  let out = "";
  for (const ch of input) {
    const lower = ch.toLowerCase();
    const candidate = LS47_ALPHABET.includes(lower) ? lower : (LS47_ALPHABET.includes(ch) ? ch : null);
    if (candidate !== null) out += candidate;
  }
  return out;
}
const clean = sanitizeLS47(userInput);
deriveKey(clean);

Type guard

const isInLS47Alphabet = ch => LS47_ALPHABET.includes(ch);
const isLS47Safe = str => [...str].every(isInLS47Alphabet);

Try / catch

try {
  deriveKey(password);
} catch (err) {
  if (err instanceof OperationError && /is not included in LS47/.test(err.message)) {
    // input contained an out-of-alphabet char; sanitize and retry
  } else throw err;
}

Prevention

When it happens

Trigger: Calling encrypt/decrypt/deriveKey with input or a key/password containing characters outside the LS47 alphabet (uppercase letters, '@', '#', '%', '&', space, newline, tabs), OR calling any LS47 function before `initTiles()` has run (tiles is empty, so every lookup throws).

Common situations: Feeding mixed-case or punctuation-rich text; pasting text with whitespace/newlines; forgetting to call initTiles() when using the library standalone; key derived from user input that includes unsupported symbols.

Related errors


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