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
- Print the numeric value in the error and map it back to a valid GcmTypeEnum constant before calling.
- Whitelist/validate the cipher-type field at config or protocol-parse time to GCM_AES256/GCM_SM4.
- Align library versions between peers so enum values agree.
- 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
- Validate cipher-type integers from config and wire messages against the enum before use.
- Keep library versions aligned across peers so enum values agree.
- Reject unknown cipher types at protocol-parse time with a clear peer-facing error.
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
- ciphertext too short: need at least
- ciphertext length is not a multiple of block size
- unknown symmetric mode name
- unsupported mode
- unknown mode
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)