OpenNHP/opennhp · error

unsupported GCM type

Error message

unsupported GCM type: %d

What it means

AeadFromKey returns this error when the GcmTypeEnum argument is not GCM_AES256 (0), GCM_SM4 (1), or GCM_CHACHA20POLY1305 (2). Because GcmTypeEnum is an int enum, any out-of-range integer — from bad config, wire data, or an uninitialized variable — lands in the default branch. It means an unrecognized AEAD algorithm selector reached the crypto layer.

Solutions

  1. Obtain GCM types via NewCipherSuite(scheme) instead of constructing them manually
  2. Validate externally-sourced integers against the GCM_AES256/GCM_SM4/GCM_CHACHA20POLY1305 constants before casting
  3. Log the numeric value and compare with the enum constants 0/1/2
  4. If a new constant was added, add its case to AeadFromKey (and CBC paths) and rebuild
  5. Note CBCEncryption has its own unsupported-value message — check which function actually returned the error

Example fix

// before
aead, err := core.AeadFromKey(core.GcmTypeEnum(cfg.AeadCode), &key)
// after
if cfg.AeadCode < int(core.GCM_AES256) || cfg.AeadCode > int(core.GCM_CHACHA20POLY1305) {
    return fmt.Errorf("invalid aead code %d", cfg.AeadCode)
}
aead, err := core.AeadFromKey(core.GcmTypeEnum(cfg.AeadCode), &key)
if err != nil {
    return err
}
Defensive patterns

Strategy: validation

Validate before calling

func isValidGcmType(t core.GcmTypeEnum) bool {
    return t >= core.GCM_AES256 && t <= core.GCM_CHACHA20POLY1305
}

if !isValidGcmType(t) {
    return fmt.Errorf("gcm type %d out of range", int(t))
}

Type guard

func asGcmType(v int) (core.GcmTypeEnum, bool) {
    if v < int(core.GCM_AES256) || v > int(core.GCM_CHACHA20POLY1305) {
        return 0, false
    }
    return core.GcmTypeEnum(v), true
}

Try / catch

aead, err := core.AeadFromKey(t, &key)
if err != nil {
    if strings.Contains(err.Error(), "unsupported GCM type") {
        return fmt.Errorf("bad AEAD selector %d: %w", int(t), err)
    }
    return err
}

Prevention

When it happens

Trigger: Passing a GcmTypeEnum cast from an unvalidated integer (e.g. -1 sentinel, value from config.toml or a protocol field), or adding a new GcmTypeEnum constant without a corresponding case in AeadFromKey.

Common situations: Mapping a cipher-scheme number to GCM type with an off-by-one or wrong table; deserializing a peer's algorithm identifier that doesn't match the local enum; extending the enum in a fork without updating the switch.

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/7714a1fd569195c7. Report an issue: GitHub.

Appendix: source

Thrown at nhp/core/crypto.go:183

		sm4Block, err := sm4.NewCipher(key[:16])
		if err != nil {
			return nil, fmt.Errorf("failed to create SM4 cipher: %w", err)
		}
		aead, err := cipher.NewGCM(sm4Block)
		if err != nil {
			return nil, fmt.Errorf("failed to create SM4-GCM: %w", err)
		}
		return aead, nil

	case GCM_CHACHA20POLY1305:
		aead, err := chacha20poly1305.New(key[:])
		if err != nil {
			return nil, fmt.Errorf("failed to create ChaCha20-Poly1305: %w", err)
		}
		return aead, nil

	default:
		return nil, fmt.Errorf("unsupported GCM type: %d", t)
	}
}

func CBCEncryption(t GcmTypeEnum, key *[SymmetricKeySize]byte, plaintext []byte, inPlace bool) ([]byte, error) {
	var block cipher.Block
	var iv []byte
	var err error
	switch t {
	case GCM_AES256:
		block, err = aes.NewCipher(key[:])
		if err != nil {
			return nil, fmt.Errorf("failed to create AES cipher for CBC: %w", err)
		}
		iv = key[8:24]

	case GCM_SM4:
		block, err = sm4.NewCipher(key[:16])
		if err != nil {

View on GitHub (pinned to 6e04ca5ff0)