OpenNHP/opennhp · error
failed to create SM4 cipher
Error message
failed to create SM4 cipher: %w
What it means
AeadFromKey(GCM_SM4, key) wraps sm4.NewCipher(key[:16]) errors as this message. The emmansun/gmsm sm4.NewCipher fails only when the key length is not exactly 16 bytes; OpenNHP hard-slices key[:16] from a 32-byte array, so failure implies the key array is malformed/nil or the gmsm dependency behaves unexpectedly. It indicates the SM4 (Chinese national standard) cipher for the GMSM cipher scheme could not be initialized.
Solutions
- Verify the 32-byte key array is fully populated by the SM2 ECDH/KDF step before invoking AeadFromKey
- Pin a known-good github.com/emmansun/gmsm version in go.mod and run go mod tidy
- Log the wrapped error to see the exact sm4.NewCipher complaint (usually key length)
- Confirm the caller passes GCM_SM4 only for scheme CIPHER_SCHEME_GMSM paths
- Test with go test ./nhp/core/... including TestGMSharedKey to reproduce with valid keys
Example fix
// before
var key *[32]byte
aead, _ := core.AeadFromKey(core.GCM_SM4, key) // nil/empty key
// after
shared := sm2Ecdh.SharedSecret(peerPub)
var key [core.SymmetricKeySize]byte
utils.Memcpy(key[:], kdf(shared))
aead, err := core.AeadFromKey(core.GCM_SM4, &key)
if err != nil {
return fmt.Errorf("sm4 aead init: %w", err)
} Defensive patterns
Strategy: validation
Validate before calling
if key == nil {
return errors.New("SM4 symmetric key not initialized")
}
zero := true
for _, b := range key {
if b != 0 { zero = false; break }
}
if zero {
return errors.New("SM4 key is all zeros - key exchange likely failed")
} Try / catch
aead, err := core.AeadFromKey(core.GCM_SM4, &key)
if err != nil {
return fmt.Errorf("SM4-GCM setup failed: %w", err)
} Prevention
- Run SM2 key exchange and KDF before any SM4 cipher use
- Use the GMSM cipher scheme end-to-end (NewCipherSuite(common.CIPHER_SCHEME_GMSM)) — don't mix suites
- Pin a tested github.com/emmansun/gmsm version in go.mod
- Check derived keys are non-empty and non-zero before encryption
When it happens
Trigger: Calling AeadFromKey(GCM_SM4, ...) with a nil *[SymmetricKeySize]byte, an array shorter than 16 bytes (only via unsafe/reflected misuse), or a gmsm library version with different NewCipher semantics.
Common situations: Mixed-scheme deployments where code paths for CIPHER_SCHEME_GMSM receive a key buffer that was never filled; refactors that change SymmetricKeySize; pinning an older/newer github.com/emmansun/gmsm with a changed API.
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-GCM
- failed to create SM4 cipher for CBC
- failed to create AES cipher
- failed to create AES-GCM
- failed to create SM4 cipher for CBC decryption
AI-assisted analysis of OpenNHP/opennhp@6e04ca5ff0 (2026-09-07).
Data as JSON: /api/errors/70f406ead4043ad8.
Report an issue: GitHub.
Appendix: source
Thrown at nhp/core/crypto.go:167
}
func AeadFromKey(t GcmTypeEnum, key *[SymmetricKeySize]byte) (cipher.AEAD, error) {
switch t {
case GCM_AES256:
aesBlock, err := aes.NewCipher(key[:])
if err != nil {
return nil, fmt.Errorf("failed to create AES cipher: %w", err)
}
aead, err := cipher.NewGCM(aesBlock)
if err != nil {
return nil, fmt.Errorf("failed to create AES-GCM: %w", err)
}
return aead, nil
case GCM_SM4:
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)
}
}View on GitHub (pinned to 6e04ca5ff0)