1
0
mirror of https://github.com/golang/go synced 2024-11-25 00:07:56 -07:00

crypto/ecdh: remove 8 byte pointer overhead for non boringcrypto builds

Change-Id: I3e6f5e43a20291ed7030df3c0b47481f725a3dcb
This commit is contained in:
Mateusz Poliwczak 2024-09-21 20:57:11 +02:00
parent c208b91395
commit 7b756dd185
4 changed files with 69 additions and 56 deletions

View File

@ -66,9 +66,10 @@ type Curve interface {
// with [crypto/x509.MarshalPKIXPublicKey]. For NIST curves, they then need to
// be converted with [crypto/ecdsa.PublicKey.ECDH] after parsing.
type PublicKey struct {
boring boring.PublicKeyECDH
curve Curve
publicKey []byte
boring *boring.PublicKeyECDH
}
// Bytes returns a copy of the encoding of the public key.
@ -105,9 +106,10 @@ func (k *PublicKey) Curve() Curve {
// with [crypto/x509.MarshalPKCS8PrivateKey]. For NIST curves, they then need to
// be converted with [crypto/ecdsa.PrivateKey.ECDH] after parsing.
type PrivateKey struct {
boring boring.PrivateKeyECDH
curve Curve
privateKey []byte
boring *boring.PrivateKeyECDH
// publicKey is set under publicKeyOnce, to allow loading private keys with
// NewPrivateKey without having to perform a scalar multiplication.
publicKey *PublicKey
@ -160,7 +162,7 @@ func (k *PrivateKey) Curve() Curve {
func (k *PrivateKey) PublicKey() *PublicKey {
k.publicKeyOnce.Do(func() {
if k.boring != nil {
if boring.Enabled && k.boring.Valid() {
// Because we already checked in NewPrivateKey that the key is valid,
// there should not be any possible errors from BoringCrypto,
// so we turn the error into a panic.

View File

@ -93,7 +93,7 @@ func (c *nistCurve[Point]) NewPrivateKey(key []byte) (*PrivateKey, error) {
return k, nil
}
func newBoringPrivateKey(c Curve, bk *boring.PrivateKeyECDH, privateKey []byte) (*PrivateKey, error) {
func newBoringPrivateKey(c Curve, bk boring.PrivateKeyECDH, privateKey []byte) (*PrivateKey, error) {
k := &PrivateKey{
curve: c,
boring: bk,

View File

@ -15,69 +15,79 @@ import (
)
type PublicKeyECDH struct {
p *publicKeyECDH
}
type publicKeyECDH struct {
curve string
key *C.GO_EC_POINT
group *C.GO_EC_GROUP
bytes []byte
}
func (k *PublicKeyECDH) finalize() {
func (k *publicKeyECDH) finalize() {
C._goboringcrypto_EC_POINT_free(k.key)
}
type PrivateKeyECDH struct {
p *privateKeyECDH
}
type privateKeyECDH struct {
curve string
key *C.GO_EC_KEY
}
func (k *PrivateKeyECDH) finalize() {
func (k *PrivateKeyECDH) Valid() bool { return k.p != nil }
func (k *privateKeyECDH) finalize() {
C._goboringcrypto_EC_KEY_free(k.key)
}
func NewPublicKeyECDH(curve string, bytes []byte) (*PublicKeyECDH, error) {
func NewPublicKeyECDH(curve string, bytes []byte) (PublicKeyECDH, error) {
if len(bytes) < 1 {
return nil, errors.New("NewPublicKeyECDH: missing key")
return PublicKeyECDH{}, errors.New("NewPublicKeyECDH: missing key")
}
nid, err := curveNID(curve)
if err != nil {
return nil, err
return PublicKeyECDH{}, err
}
group := C._goboringcrypto_EC_GROUP_new_by_curve_name(nid)
if group == nil {
return nil, fail("EC_GROUP_new_by_curve_name")
return PublicKeyECDH{}, fail("EC_GROUP_new_by_curve_name")
}
defer C._goboringcrypto_EC_GROUP_free(group)
key := C._goboringcrypto_EC_POINT_new(group)
if key == nil {
return nil, fail("EC_POINT_new")
return PublicKeyECDH{}, fail("EC_POINT_new")
}
ok := C._goboringcrypto_EC_POINT_oct2point(group, key, (*C.uint8_t)(unsafe.Pointer(&bytes[0])), C.size_t(len(bytes)), nil) != 0
if !ok {
C._goboringcrypto_EC_POINT_free(key)
return nil, errors.New("point not on curve")
return PublicKeyECDH{}, errors.New("point not on curve")
}
k := &PublicKeyECDH{curve, key, group, append([]byte(nil), bytes...)}
k := &publicKeyECDH{curve, key, group, append([]byte(nil), bytes...)}
// Note: Because of the finalizer, any time k.key is passed to cgo,
// that call must be followed by a call to runtime.KeepAlive(k),
// to make sure k is not collected (and finalized) before the cgo
// call returns.
runtime.SetFinalizer(k, (*PublicKeyECDH).finalize)
return k, nil
runtime.SetFinalizer(k, (*publicKeyECDH).finalize)
return PublicKeyECDH{p: k}, nil
}
func (k *PublicKeyECDH) Bytes() []byte { return k.bytes }
func (k *PublicKeyECDH) Bytes() []byte { return k.p.bytes }
func NewPrivateKeyECDH(curve string, bytes []byte) (*PrivateKeyECDH, error) {
func NewPrivateKeyECDH(curve string, bytes []byte) (PrivateKeyECDH, error) {
nid, err := curveNID(curve)
if err != nil {
return nil, err
return PrivateKeyECDH{}, err
}
key := C._goboringcrypto_EC_KEY_new_by_curve_name(nid)
if key == nil {
return nil, fail("EC_KEY_new_by_curve_name")
return PrivateKeyECDH{}, fail("EC_KEY_new_by_curve_name")
}
b := bytesToBN(bytes)
ok := b != nil && C._goboringcrypto_EC_KEY_set_private_key(key, b) != 0
@ -86,42 +96,42 @@ func NewPrivateKeyECDH(curve string, bytes []byte) (*PrivateKeyECDH, error) {
}
if !ok {
C._goboringcrypto_EC_KEY_free(key)
return nil, fail("EC_KEY_set_private_key")
return PrivateKeyECDH{}, fail("EC_KEY_set_private_key")
}
k := &PrivateKeyECDH{curve, key}
k := &privateKeyECDH{curve, key}
// Note: Same as in NewPublicKeyECDH regarding finalizer and KeepAlive.
runtime.SetFinalizer(k, (*PrivateKeyECDH).finalize)
return k, nil
runtime.SetFinalizer(k, (*privateKeyECDH).finalize)
return PrivateKeyECDH{p: k}, nil
}
func (k *PrivateKeyECDH) PublicKey() (*PublicKeyECDH, error) {
func (k *PrivateKeyECDH) PublicKey() (PublicKeyECDH, error) {
defer runtime.KeepAlive(k)
group := C._goboringcrypto_EC_KEY_get0_group(k.key)
group := C._goboringcrypto_EC_KEY_get0_group(k.p.key)
if group == nil {
return nil, fail("EC_KEY_get0_group")
return PublicKeyECDH{}, fail("EC_KEY_get0_group")
}
kbig := C._goboringcrypto_EC_KEY_get0_private_key(k.key)
kbig := C._goboringcrypto_EC_KEY_get0_private_key(k.p.key)
if kbig == nil {
return nil, fail("EC_KEY_get0_private_key")
return PublicKeyECDH{}, fail("EC_KEY_get0_private_key")
}
pt := C._goboringcrypto_EC_POINT_new(group)
if pt == nil {
return nil, fail("EC_POINT_new")
return PublicKeyECDH{}, fail("EC_POINT_new")
}
if C._goboringcrypto_EC_POINT_mul(group, pt, kbig, nil, nil, nil) == 0 {
C._goboringcrypto_EC_POINT_free(pt)
return nil, fail("EC_POINT_mul")
return PublicKeyECDH{}, fail("EC_POINT_mul")
}
bytes, err := pointBytesECDH(k.curve, group, pt)
bytes, err := pointBytesECDH(k.p.curve, group, pt)
if err != nil {
C._goboringcrypto_EC_POINT_free(pt)
return nil, err
return PublicKeyECDH{}, err
}
pub := &PublicKeyECDH{k.curve, pt, group, bytes}
pub := &publicKeyECDH{k.p.curve, pt, group, bytes}
// Note: Same as in NewPublicKeyECDH regarding finalizer and KeepAlive.
runtime.SetFinalizer(pub, (*PublicKeyECDH).finalize)
return pub, nil
runtime.SetFinalizer(pub, (*publicKeyECDH).finalize)
return PublicKeyECDH{p: pub}, nil
}
func pointBytesECDH(curve string, group *C.GO_EC_GROUP, pt *C.GO_EC_POINT) ([]byte, error) {
@ -133,12 +143,12 @@ func pointBytesECDH(curve string, group *C.GO_EC_GROUP, pt *C.GO_EC_POINT) ([]by
return out, nil
}
func ECDH(priv *PrivateKeyECDH, pub *PublicKeyECDH) ([]byte, error) {
group := C._goboringcrypto_EC_KEY_get0_group(priv.key)
func ECDH(priv PrivateKeyECDH, pub PublicKeyECDH) ([]byte, error) {
group := C._goboringcrypto_EC_KEY_get0_group(priv.p.key)
if group == nil {
return nil, fail("EC_KEY_get0_group")
}
privBig := C._goboringcrypto_EC_KEY_get0_private_key(priv.key)
privBig := C._goboringcrypto_EC_KEY_get0_private_key(priv.p.key)
if privBig == nil {
return nil, fail("EC_KEY_get0_private_key")
}
@ -147,10 +157,10 @@ func ECDH(priv *PrivateKeyECDH, pub *PublicKeyECDH) ([]byte, error) {
return nil, fail("EC_POINT_new")
}
defer C._goboringcrypto_EC_POINT_free(pt)
if C._goboringcrypto_EC_POINT_mul(group, pt, nil, pub.key, privBig, nil) == 0 {
if C._goboringcrypto_EC_POINT_mul(group, pt, nil, pub.p.key, privBig, nil) == 0 {
return nil, fail("EC_POINT_mul")
}
out, err := xCoordBytesECDH(priv.curve, group, pt)
out, err := xCoordBytesECDH(priv.p.curve, group, pt)
if err != nil {
return nil, err
}
@ -187,38 +197,38 @@ func curveSize(curve string) int {
}
}
func GenerateKeyECDH(curve string) (*PrivateKeyECDH, []byte, error) {
func GenerateKeyECDH(curve string) (PrivateKeyECDH, []byte, error) {
nid, err := curveNID(curve)
if err != nil {
return nil, nil, err
return PrivateKeyECDH{}, nil, err
}
key := C._goboringcrypto_EC_KEY_new_by_curve_name(nid)
if key == nil {
return nil, nil, fail("EC_KEY_new_by_curve_name")
return PrivateKeyECDH{}, nil, fail("EC_KEY_new_by_curve_name")
}
if C._goboringcrypto_EC_KEY_generate_key_fips(key) == 0 {
C._goboringcrypto_EC_KEY_free(key)
return nil, nil, fail("EC_KEY_generate_key_fips")
return PrivateKeyECDH{}, nil, fail("EC_KEY_generate_key_fips")
}
group := C._goboringcrypto_EC_KEY_get0_group(key)
if group == nil {
C._goboringcrypto_EC_KEY_free(key)
return nil, nil, fail("EC_KEY_get0_group")
return PrivateKeyECDH{}, nil, fail("EC_KEY_get0_group")
}
b := C._goboringcrypto_EC_KEY_get0_private_key(key)
if b == nil {
C._goboringcrypto_EC_KEY_free(key)
return nil, nil, fail("EC_KEY_get0_private_key")
return PrivateKeyECDH{}, nil, fail("EC_KEY_get0_private_key")
}
bytes, err := bigBytesECDH(curve, b)
if err != nil {
C._goboringcrypto_EC_KEY_free(key)
return nil, nil, err
return PrivateKeyECDH{}, nil, err
}
k := &PrivateKeyECDH{curve, key}
k := &privateKeyECDH{curve, key}
// Note: Same as in NewPublicKeyECDH regarding finalizer and KeepAlive.
runtime.SetFinalizer(k, (*PrivateKeyECDH).finalize)
return k, bytes, nil
runtime.SetFinalizer(k, (*privateKeyECDH).finalize)
return PrivateKeyECDH{p: k}, bytes, nil
}

View File

@ -115,9 +115,10 @@ func VerifyRSAPSS(pub *PublicKeyRSA, h crypto.Hash, hashed, sig []byte, saltLen
type PublicKeyECDH struct{}
type PrivateKeyECDH struct{}
func ECDH(*PrivateKeyECDH, *PublicKeyECDH) ([]byte, error) { panic("boringcrypto: not available") }
func GenerateKeyECDH(string) (*PrivateKeyECDH, []byte, error) { panic("boringcrypto: not available") }
func NewPrivateKeyECDH(string, []byte) (*PrivateKeyECDH, error) { panic("boringcrypto: not available") }
func NewPublicKeyECDH(string, []byte) (*PublicKeyECDH, error) { panic("boringcrypto: not available") }
func ECDH(PrivateKeyECDH, PublicKeyECDH) ([]byte, error) { panic("boringcrypto: not available") }
func GenerateKeyECDH(string) (PrivateKeyECDH, []byte, error) { panic("boringcrypto: not available") }
func NewPrivateKeyECDH(string, []byte) (PrivateKeyECDH, error) { panic("boringcrypto: not available") }
func NewPublicKeyECDH(string, []byte) (PublicKeyECDH, error) { panic("boringcrypto: not available") }
func (*PublicKeyECDH) Bytes() []byte { panic("boringcrypto: not available") }
func (*PrivateKeyECDH) PublicKey() (*PublicKeyECDH, error) { panic("boringcrypto: not available") }
func (*PrivateKeyECDH) PublicKey() (PublicKeyECDH, error) { panic("boringcrypto: not available") }
func (*PrivateKeyECDH) Valid() bool { panic("boringcrypto: not available") }