OpenNHP/opennhp · error
failed to create SM4 cipher for CBC
Error message
failed to create SM4 cipher for CBC: %w
What it means
CBCEncryption(GCM_SM4, key, ...) wraps sm4.NewCipher(key[:16]) failure as this message. gmsm's sm4.NewCipher fails only for key lengths other than 16 bytes; because OpenNHP slices the first 16 bytes of the fixed 32-byte key array, failure implies malformed/nil key material or a non-standard gmsm dependency. It occurs while initializing the SM4-CBC block cipher (IV from key[16:]).
Solutions
- Ensure the SM2 ECDH/KDF step fully populated the 32-byte key before calling CBCEncryption
- Log the wrapped error to capture sm4.NewCipher's underlying key-length message
- Pin a known-good github.com/emmansun/gmsm version and run go mod tidy
- Add a caller-side check that the key is non-zero before encryption
- Verify with go test ./nhp/core/... (TestGMSharedKey covers SM4 paths)
Example fix
// before
shared := sm2Ecdh.SharedSecret(peerPub) // empty on failed exchange
ciphertext, _ := core.CBCEncryption(core.GCM_SM4, (*[core.SymmetricKeySize]byte)(shared), plaintext, false)
// after
shared := sm2Ecdh.SharedSecret(peerPub)
if len(shared) == 0 {
return errors.New("SM2 key exchange failed: empty shared secret")
}
var key [core.SymmetricKeySize]byte
utils.Memcpy(key[:], kdf(shared))
ciphertext, err := core.CBCEncryption(core.GCM_SM4, &key, plaintext, false)
if err != nil {
return fmt.Errorf("sm4 cbc encrypt: %w", err)
} Defensive patterns
Strategy: validation
Validate before calling
if key == nil {
return errors.New("SM4-CBC key not initialized")
}
if len(sharedSecret) == 0 {
return errors.New("empty shared secret - SM2 key exchange failed")
} Try / catch
ciphertext, err := core.CBCEncryption(core.GCM_SM4, &key, plaintext, false)
if err != nil {
if errors.Is(err, core.ErrNotApplicable) {
return errors.New("SM4-CBC not applicable for this cipher type")
}
return fmt.Errorf("SM4-CBC encrypt failed: %w", err)
} Prevention
- Verify the SM2 ECDH exchange produced a non-empty shared secret before CBC encryption
- Use the GMSM suite consistently via NewCipherSuite(common.CIPHER_SCHEME_GMSM)
- Pin a tested github.com/emmansun/gmsm version
- Note CBC derives its IV directly from key[16:] — never pass short keys
When it happens
Trigger: Calling CBCEncryption with GCM_SM4 and a nil pointer or improperly sized array (e.g. via unsafe casts), or after gmsm library changes to NewCipher semantics; not triggerable with correct 32-byte key arrays.
Common situations: GMSM-scheme bulk encryption paths where the SM2 key exchange silently failed leaving a zeroed key; custom code constructing shorter key buffers; pinning an incompatible emmansun/gmsm version.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- failed to create SM4 cipher
- failed to create SM4-GCM
- failed to create AES cipher for CBC
- failed to create SM4 cipher for CBC decryption
- unsupported cipher type for CBC decryption
AI-assisted analysis of OpenNHP/opennhp@6e04ca5ff0 (2026-09-07).
Data as JSON: /api/errors/79b83ddc61f903fc.
Report an issue: GitHub.
Appendix: source
Thrown at nhp/core/crypto.go:202
}
}
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 {
return nil, fmt.Errorf("failed to create SM4 cipher for CBC: %w", err)
}
iv = key[16:]
case GCM_CHACHA20POLY1305:
return nil, ErrNotApplicable
default:
return nil, fmt.Errorf("unsupported cipher type for CBC: %d", t)
}
var paddedPlainText []byte
if len(plaintext)%block.BlockSize() == 0 {
// skip padding
paddedPlainText = plaintext
} else {
pkcs7 := padding.NewPKCS7Padding(uint(block.BlockSize()))
paddedPlainText = pkcs7.Pad(plaintext)
}View on GitHub (pinned to 6e04ca5ff0)