OpenNHP/opennhp · error

unsupported cipher type for CBC decryption

Error message

unsupported cipher type for CBC decryption: %d

What it means

CBCDecryption's default branch rejects any GcmTypeEnum that is neither GCM_AES256, GCM_SM4, nor GCM_CHACHA20POLY1305 (which is rejected earlier as ErrNotApplicable). CBC is a block-cipher mode, so an unknown/invalid cipher-type integer cannot be mapped to a block cipher and decryption is refused.

Solutions

  1. Print the numeric value in the error and map it back to a valid GcmTypeEnum constant before calling.
  2. Whitelist/validate the cipher-type field at config or protocol-parse time to GCM_AES256/GCM_SM4.
  3. Align library versions between peers so enum values agree.
  4. If stream-cipher data, switch to the AEAD API (AeadFromKey) instead of CBC.

Example fix

// before
t := core.GcmTypeEnum(msg.CipherType) // unvalidated from wire
plain, err := core.CBCDecryption(t, key, ct, false)
// after
if msg.CipherType != int(core.GCM_AES256) && msg.CipherType != int(core.GCM_SM4) {
    return fmt.Errorf("peer sent unsupported cipher type %d", msg.CipherType)
}
plain, err := core.CBCDecryption(core.GcmTypeEnum(msg.CipherType), key, ct, false)
Defensive patterns

Strategy: validation

Validate before calling

switch core.GcmTypeEnum(wireType) {
case core.GCM_AES256, core.GCM_SM4:
    // ok
default:
    return fmt.Errorf("refusing cipher type %d", wireType)
}

Type guard

func validCBCType(t core.GcmTypeEnum) bool { return t == core.GCM_AES256 || t == core.GCM_SM4 }

Try / catch

plain, err := core.CBCDecryption(t, key, ct, false)
if err != nil {
    var badType = t
    return fmt.Errorf("unsupported cipher type %d from peer: %w", badType, err)
}

Prevention

When it happens

Trigger: Calling CBCDecryption with a numeric cipher type that matches no case: zero-value enum, a type parsed from config or an untrusted packet field, or an enum value from a different/older version of the library.

Common situations: Cipher type serialized from a peer packet and deserialized incorrectly; config file with an out-of-range cipher index; version mismatch where the local GcmTypeEnum lacks a newer value sent by a peer.

Related errors


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

Appendix: source

Thrown at nhp/core/crypto.go:259

	case GCM_AES256:
		block, err = aes.NewCipher(key[:])
		if err != nil {
			return nil, fmt.Errorf("failed to create AES cipher for CBC decryption: %w", err)
		}
		iv = key[8:24]

	case GCM_SM4:
		block, err = sm4.NewCipher(key[:16])
		if err != nil {
			return nil, fmt.Errorf("failed to create SM4 cipher for CBC decryption: %w", err)
		}
		iv = key[16:]

	case GCM_CHACHA20POLY1305:
		return nil, ErrNotApplicable

	default:
		return nil, fmt.Errorf("unsupported cipher type for CBC decryption: %d", t)
	}

	// Validate ciphertext: must be at least one block and a multiple of block size
	if len(ciphertext) < block.BlockSize() {
		return nil, fmt.Errorf("ciphertext too short: need at least %d bytes", block.BlockSize())
	}
	if len(ciphertext)%block.BlockSize() != 0 {
		return nil, fmt.Errorf("ciphertext length %d is not a multiple of block size %d", len(ciphertext), block.BlockSize())
	}

	var plaintext []byte
	if inPlace {
		plaintext = ciphertext
	} else {
		plaintext = make([]byte, len(ciphertext))
	}

	mode := cipher.NewCBCDecrypter(block, iv)

View on GitHub (pinned to 6e04ca5ff0)