OpenNHP/opennhp · error

failed to create AES cipher for CBC decryption

Error message

failed to create AES cipher for CBC decryption: %w

What it means

In CBCDecryption's GCM_AES256 branch, aes.NewCipher(key[:]) failed. Go's AES implementation only accepts 16/24/32-byte keys, so this wraps the underlying key-length error. With SymmetricKeySize keys this should never occur, meaning the caller effectively passed a wrong-sized or corrupted key buffer.

Solutions

  1. Generate keys with the daemon's `keygen --curve` output or the library's key derivation so the AES key is exactly 32 bytes.
  2. Check that the key was fully decoded (base64/hex) and not truncated before wrapping it in the [SymmetricKeySize]byte array.
  3. Confirm the config.toml private key matches the curve/scheme expected (curve25519/AES vs SM2/SM4).
  4. Log/inspect the wrapped %w error; it names the exact key-length violation.

Example fix

// before
keyBytes, _ := hex.DecodeString(cfg.Key) // may be 24 or 40 bytes
var key [core.SymmetricKeySize]byte
copy(key[:], keyBytes)
// after
if len(keyBytes) != core.SymmetricKeySize {
    return fmt.Errorf("key must be %d bytes, got %d", core.SymmetricKeySize, len(keyBytes))
}
copy(key[:], keyBytes)
Defensive patterns

Strategy: validation

Validate before calling

if len(keyBytes) != core.SymmetricKeySize {
    return fmt.Errorf("AES key must be %d bytes, got %d", core.SymmetricKeySize, len(keyBytes))
}

Try / catch

plain, err := core.CBCDecryption(core.GCM_AES256, key, ct, false)
if err != nil {
    return fmt.Errorf("CBC decrypt failed (check key material): %w", err)
}

Prevention

When it happens

Trigger: Calling CBCDecryption with GCM_AES256 and a *[SymmetricKeySize]byte whose backing bytes were constructed from a key of invalid AES length (not 16/24/32 bytes), typically a truncated, mis-decoded, or wrong-format key.

Common situations: Key loaded from a hex/base64 string decoded to a non-standard length; key material from an older config version with a different key size; hand-built byte arrays instead of the library's keygen output.

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

Appendix: source

Thrown at nhp/core/crypto.go:244

		ciphertext = make([]byte, 0, len(plaintext))
	}

	mode := cipher.NewCBCEncrypter(block, iv)
	// CryptBlocks can work in-place if the two arguments are the same.
	mode.CryptBlocks(ciphertext, paddedPlainText)

	return ciphertext, nil
}

func CBCDecryption(t GcmTypeEnum, key *[SymmetricKeySize]byte, ciphertext []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 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

View on GitHub (pinned to 6e04ca5ff0)