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.

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.

Appendix: 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)