{"record":{"id":"eaa809cd9e7b4ff8","repo":"gchq/CyberChef","slug":"not-a-key-exchange-init-eaa809","errorCode":null,"errorMessage":"Not a Key Exchange Init.","messagePattern":"Not a Key Exchange Init\\.","errorType":"exception","errorClass":"OperationError","httpStatus":null,"severity":"error","filePath":"src/core/operations/HASSHServerFingerprint.mjs","lineNumber":76,"sourceCode":"     */\n    run(input, args) {\n        const [inputFormat, outputFormat] = args;\n\n        input = Utils.convertToByteArray(input, inputFormat);\n        const s = new Stream(new Uint8Array(input));\n\n        // Length\n        const length = s.readInt(4);\n        if (s.length !== length + 4)\n            throw new OperationError(\"Incorrect packet length.\");\n\n        // Padding length\n        const paddingLength = s.readInt(1);\n\n        // Message code\n        const messageCode = s.readInt(1);\n        if (messageCode !== 20)\n            throw new OperationError(\"Not a Key Exchange Init.\");\n\n        // Cookie\n        s.moveForwardsBy(16);\n\n        // KEX Algorithms\n        const kexAlgosLength = s.readInt(4);\n        const kexAlgos = s.readString(kexAlgosLength);\n\n        // Server Host Key Algorithms\n        const serverHostKeyAlgosLength = s.readInt(4);\n        s.moveForwardsBy(serverHostKeyAlgosLength);\n\n        // Encryption Algorithms Client to Server\n        const encAlgosC2SLength = s.readInt(4);\n        s.moveForwardsBy(encAlgosC2SLength);\n\n        // Encryption Algorithms Server to Client\n        const encAlgosS2CLength = s.readInt(4);","sourceCodeStart":58,"sourceCodeEnd":94,"githubUrl":"https://github.com/gchq/CyberChef/blob/4290ea753912378913b1f3f54e0fc5720afeda5d/src/core/operations/HASSHServerFingerprint.mjs#L58-L94","documentation":"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.","triggerScenarios":"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).","commonSituations":"Direction confusion; capturing the wrong handshake stage; multi-record stream where the first server packet was a banner/EXT_INFO rather than KEXINIT.","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."],"exampleFix":"// before: first server packet was EXT_INFO (code 7)\nrun(extInfoHex, [\"Hex\", \"Hash\"]);\n// after: find the server KEXINIT record\nconst srvKex = srvRecords.find(r => r[5] === 0x14);\nrun(srvKex, [\"Hex\", \"Hash\"]);","handlingStrategy":"validation","validationCode":"function isServerKexInit(bytes) {\n  return bytes.length >= 6 && bytes[5] === 20;\n}","typeGuard":"function isServerKexInitRecord(bytes) {\n  return isCompleteServerSshPacket(bytes) && bytes[5] === 20;\n}","tryCatchPattern":"try {\n  hash = hasshServer.run(hexInput, args);\n} catch (e) {\n  if (e instanceof OperationError && /Key Exchange Init/i.test(e.message)) {\n    // not KEXINIT - advance to next server record\n    hash = await nextServerRecord();\n  } else throw e;\n}","preventionTips":["Confirm byte offset 5 is 0x14 before invoking.","Use the server-direction KEXINIT record.","Skip banners / EXT_INFO packets that precede KEXINIT."],"tags":["ssh","hassh","fingerprinting","message-code","kex-init"],"backgroundTag":null,"analyzedSha":"4290ea753912378913b1f3f54e0fc5720afeda5d","analyzedAt":"2026-08-13T06:05:50.210Z","schemaVersion":2},"datasetVersion":"2026-08-13T09:17:06.757Z"}