golang/go · error

crypto/ecdh: invalid private key

Error message

crypto/ecdh: invalid private key

What it means

When BoringCrypto is enabled, NewPrivateKey delegates parsing to boring.NewPrivateKeyECDH(c.name, key). If that call fails, the key bytes are not a valid private scalar for the named NIST curve, so this generic 'invalid private key' error is returned. The second return path (bk.PublicKey()) is tracked separately at line 92.

Source

Thrown at src/crypto/ecdh/nist.go:88

		bk, err := boring.NewPrivateKeyECDH(c.name, k.privateKey)
		if err != nil {
			return nil, err
		}
		pub, err := bk.PublicKey()
		if err != nil {
			return nil, err
		}
		k.boring = bk
		k.publicKey.boring = pub
	}
	return k, nil
}

func (c *nistCurve) NewPrivateKey(key []byte) (*PrivateKey, error) {
	if boring.Enabled {
		bk, err := boring.NewPrivateKeyECDH(c.name, key)
		if err != nil {
			return nil, errors.New("crypto/ecdh: invalid private key")
		}
		pub, err := bk.PublicKey()
		if err != nil {
			return nil, errors.New("crypto/ecdh: invalid private key")
		}
		k := &PrivateKey{
			curve:      c,
			privateKey: bytes.Clone(key),
			publicKey:  &PublicKey{curve: c, publicKey: pub.Bytes(), boring: pub},
			boring:     bk,
		}
		return k, nil
	}

	fk, err := c.newPrivateKey(key)
	if err != nil {
		return nil, err
	}

View on GitHub (pinned to b6b368adc5)

Solutions

  1. Ensure the key bytes are the raw, fixed-length scalar for the exact curve used.
  2. Generate keys via curve.GenerateKey(rand.Reader) so encoding is always valid.
  3. Verify key length matches the curve's expected private-key size before calling NewPrivateKey.
Defensive patterns

Strategy: validation

Validate before calling

// Validate length/range for the NIST curve before NewPrivateKey.
// P-256 expects 32 bytes, P-384 48, P-521 66.
func loadPriv(curve ecdh.Curve, key []byte) (*ecdh.PrivateKey, error) {
    if len(key) == 0 {
        return nil, errors.New("empty private key")
    }
    return curve.NewPrivateKey(key)
}

Try / catch

priv, err := curve.NewPrivateKey(key)
if err != nil {
    // 'invalid private key' under BoringCrypto: reject and request a fresh key.
    return err
}

Prevention

When it happens

Trigger: Calling curve.NewPrivateKey(key) with malformed, out-of-range, or wrong-length scalar bytes while boring.Enabled is true.

Common situations: Loading a key with the wrong curve's encoding; truncated key bytes; a scalar that is zero or >= the curve order; key produced by a non-compatible library.

Related errors


AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12). Data as JSON: /api/errors/a40d6db320d7d466. Report an issue: GitHub.