gchq/CyberChef · error · OperationError

Incorrect packet length.

Error message

Incorrect packet length.

What it means

Thrown by HASSH Client Fingerprint while parsing the binary SSH packet. The first 4 bytes are the packet length; the operation asserts that stream length equals that value plus 4 (the length field excludes itself). Any byte stream that is not a complete SSH transport-layer packet trips this guard before the message code is even read.

Source

Thrown at src/core/operations/HASSHClientFingerprint.mjs:68

            }
        ];
    }

    /**
     * @param {string} input
     * @param {Object[]} args
     * @returns {string}
     */
    run(input, args) {
        const [inputFormat, outputFormat] = args;

        input = Utils.convertToByteArray(input, inputFormat);
        const s = new Stream(new Uint8Array(input));

        // Length
        const length = s.readInt(4);
        if (s.length !== length + 4)
            throw new OperationError("Incorrect packet length.");

        // Padding length
        const paddingLength = s.readInt(1);

        // Message code
        const messageCode = s.readInt(1);
        if (messageCode !== 20)
            throw new OperationError("Not a Key Exchange Init.");

        // Cookie
        s.moveForwardsBy(16);

        // KEX Algorithms
        const kexAlgosLength = s.readInt(4);
        const kexAlgos = s.readString(kexAlgosLength);

        // Server Host Key Algorithms
        const serverHostKeyAlgosLength = s.readInt(4);

View on GitHub (pinned to 4290ea7539)

Solutions

  1. Confirm the Input format argument matches how your bytes are encoded (Hex, Base64, Raw).
  2. Extract only the client->server SSH_MSG_KEXINIT record, including its 4-byte length prefix.
  3. Re-export the packet from Wireshark via 'Follow TCP Stream' -> 'client side only' and trim to the first record.
  4. Verify the byte count: total bytes must equal (first 4 bytes as big-endian uint32) + 4.

Example fix

// before: input is the KEX payload without the length prefix
const payload = captureWithoutLength;
run(payload, ["Hex", "Hash"]);
// after: prepend the 4-byte big-endian length
const len = payload.length / 2; // hex chars to bytes
const prefixed = len.toString(16).padStart(8, "0") + payload;
run(prefixed, ["Hex", "Hash"]);
Defensive patterns

Strategy: validation

Validate before calling

function assertSshPacket(bytes) {
  if (bytes.length < 5) throw new Error('packet too short');
  const len = (bytes[0]<<24 | bytes[1]<<16 | bytes[2]<<8 | bytes[3]) >>> 0;
  if (bytes.length !== len + 4) {
    throw new Error(`length mismatch: header says ${len}, got ${bytes.length-4} payload bytes`);
  }
  return len;
}

Type guard

function isCompleteSshPacket(bytes) {
  if (!(bytes instanceof Uint8Array) || bytes.length < 5) return false;
  const len = (bytes[0]<<24 | bytes[1]<<16 | bytes[2]<<8 | bytes[3]) >>> 0;
  return bytes.length === len + 4;
}

Try / catch

try {
  hash = hasshClient.run(hexInput, [inputFmt, outFmt]);
} catch (e) {
  if (e instanceof OperationError && /packet length/i.test(e.message)) {
    // not an SSH record - skip or re-capture
    return null;
  }
  throw e;
}

Prevention

When it happens

Trigger: Feeding a non-SSH byte stream, a truncated capture, a reassembled TCP stream missing bytes, or a packet from the wrong direction (server->client instead of client->server). Also triggered by base64/hex input when the input format argument does not match.

Common situations: Wrong input format selection (e.g. Hex bytes while the arg expects raw); copying only the KEX_INIT payload without its 4-byte length prefix; capturing post-handshake SSH traffic; feeding the entire TCP session rather than a single record.

Related errors


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