OpenNHP/opennhp · error

private key too short: got

Error message

private key too short: got %d bytes, need %d

What it means

Curve25519ECDH.SetPrivateKey validates that the supplied private key material is at least PrivateKeySize (32) bytes before copying it into the fixed 32-byte PrivKey array. If the input is shorter, the X25519 scalar would be silently under-sized, so the library rejects it with this error instead of producing a wrong/weak key pair. It is a defensive length check on ECDH key initialization.

Solutions

  1. Check len(prk) >= 32 at the call site and fix the key source (re-decode base64, use the full key string).
  2. Regenerate the key pair with the daemon's `keygen --curve` command and paste the complete 32-byte (44-char base64) private key.
  3. If the key is stored as hex/base64, verify the decoding method matches the storage encoding before calling SetPrivateKey.
  4. If the key comes from a KDF, ensure the output length is exactly 32 bytes (e.g. XOF/sha256 with size 32).

Example fix

// before
prk := keyBytes[:16] // accidentally truncated
ecdhe := curve.NewECDH()
err := ecdhe.SetPrivateKey(prk)
// after
if len(keyBytes) < curve.PrivateKeySize {
	return fmt.Errorf("key source provided %d bytes", len(keyBytes))
}
err := ecdhe.SetPrivateKey(keyBytes[:curve.PrivateKeySize])
Defensive patterns

Strategy: validation

Validate before calling

// Go
func validCurvePrivKey(b []byte) bool { return len(b) >= curve.PrivateKeySize } // PrivateKeySize == 32
if !validCurvePrivKey(keyBytes) {
	return fmt.Errorf("curve private key must be 32 bytes, got %d", len(keyBytes))
}

Try / catch

if err := ecdhe.SetPrivateKey(prk); err != nil {
	if strings.Contains(err.Error(), "private key too short") {
		// recover: re-load or regenerate key pair
	}
	return err
}

Prevention

When it happens

Trigger: Calling (*Curve25519ECDH).SetPrivateKey with a byte slice shorter than 32 bytes, directly or indirectly via NewECDH's key-setting path or ECDHFromKey, e.g. passing a truncated base64-decoded key, a hex string decoded to 16 bytes, or a seed/derivation output that returned fewer bytes than expected.

Common situations: Loading a private key from config.toml where the value was truncated or mis-pasted; decoding a key with the wrong base64/hex assumption; generating keys with a different tool that outputs 16- or 24-byte keys; a key-derivation function returning a shortened seed.

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

Appendix: source

Thrown at nhp/core/scheme/curve/curve.go:26

	"golang.org/x/crypto/curve25519"
)

const (
	PrivateKeySize = 32
	PublicKeySize  = 32
)

type Curve25519ECDH struct {
	PrivKey       [PrivateKeySize]byte
	PubKey        [PublicKeySize]byte
	PrivKeyBase64 string
	PubKeyBase64  string
	BriefName     string
}

func (c *Curve25519ECDH) SetPrivateKey(prk []byte) (err error) {
	if len(prk) < PrivateKeySize {
		return fmt.Errorf("private key too short: got %d bytes, need %d", len(prk), PrivateKeySize)
	}
	copy(c.PrivKey[:], prk[:PrivateKeySize])
	pbk, err := curve25519.X25519(c.PrivKey[:], curve25519.Basepoint)
	if err != nil {
		return err
	}
	copy(c.PubKey[:], pbk)
	c.PrivKeyBase64 = base64.StdEncoding.EncodeToString(c.PrivKey[:])
	c.PubKeyBase64 = base64.StdEncoding.EncodeToString(c.PubKey[:])
	c.BriefName = fmt.Sprintf("%s...%s", c.PubKeyBase64[0:4], c.PubKeyBase64[39:43])

	return nil
}

func (c *Curve25519ECDH) PrivateKey() []byte {
	return c.PrivKey[:]
}

View on GitHub (pinned to 6e04ca5ff0)