OpenNHP/opennhp · error

invalid key length for SM4-GCM

Error message

invalid key length for SM4-GCM

What it means

For SM4-GCM modes, newCipherBlock requires a key of at least 16 bytes; shorter keys return this error. Keys longer than 16 bytes are truncated to the first 16 bytes (SM4-128). Raised from Encrypt/Decrypt when an SM4 mode receives an undersized key.

Solutions

  1. Supply a key of at least 16 bytes (extra bytes are truncated to the first 16)
  2. Use a proper KDF (HKDF) to expand short secrets to 16+ bytes
  3. Check that key decoding succeeded and the slice is not empty/truncated

Example fix

// before
key := []byte("short") // <16 bytes -> error
// after
key := hkdf.Expand(secret, 16) // or any >=16 byte key
Defensive patterns

Strategy: validation

Validate before calling

if len(key) < 16 {
	return fmt.Errorf("SM4-GCM requires at least a 16-byte key, got %d", len(key))
}

Try / catch

ct, err := mode.Encrypt(key, nonce, plaintext, ad)
if err != nil {
	if strings.Contains(err.Error(), "invalid key length for SM4-GCM") {
		// expand key via KDF to >=16 bytes and retry
	}
	return err
}

Prevention

When it happens

Trigger: Encrypt or Decrypt invoked on SM4GCM64Tag or SM4GCM128Tag with len(key) < 16 (nhp/core/ztdo/noise.go:116).

Common situations: Deriving short keys from passwords without KDF, using 8-byte test keys, passing empty or partially initialized key slices after a failed decode.

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/643e53d686516608. Report an issue: GitHub.

Appendix: source

Thrown at nhp/core/ztdo/noise.go:116

	case "SM4-GCM-64":
		return SM4GCM64Tag, nil
	case "SM4-GCM-128":
		return SM4GCM128Tag, nil
	default:
		return 0, fmt.Errorf("unknown symmetric mode name: %s", mode)
	}
}
func (mode SymmetricCipherMode) newCipherBlock(key []byte) (cipher.Block, error) {
	switch mode {
	case AES256GCM64Tag, AES256GCM96Tag, AES256GCM104Tag,
		AES256GCM112Tag, AES256GCM120Tag, AES256GCM128Tag:
		if len(key) != 32 {
			return nil, fmt.Errorf("invalid key length for AES-256-GCM")
		}
		return aes.NewCipher(key)
	case SM4GCM64Tag, SM4GCM128Tag:
		if len(key) < 16 {
			return nil, fmt.Errorf("invalid key length for SM4-GCM")
		} else {
			key = key[:16]
		}
		return sm4.NewCipher(key)
	default:
		return nil, fmt.Errorf("unsupported mode: %v", mode)
	}
}

func (mode SymmetricCipherMode) Encrypt(key, nonce, plaintext, ad []byte) ([]byte, error) {
	tagSize := mode.TagSize()

	cipherBlock, err := mode.newCipherBlock(key)
	if err != nil {
		return nil, err
	}

	aead, err := cipher.NewGCMWithTagSize(cipherBlock, tagSize)

View on GitHub (pinned to 6e04ca5ff0)