diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-16 19:23:18 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-16 19:23:18 +0000 |
commit | 43a123c1ae6613b3efeed291fa552ecd909d3acf (patch) | |
tree | fd92518b7024bc74031f78a1cf9e454b65e73665 /src/crypto/internal/boring/ecdh.go | |
parent | Initial commit. (diff) | |
download | golang-1.20-43a123c1ae6613b3efeed291fa552ecd909d3acf.tar.xz golang-1.20-43a123c1ae6613b3efeed291fa552ecd909d3acf.zip |
Adding upstream version 1.20.14.upstream/1.20.14upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/crypto/internal/boring/ecdh.go')
-rw-r--r-- | src/crypto/internal/boring/ecdh.go | 224 |
1 files changed, 224 insertions, 0 deletions
diff --git a/src/crypto/internal/boring/ecdh.go b/src/crypto/internal/boring/ecdh.go new file mode 100644 index 0000000..8f46d81 --- /dev/null +++ b/src/crypto/internal/boring/ecdh.go @@ -0,0 +1,224 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build boringcrypto && linux && (amd64 || arm64) && !android && !cmd_go_bootstrap && !msan + +package boring + +// #include "goboringcrypto.h" +import "C" +import ( + "errors" + "runtime" + "unsafe" +) + +type PublicKeyECDH struct { + curve string + key *C.GO_EC_POINT + group *C.GO_EC_GROUP + bytes []byte +} + +func (k *PublicKeyECDH) finalize() { + C._goboringcrypto_EC_POINT_free(k.key) +} + +type PrivateKeyECDH struct { + curve string + key *C.GO_EC_KEY +} + +func (k *PrivateKeyECDH) finalize() { + C._goboringcrypto_EC_KEY_free(k.key) +} + +func NewPublicKeyECDH(curve string, bytes []byte) (*PublicKeyECDH, error) { + if len(bytes) < 1 { + return nil, errors.New("NewPublicKeyECDH: missing key") + } + + nid, err := curveNID(curve) + if err != nil { + return nil, err + } + + group := C._goboringcrypto_EC_GROUP_new_by_curve_name(nid) + if group == nil { + return nil, 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") + } + 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") + } + + 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 +} + +func (k *PublicKeyECDH) Bytes() []byte { return k.bytes } + +func NewPrivateKeyECDH(curve string, bytes []byte) (*PrivateKeyECDH, error) { + nid, err := curveNID(curve) + if err != nil { + return nil, err + } + key := C._goboringcrypto_EC_KEY_new_by_curve_name(nid) + if key == nil { + return nil, fail("EC_KEY_new_by_curve_name") + } + b := bytesToBN(bytes) + ok := b != nil && C._goboringcrypto_EC_KEY_set_private_key(key, b) != 0 + if b != nil { + C._goboringcrypto_BN_free(b) + } + if !ok { + C._goboringcrypto_EC_KEY_free(key) + return nil, fail("EC_KEY_set_private_key") + } + k := &PrivateKeyECDH{curve, key} + // Note: Same as in NewPublicKeyECDH regarding finalizer and KeepAlive. + runtime.SetFinalizer(k, (*PrivateKeyECDH).finalize) + return k, nil +} + +func (k *PrivateKeyECDH) PublicKey() (*PublicKeyECDH, error) { + defer runtime.KeepAlive(k) + + group := C._goboringcrypto_EC_KEY_get0_group(k.key) + if group == nil { + return nil, fail("EC_KEY_get0_group") + } + kbig := C._goboringcrypto_EC_KEY_get0_private_key(k.key) + if kbig == nil { + return nil, fail("EC_KEY_get0_private_key") + } + pt := C._goboringcrypto_EC_POINT_new(group) + if pt == nil { + return nil, 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") + } + bytes, err := pointBytesECDH(k.curve, group, pt) + if err != nil { + C._goboringcrypto_EC_POINT_free(pt) + return nil, err + } + pub := &PublicKeyECDH{k.curve, pt, group, bytes} + // Note: Same as in NewPublicKeyECDH regarding finalizer and KeepAlive. + runtime.SetFinalizer(pub, (*PublicKeyECDH).finalize) + return pub, nil +} + +func pointBytesECDH(curve string, group *C.GO_EC_GROUP, pt *C.GO_EC_POINT) ([]byte, error) { + out := make([]byte, 1+2*curveSize(curve)) + n := C._goboringcrypto_EC_POINT_point2oct(group, pt, C.GO_POINT_CONVERSION_UNCOMPRESSED, (*C.uint8_t)(unsafe.Pointer(&out[0])), C.size_t(len(out)), nil) + if int(n) != len(out) { + return nil, fail("EC_POINT_point2oct") + } + return out, nil +} + +func ECDH(priv *PrivateKeyECDH, pub *PublicKeyECDH) ([]byte, error) { + group := C._goboringcrypto_EC_KEY_get0_group(priv.key) + if group == nil { + return nil, fail("EC_KEY_get0_group") + } + privBig := C._goboringcrypto_EC_KEY_get0_private_key(priv.key) + if privBig == nil { + return nil, fail("EC_KEY_get0_private_key") + } + pt := C._goboringcrypto_EC_POINT_new(group) + if pt == nil { + 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 { + return nil, fail("EC_POINT_mul") + } + out, err := xCoordBytesECDH(priv.curve, group, pt) + if err != nil { + return nil, err + } + return out, nil +} + +func xCoordBytesECDH(curve string, group *C.GO_EC_GROUP, pt *C.GO_EC_POINT) ([]byte, error) { + big := C._goboringcrypto_BN_new() + defer C._goboringcrypto_BN_free(big) + if C._goboringcrypto_EC_POINT_get_affine_coordinates_GFp(group, pt, big, nil, nil) == 0 { + return nil, fail("EC_POINT_get_affine_coordinates_GFp") + } + return bigBytesECDH(curve, big) +} + +func bigBytesECDH(curve string, big *C.GO_BIGNUM) ([]byte, error) { + out := make([]byte, curveSize(curve)) + if C._goboringcrypto_BN_bn2bin_padded((*C.uint8_t)(&out[0]), C.size_t(len(out)), big) == 0 { + return nil, fail("BN_bn2bin_padded") + } + return out, nil +} + +func curveSize(curve string) int { + switch curve { + default: + panic("crypto/internal/boring: unknown curve " + curve) + case "P-256": + return 256 / 8 + case "P-384": + return 384 / 8 + case "P-521": + return (521 + 7) / 8 + } +} + +func GenerateKeyECDH(curve string) (*PrivateKeyECDH, []byte, error) { + nid, err := curveNID(curve) + if err != nil { + return nil, 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") + } + 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") + } + + 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") + } + 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") + } + bytes, err := bigBytesECDH(curve, b) + if err != nil { + C._goboringcrypto_EC_KEY_free(key) + return nil, nil, err + } + + k := &PrivateKeyECDH{curve, key} + // Note: Same as in NewPublicKeyECDH regarding finalizer and KeepAlive. + runtime.SetFinalizer(k, (*PrivateKeyECDH).finalize) + return k, bytes, nil +} |