{"record":{"id":"25a2ea66e4fb009f","repo":"OpenNHP/opennhp","slug":"extractinitiatorstaticpubkey-chain-hash-w","errorCode":null,"errorMessage":"extractInitiatorStaticPubKey: chain hash: %w","messagePattern":"extractInitiatorStaticPubKey: chain hash: %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"nhp/core/responder.go","lineNumber":140,"sourceCode":"// instances; doing it here too costs one extra ECDH per RKN-under-\n// overload packet, but keeps the noise-transcript machinery untouched\n// (and untouchable from this helper, which only takes a *Device, the\n// cipher suite, and the header).\nfunc extractInitiatorStaticPubKey(device *Device, ciphers *CipherSuite, header Header) ([]byte, error) {\n\tdeviceEcdh := device.GetEcdhByCipherScheme(header.CipherScheme())\n\n\tess := deviceEcdh.SharedSecret(header.EphermeralBytes())\n\tif ess == nil {\n\t\treturn nil, ErrDeviceECDHEphermalFailed\n\t}\n\tdefer SetZero(ess[:])\n\n\t// Local chain hash: InitialHash || serverPubKey || ephemeral\n\t// (mirrors validatePeer's ChainHash0 → ChainHash1 evolution, but\n\t// in a throwaway hash that never leaks back to ppd).\n\tchainHash, err := NewHash(ciphers.HashType)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"extractInitiatorStaticPubKey: chain hash: %w\", err)\n\t}\n\tchainHash.Write([]byte(InitialHashString))\n\tchainHash.Write(deviceEcdh.PublicKey())\n\tchainHash.Write(header.EphermeralBytes())\n\n\t// Local chain key: ChainKey0 = MixKey(InitialHash, InitialChainKey)\n\t// then ChainKey0 → ChainKey1 via ess.\n\tvar noise NoiseFactory\n\tnoise.HashType = ciphers.HashType\n\tvar chainKey [SymmetricKeySize]byte\n\tdefer SetZero(chainKey[:])\n\t// ChainKey0\n\tinitHash, err := NewHash(ciphers.HashType)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"extractInitiatorStaticPubKey: init hash: %w\", err)\n\t}\n\tinitHash.Write([]byte(InitialHashString))\n\tnoise.MixKey(&chainKey, initHash.Sum(nil), []byte(InitialChainKeyString))","sourceCodeStart":122,"sourceCodeEnd":158,"githubUrl":"https://github.com/OpenNHP/opennhp/blob/6e04ca5ff03222a699c24205cd4bf8fee9af7ffe/nhp/core/responder.go#L122-L158","documentation":"extractInitiatorStaticPubKey builds a throwaway chain hash (InitialHash || serverPubKey || ephemeral) to recover the initiator's static public key during checkHMAC. This error wraps a NewHash failure for the cipher suite's hash type, meaning the responder cannot even begin verifying the message.","triggerScenarios":"checkHMAC (nhp/core/responder.go:140) invoked during packet verification with ciphers.HashType that NewHash cannot instantiate (unknown algorithm, zero value, or missing crypto backend).","commonSituations":"Responder configured with a different/unknown cipher scheme than the peer; uninitialized CipherSuites in a custom code path; builds lacking SM3 (GMSM) support.","solutions":["Align the responder's cipher scheme configuration with the initiator's (both CURVE or both GMSM)","Validate ciphers.HashType is set from a supported scheme constant","Call NewHash(hashType) in an init check to fail fast at startup","Rebuild with complete crypto backends if hash algorithms were trimmed"],"exampleFix":"// before\nresponder, _ := nhpcore.NewDevice(nhpcore.NHP_SERVER)\nresponder.SetCiphers(&nhpcore.CipherSuites{}) // empty suite\n// after\nresponder.SetCiphers(nhpcore.NewCipherSuites(nhpcore.CIPHER_SCHEME_CURVE))","handlingStrategy":"validation","validationCode":"if _, err := nhpcore.NewHash(ciphers.HashType); err != nil {\n    return fmt.Errorf(\"responder hash type invalid: %w\", err)\n}","typeGuard":"func hashReady(c *nhpcore.CipherSuites) bool {\n    h, err := nhpcore.NewHash(c.HashType)\n    return err == nil && h != nil\n}","tryCatchPattern":"ppd, err := responder.PacketToMsg(pkt)\nif err != nil && strings.Contains(err.Error(), \"chain hash\") {\n    log.Errorf(\"cipher mismatch with initiator: %v\", err)\n    return\n}","preventionTips":["Keep responder and initiator cipher schemes in sync","Fail fast at startup by instantiating the hash once","Compile with all required crypto backends"],"tags":["go","crypto","responder"],"backgroundTag":"invalid-enum-value","analyzedSha":"6e04ca5ff03222a699c24205cd4bf8fee9af7ffe","analyzedAt":"2026-09-07T15:44:59.941Z","contentChangedAt":"2026-09-07T15:44:59.941Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}