gchq/CyberChef · error · OperationError

Not a Key Exchange Init.

Error message

Not a Key Exchange Init.

What it means

Server-side twin of error 402. HASSH Server Fingerprint reads the message code byte and requires 20 (SSH_MSG_KEXINIT). A different code means the record is a different SSH message and the server's algorithm list cannot be extracted.

Source

Thrown at src/core/operations/HASSHServerFingerprint.mjs:76

     */
    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);
        s.moveForwardsBy(serverHostKeyAlgosLength);

        // Encryption Algorithms Client to Server
        const encAlgosC2SLength = s.readInt(4);
        s.moveForwardsBy(encAlgosC2SLength);

        // Encryption Algorithms Server to Client
        const encAlgosS2CLength = s.readInt(4);

View on GitHub (pinned to 4290ea7539)

Solutions

  1. Confirm byte 5 (offset 5 after the 4-byte length) is 0x14.
  2. Use the server-direction KEXINIT, not the client's.
  3. Pick the server record immediately following the client KEXINIT.
  4. If only EXT_INFO/banner was captured, re-grab the full handshake.

Example fix

// before: first server packet was EXT_INFO (code 7)
run(extInfoHex, ["Hex", "Hash"]);
// after: find the server KEXINIT record
const srvKex = srvRecords.find(r => r[5] === 0x14);
run(srvKex, ["Hex", "Hash"]);
Defensive patterns

Strategy: validation

Validate before calling

function isServerKexInit(bytes) {
  return bytes.length >= 6 && bytes[5] === 20;
}

Type guard

function isServerKexInitRecord(bytes) {
  return isCompleteServerSshPacket(bytes) && bytes[5] === 20;
}

Try / catch

try {
  hash = hasshServer.run(hexInput, args);
} catch (e) {
  if (e instanceof OperationError && /Key Exchange Init/i.test(e.message)) {
    // not KEXINIT - advance to next server record
    hash = await nextServerRecord();
  } else throw e;
}

Prevention

When it happens

Trigger: A valid SSH packet of any non-KEXINIT type fed to the server fingerprint op; client-direction KEXINIT bytes fed here; a post-KEXINIT record (e.g. SSH_MSG_KEXDH_REPLY=31).

Common situations: Direction confusion; capturing the wrong handshake stage; multi-record stream where the first server packet was a banner/EXT_INFO rather than KEXINIT.

Related errors


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