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

  1. Verify the 32-byte key array is fully populated by the SM2 ECDH/KDF step before invoking AeadFromKey
  2. Pin a known-good github.com/emmansun/gmsm version in go.mod and run go mod tidy
  3. Log the wrapped error to see the exact sm4.NewCipher complaint (usually key length)
  4. Confirm the caller passes GCM_SM4 only for scheme CIPHER_SCHEME_GMSM paths
  5. 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

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


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)