OpenNHP/opennhp · error

extractInitiatorStaticPubKey: aead

Error message

extractInitiatorStaticPubKey: aead: %w

What it means

After deriving the AEAD key (KeyGen2 from the Noise chain key and ephemeral shared secret), extractInitiatorStaticPubKey builds an AEAD instance via AeadFromKey using ciphers.GcmType (AES-256-GCM or SM4-GCM). This error means the AEAD construction itself failed — the key material was fine size-wise but the GcmType is not a recognized AEAD algorithm, or the AEAD backend could not accept the key.

Solutions

  1. Ensure the CipherSuite originates from NewCipherSuite(common.CIPHER_SCHEME_CURVE|GMSM) so HashType/GcmType are consistent with what AeadFromKey supports.
  2. Confirm both AES-GCM and SM4-GCM backends are compiled in for your build tags if using the GMSM scheme.
  3. Log ciphers.GcmType alongside the wrapped error to see which unsupported value reached AeadFromKey.
  4. If adding a new cipher scheme, register its AEAD constructor in AeadFromKey before deploying senders that use it.

Example fix

// before
suite := &core.CipherSuite{HashType: ht, GcmType: 99} // unsupported
peerPk, err := extractInitiatorStaticPubKey(dev, suite, hdr)
// after
suite := core.NewCipherSuite(common.CIPHER_SCHEME_GMSM)
peerPk, err := extractInitiatorStaticPubKey(dev, suite, hdr)
Defensive patterns

Strategy: validation

Validate before calling

switch suite.GcmType {
case common.CIPHER_SCHEME_CURVE, common.CIPHER_SCHEME_GMSM:
	// ok
default:
	return fmt.Errorf("unsupported gcm type %d", suite.GcmType)
}

Type guard

func hasKnownAead(c *core.CipherSuite) bool {
	return c != nil && c.GcmType == common.CIPHER_SCHEME_CURVE || (c != nil && c.GcmType == common.CIPHER_SCHEME_GMSM)
}

Try / catch

aead, err := AeadFromKey(ciphers.GcmType, &key)
if err != nil {
	log.Error("aead init failed gcmType=%d: %v", ciphers.GcmType, err)
	return nil, err // abort packet, do not fall through to cookie verification
}

Prevention

When it happens

Trigger: checkHMAC on an overload-path RKN packet where the CipherSuite's GcmType is not one of the registered GCM implementations (e.g. CipherSuite built manually with an unsupported GcmType constant), or an SM4/AES backend initialization failure in the crypto package.

Common situations: Mixing cipher scheme constants between builds (scheme table changed between versions so old persisted config maps to a GcmType that no longer exists); a custom crypto plugin returning an unsupported GcmType; corrupted in-memory CipherSuite.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


AI-assisted analysis of OpenNHP/opennhp@6e04ca5ff0 (2026-09-07). Data as JSON: /api/errors/48211cec52c5bcb4. Report an issue: GitHub.

Appendix: source

Thrown at nhp/core/responder.go:169

	defer SetZero(chainKey[:])
	// ChainKey0
	initHash, err := NewHash(ciphers.HashType)
	if err != nil {
		return nil, fmt.Errorf("extractInitiatorStaticPubKey: init hash: %w", err)
	}
	initHash.Write([]byte(InitialHashString))
	noise.MixKey(&chainKey, initHash.Sum(nil), []byte(InitialChainKeyString))
	// ChainKey0 → ChainKey1
	noise.MixKey(&chainKey, chainKey[:], header.EphermeralBytes())

	// Derive AEAD key for static-field decryption.
	var key [SymmetricKeySize]byte
	defer SetZero(key[:])
	noise.KeyGen2(&chainKey, &key, chainKey[:], ess[:])

	aead, err := AeadFromKey(ciphers.GcmType, &key)
	if err != nil {
		return nil, fmt.Errorf("extractInitiatorStaticPubKey: aead: %w", err)
	}
	// Trust the AEAD's returned plaintext length over a static
	// scheme→size mapping. The previous version allocated a
	// PublicKeySizeEx-sized buffer and sliced it back down based on
	// header.CipherScheme(); that worked because the only two ciphers
	// today happen to match the scheme→size table exactly, but a
	// future cipher whose plaintext length doesn't fit either fixed
	// size would silently mis-key the cookie HMAC (Open writes
	// however many bytes the AEAD decrypted, then the caller would
	// either truncate them or hash trailing zero-padding).
	//
	// Validate the length explicitly before returning so future
	// breakage manifests as an error here, not as cookie failures
	// further down. Pass nil for the dst so Open allocates exactly
	// the right size.
	peerPk, err := aead.Open(nil, header.NonceBytes(), header.StaticBytes(), chainHash.Sum(nil))
	if err != nil {
		return nil, fmt.Errorf("extractInitiatorStaticPubKey: open: %w", err)

View on GitHub (pinned to 6e04ca5ff0)