gchq/CyberChef · error · OperationError

Wrong key size

Error message

Wrong key size

What it means

LS47 is a 7x7 tile-based substitution cipher using a fixed 49-character alphabet (letters = "_abcdefghijklmnopqrstuvwxyz.0123456789,-+*/:?!'()"). The key must be a permutation of exactly those 49 characters. checkKey() rejects any key whose length differs from letters.length (49). This guard runs at the start of encrypt/decrypt/encryptPad/decryptPad before any cryptographic work.

Source

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

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;
}

/**
 * Checks the key is a valid key.
 *
 * @param {string} key
 */
function checkKey(key) {
    if (key.length !== letters.length)
        throw new OperationError("Wrong key size");
    const counts = new Array();
    for (let i = 0; i < letters.length; i++)
        counts[letters.charAt(i)] = 0;
    for (const elem of letters) {
        if (letters.indexOf(elem) === -1)
            throw new OperationError("Letter " + elem + " not in LS47");
        counts[elem]++;
        if (counts[elem] > 1)
            throw new OperationError("Letter duplicated in the key");
    }
}

/**
 * Finds the position of a letter in they key.
 *
 * @param {letter} key
 * @param {string} letter
 * @returns {object}

View on GitHub (pinned to 4290ea7539)

Solutions

  1. Generate the key with deriveKey(password) (exported from LS47.mjs) which always returns a valid 49-char permutation.
  2. Verify key.length === 49 before calling encrypt/decrypt and surface a clearer error to the end user.
  3. Strip whitespace/newlines from the key (key.replace(/\s/g, '')) before passing it in.
  4. If you have a hand-built key, confirm it contains exactly one of each of the 49 alphabet characters.

Example fix

// before
const ct = LS47.encrypt(myPassword, plaintext); // raw password -> Wrong key size

// after
LS47.initTiles();
const key = LS47.deriveKey(myPassword);    // 49-char permutation
const ct = LS47.encrypt(key, plaintext);
Defensive patterns

Strategy: validation

Validate before calling

import { initTiles, deriveKey } from './LS47.mjs';

function validLS47Key(key) {
  const ALPHABET = "_abcdefghijklmnopqrstuvwxyz.0123456789,-+*/:?!'()";
  return typeof key === 'string' &&
         key.length === 49 &&
         new Set(key).size === 49 &&
         [...key].every(c => ALPHABET.includes(c));
}

// use before encrypt/decrypt/encryptPad/decryptPad
initTiles();
const key = validLS47Key(myKey) ? myKey : deriveKey(passphrase);

Type guard

function isLS47Key(x): x is string {
  if (typeof x !== 'string' || x.length !== 49) return false;
  const ALPHABET = "_abcdefghijklmnopqrstuvwxyz.0123456789,-+*/:?!'()";
  return new Set(x).size === 49 && [...x].every(c => ALPHABET.includes(c));
}

Try / catch

try {
  const ct = LS47.encrypt(key, plaintext);
} catch (e) {
  if (e instanceof OperationError && /Wrong key size/.test(e.message)) {
    throw new Error('LS47 key must be a 49-character permutation; use deriveKey().');
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling encrypt(key, plaintext), decrypt(key, ciphertext), encryptPad(...), or decryptPad(...) with a key string whose .length !== 49. Common offenders: passing a raw password instead of a derived key, passing a hex/base64 key, or a manually typed key missing a character.

Common situations: User passes a human-typed passphrase straight to encrypt() rather than deriveKey(); key copied with a trailing newline or whitespace inflating length; key truncated by a paste operation; using an LS47+ key (longer alphabet) against the plain LS47 routine.

Related errors


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