gchq/CyberChef · error · OperationError
Not a Key Exchange Init.
Error message
Not a Key Exchange Init.
What it means
Thrown by HASSH Client Fingerprint after the length/padding bytes are consumed. The SSH message code byte is read and compared against 20 (SSH_MSG_KEXINIT). Any other value means the record is not the key-exchange init message, so the HASSH algorithm string cannot be extracted.
Source
Thrown at src/core/operations/HASSHClientFingerprint.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);
const encAlgosC2S = s.readString(encAlgosC2SLength);
// Encryption Algorithms Server to Client
const encAlgosS2CLength = s.readInt(4);View on GitHub (pinned to 4290ea7539)
Solutions
- Confirm the packet is the client's SSH_MSG_KEXINIT (5th byte after the 4-byte length is decimal 20 / 0x14).
- Use HASSH Server Fingerprint if the bytes came from the server direction.
- Re-capture and pick the earliest KEX_INIT record in the TCP stream.
- Check byte 5 (0-indexed offset 5) equals 0x14 before invoking.
Example fix
// before: bytes are from a NEWKEYS (0x15) packet run(newkeysHex, ["Hex", "Hash"]); // after: select the record whose 5th byte is 0x14 const kexInit = records.find(r => r[5] === 0x14); run(kexInit, ["Hex", "Hash"]);
Defensive patterns
Strategy: validation
Validate before calling
function isKexInit(bytes) {
// message code sits at offset 5 (4-byte length + 1 padding-length byte)
return bytes.length >= 6 && bytes[5] === 20;
} Type guard
function isClientKexInit(bytes) {
return isCompleteSshPacket(bytes) && bytes[5] === 20;
} Try / catch
try {
hash = hasshClient.run(hexInput, args);
} catch (e) {
if (e instanceof OperationError && /Key Exchange Init/i.test(e.message)) {
// wrong message type - try the next record
hash = await nextRecord();
} else throw e;
} Prevention
- Verify byte offset 5 equals 0x14 (decimal 20) before invoking.
- Use the client-direction record for the client op.
- Pick the earliest KEX_INIT in the handshake.
When it happens
Trigger: Feeding a valid SSH packet that is a different message type (NEWKEYS=21, KEX_DH_INIT=30, DISCONNECT=1, service request, etc.); feeding the server's KEX_INIT to the client fingerprint operation; feeding a later-stage packet.
Common situations: Captured the wrong handshake message; used server-direction bytes in the client operation; reordered a multi-packet capture; the connection failed before KEXINIT and only a DISCONNECT was sent.
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/ed0f844b3a4f61af.
Report an issue: GitHub.