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
- Confirm byte 5 (offset 5 after the 4-byte length) is 0x14.
- Use the server-direction KEXINIT, not the client's.
- Pick the server record immediately following the client KEXINIT.
- 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
- Confirm byte offset 5 is 0x14 before invoking.
- Use the server-direction KEXINIT record.
- Skip banners / EXT_INFO packets that precede KEXINIT.
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
- Not a Key Exchange Init.
- Incorrect packet length.
- Incorrect packet length.
- Data is not a valid TLS Client Hello. QUIC is not yet suppor
- Data is not a valid TLS Server Hello. QUIC is not yet suppor
AI-assisted analysis of gchq/CyberChef@4290ea7539 (2026-08-13).
Data as JSON: /api/errors/eaa809cd9e7b4ff8.
Report an issue: GitHub.