gchq/CyberChef · error · OperationError

input must be 8n (n>=2) bytes (currently " + inputData.lengt

Error message

input must be 8n (n>=2) bytes (currently " + inputData.length + " bytes)

What it means

RFC 3394 requires the key material being wrapped to be at least 2 blocks (n≥2), i.e. a multiple of 8 bytes and ≥ 16 bytes. AESKeyWrap throws this when inputData.length % 8 !== 0 or inputData.length < 16. (Compare with unwrap, which needs ≥ 24 because the wrapped form adds one IV block.)

Source

Thrown at src/core/operations/AESKeyWrap.mjs:75

     * @param {string} input
     * @param {Object[]} args
     * @returns {string}
     */
    run(input, args) {
        const kek = Utils.convertToByteString(args[0].string, args[0].option),
            iv = Utils.convertToByteString(args[1].string, args[1].option),
            inputType = args[2],
            outputType = args[3];

        if (kek.length !== 16 && kek.length !== 24 && kek.length !== 32) {
            throw new OperationError("KEK must be either 16, 24, or 32 bytes (currently " + kek.length + " bytes)");
        }
        if (iv.length !== 8) {
            throw new OperationError("IV must be 8 bytes (currently " + iv.length + " bytes)");
        }
        const inputData = Utils.convertToByteString(input, inputType);
        if (inputData.length % 8 !== 0 || inputData.length < 16) {
            throw new OperationError("input must be 8n (n>=2) bytes (currently " + inputData.length + " bytes)");
        }

        const cipher = forge.cipher.createCipher("AES-ECB", kek);

        let A = iv;
        const R = [];
        for (let i = 0; i < inputData.length; i += 8) {
            R.push(inputData.substring(i, i + 8));
        }
        let cntLower = 1, cntUpper = 0;
        for (let j = 0; j < 6; j++) {
            for (let i = 0; i < R.length; i++) {
                cipher.start();
                cipher.update(forge.util.createBuffer(A + R[i]));
                cipher.finish();
                const B = cipher.output.getBytes();
                const msbBuffer = Utils.strToArrayBuffer(B.substring(0, 8));
                const msbView = new DataView(msbBuffer);

View on GitHub (pinned to 4290ea7539)

Solutions

  1. Confirm the input is the raw key material (e.g. a 16/24/32-byte AES key) you intend to protect.
  2. Verify the input format option and that decoding yields a multiple of 8 bytes ≥ 16.
  3. If you genuinely have an 8-byte key, note RFC 3394 disallows it — use a different wrapping scheme or pad per your protocol.

Example fix

// before: wrap an 8-byte DES key → throws (n must be ≥2)
// after: wrap a 16/24/32-byte AES key instead
Defensive patterns

Strategy: validation

Validate before calling

function validateKeyMaterial(bytes) {
  if (bytes.length % 8 !== 0 || bytes.length < 16) {
    throw new Error(`Key material must be 8n (n>=2) bytes, got ${bytes.length}`);
  }
}

Type guard

function isWrappableKey(bytes) { return bytes.length >= 16 && bytes.length % 8 === 0; }

Try / catch

try { aesKeyWrap(...); } catch (e) { if (/input must be 8n/.test(e.message)) {/* supply ≥16-byte key material */} else throw e; }

Prevention

When it happens

Trigger: The key-data input is not a multiple of 8 bytes, or is shorter than 16 bytes. For example, trying to wrap a single 8-byte block, or feeding an odd-length hex string that decodes to a non-multiple-of-8 byte count.

Common situations: Attempting to wrap a DES-size (8-byte) key (too small); format-option mismatch producing wrong byte count; truncated key material; user fed already-wrapped data by mistake.

Related errors


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