{"record":{"id":"e46025211a22b87a","repo":"gchq/CyberChef","slug":"letter-letter-is-not-included-in-ls47","errorCode":null,"errorMessage":"Letter ${letter} is not included in LS47","messagePattern":"Letter (.+?) is not included in LS47","errorType":"exception","errorClass":"OperationError","httpStatus":null,"severity":"error","filePath":"src/core/lib/LS47.mjs","lineNumber":72,"sourceCode":" * @returns {string}\n */\nfunction rotateRight(key, row, n) {\n    const mid = key.slice(row * 7, (row + 1) * 7);\n    n = (7 - n % 7) % 7;\n    return key.slice(0, 7 * row) + mid.slice(n) + mid.slice(0, n) + key.slice(7 * (row + 1));\n}\n\n/**\n * Finds the position of a letter in the tiles.\n *\n * @param {string} letter\n * @returns {string}\n */\nfunction findIx(letter) {\n    for (let i = 0; i < tiles.length; i++)\n        if (tiles[i][0] === letter)\n            return tiles[i][1];\n    throw new OperationError(\"Letter \" + letter + \" is not included in LS47\");\n}\n\n/**\n * Derives key from the input password.\n *\n * @param {string} password\n * @returns {string}\n */\nexport function deriveKey(password) {\n    let i = 0;\n    let k = letters;\n    for (const c of password) {\n        const [row, col] = findIx(c);\n        k = rotateDown(rotateRight(k, i, col), i, row);\n        i = (i + 1) % 7;\n    }\n    return k;\n}","sourceCodeStart":54,"sourceCodeEnd":90,"githubUrl":"https://github.com/gchq/CyberChef/blob/4290ea753912378913b1f3f54e0fc5720afeda5d/src/core/lib/LS47.mjs#L54-L90","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","solutions":["Call initTiles() once before any encrypt/decrypt/deriveKey call.","Sanitise input so every character is in the LS47 alphabet (lowercase the text; strip or reject unsupported symbols/whitespace).","Validate the input string against the alphabet before processing."],"exampleFix":"// before\ninitTiles(); // forgotten, or input has uppercase\nderiveKey(\"P@ssword\");\n\n// after\nimport { initTiles } from \"./LS47.mjs\";\ninitTiles();\nconst ALPHABET = \"_abcdefghijklmnopqrstuvwxyz.0123456789,-+*/:?!'()\";\nconst clean = [...\"Password\"].map(c => ALPHABET.includes(c.toLowerCase()) ? c.toLowerCase() : \"\").join(\"\");\nderiveKey(clean);","handlingStrategy":"validation","validationCode":"import { initTiles } from \"./LS47.mjs\";\ninitTiles(); // MUST run before any encrypt/decrypt/deriveKey\nconst LS47_ALPHABET = \"_abcdefghijklmnopqrstuvwxyz.0123456789,-+*/:?!'()\";\nfunction sanitizeLS47(input) {\n  let out = \"\";\n  for (const ch of input) {\n    const lower = ch.toLowerCase();\n    const candidate = LS47_ALPHABET.includes(lower) ? lower : (LS47_ALPHABET.includes(ch) ? ch : null);\n    if (candidate !== null) out += candidate;\n  }\n  return out;\n}\nconst clean = sanitizeLS47(userInput);\nderiveKey(clean);","typeGuard":"const isInLS47Alphabet = ch => LS47_ALPHABET.includes(ch);\nconst isLS47Safe = str => [...str].every(isInLS47Alphabet);","tryCatchPattern":"try {\n  deriveKey(password);\n} catch (err) {\n  if (err instanceof OperationError && /is not included in LS47/.test(err.message)) {\n    // input contained an out-of-alphabet char; sanitize and retry\n  } else throw err;\n}","preventionTips":["Always call initTiles() once before any LS47 operation when using the library standalone.","Lowercase input and strip unsupported symbols/whitespace before processing.","Validate every char against the 49-char LS47 alphabet before calling encrypt/decrypt/deriveKey."],"tags":["ls47","crypto","alphabet","validation","initialization"],"backgroundTag":null,"analyzedSha":"4290ea753912378913b1f3f54e0fc5720afeda5d","analyzedAt":"2026-08-13T06:05:50.210Z","schemaVersion":2},"datasetVersion":"2026-08-13T09:17:06.757Z"}