github.com/mtsmfm/go/src@v0.0.0-20221020090648-44bdcb9f8fde/crypto/internal/boring/ecdsa.go (about)

     1  // Copyright 2017 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  //go:build boringcrypto && linux && (amd64 || arm64) && !android && !cmd_go_bootstrap && !msan
     6  
     7  package boring
     8  
     9  // #include "goboringcrypto.h"
    10  import "C"
    11  import (
    12  	"errors"
    13  	"runtime"
    14  	"unsafe"
    15  )
    16  
    17  type ecdsaSignature struct {
    18  	R, S BigInt
    19  }
    20  
    21  type PrivateKeyECDSA struct {
    22  	key *C.GO_EC_KEY
    23  }
    24  
    25  func (k *PrivateKeyECDSA) finalize() {
    26  	C._goboringcrypto_EC_KEY_free(k.key)
    27  }
    28  
    29  type PublicKeyECDSA struct {
    30  	key *C.GO_EC_KEY
    31  }
    32  
    33  func (k *PublicKeyECDSA) finalize() {
    34  	C._goboringcrypto_EC_KEY_free(k.key)
    35  }
    36  
    37  var errUnknownCurve = errors.New("boringcrypto: unknown elliptic curve")
    38  
    39  func curveNID(curve string) (C.int, error) {
    40  	switch curve {
    41  	case "P-224":
    42  		return C.GO_NID_secp224r1, nil
    43  	case "P-256":
    44  		return C.GO_NID_X9_62_prime256v1, nil
    45  	case "P-384":
    46  		return C.GO_NID_secp384r1, nil
    47  	case "P-521":
    48  		return C.GO_NID_secp521r1, nil
    49  	}
    50  	return 0, errUnknownCurve
    51  }
    52  
    53  func NewPublicKeyECDSA(curve string, X, Y BigInt) (*PublicKeyECDSA, error) {
    54  	key, err := newECKey(curve, X, Y)
    55  	if err != nil {
    56  		return nil, err
    57  	}
    58  	k := &PublicKeyECDSA{key}
    59  	// Note: Because of the finalizer, any time k.key is passed to cgo,
    60  	// that call must be followed by a call to runtime.KeepAlive(k),
    61  	// to make sure k is not collected (and finalized) before the cgo
    62  	// call returns.
    63  	runtime.SetFinalizer(k, (*PublicKeyECDSA).finalize)
    64  	return k, nil
    65  }
    66  
    67  func newECKey(curve string, X, Y BigInt) (*C.GO_EC_KEY, error) {
    68  	nid, err := curveNID(curve)
    69  	if err != nil {
    70  		return nil, err
    71  	}
    72  	key := C._goboringcrypto_EC_KEY_new_by_curve_name(nid)
    73  	if key == nil {
    74  		return nil, fail("EC_KEY_new_by_curve_name")
    75  	}
    76  	group := C._goboringcrypto_EC_KEY_get0_group(key)
    77  	pt := C._goboringcrypto_EC_POINT_new(group)
    78  	if pt == nil {
    79  		C._goboringcrypto_EC_KEY_free(key)
    80  		return nil, fail("EC_POINT_new")
    81  	}
    82  	bx := bigToBN(X)
    83  	by := bigToBN(Y)
    84  	ok := bx != nil && by != nil && C._goboringcrypto_EC_POINT_set_affine_coordinates_GFp(group, pt, bx, by, nil) != 0 &&
    85  		C._goboringcrypto_EC_KEY_set_public_key(key, pt) != 0
    86  	if bx != nil {
    87  		C._goboringcrypto_BN_free(bx)
    88  	}
    89  	if by != nil {
    90  		C._goboringcrypto_BN_free(by)
    91  	}
    92  	C._goboringcrypto_EC_POINT_free(pt)
    93  	if !ok {
    94  		C._goboringcrypto_EC_KEY_free(key)
    95  		return nil, fail("EC_POINT_set_affine_coordinates_GFp")
    96  	}
    97  	return key, nil
    98  }
    99  
   100  func NewPrivateKeyECDSA(curve string, X, Y BigInt, D BigInt) (*PrivateKeyECDSA, error) {
   101  	key, err := newECKey(curve, X, Y)
   102  	if err != nil {
   103  		return nil, err
   104  	}
   105  	bd := bigToBN(D)
   106  	ok := bd != nil && C._goboringcrypto_EC_KEY_set_private_key(key, bd) != 0
   107  	if bd != nil {
   108  		C._goboringcrypto_BN_free(bd)
   109  	}
   110  	if !ok {
   111  		C._goboringcrypto_EC_KEY_free(key)
   112  		return nil, fail("EC_KEY_set_private_key")
   113  	}
   114  	k := &PrivateKeyECDSA{key}
   115  	// Note: Because of the finalizer, any time k.key is passed to cgo,
   116  	// that call must be followed by a call to runtime.KeepAlive(k),
   117  	// to make sure k is not collected (and finalized) before the cgo
   118  	// call returns.
   119  	runtime.SetFinalizer(k, (*PrivateKeyECDSA).finalize)
   120  	return k, nil
   121  }
   122  
   123  func SignMarshalECDSA(priv *PrivateKeyECDSA, hash []byte) ([]byte, error) {
   124  	size := C._goboringcrypto_ECDSA_size(priv.key)
   125  	sig := make([]byte, size)
   126  	var sigLen C.uint
   127  	if C._goboringcrypto_ECDSA_sign(0, base(hash), C.size_t(len(hash)), (*C.uint8_t)(unsafe.Pointer(&sig[0])), &sigLen, priv.key) == 0 {
   128  		return nil, fail("ECDSA_sign")
   129  	}
   130  	runtime.KeepAlive(priv)
   131  	return sig[:sigLen], nil
   132  }
   133  
   134  func VerifyECDSA(pub *PublicKeyECDSA, hash []byte, sig []byte) bool {
   135  	ok := C._goboringcrypto_ECDSA_verify(0, base(hash), C.size_t(len(hash)), (*C.uint8_t)(unsafe.Pointer(&sig[0])), C.size_t(len(sig)), pub.key) != 0
   136  	runtime.KeepAlive(pub)
   137  	return ok
   138  }
   139  
   140  func GenerateKeyECDSA(curve string) (X, Y, D BigInt, err error) {
   141  	nid, err := curveNID(curve)
   142  	if err != nil {
   143  		return nil, nil, nil, err
   144  	}
   145  	key := C._goboringcrypto_EC_KEY_new_by_curve_name(nid)
   146  	if key == nil {
   147  		return nil, nil, nil, fail("EC_KEY_new_by_curve_name")
   148  	}
   149  	defer C._goboringcrypto_EC_KEY_free(key)
   150  	if C._goboringcrypto_EC_KEY_generate_key_fips(key) == 0 {
   151  		return nil, nil, nil, fail("EC_KEY_generate_key_fips")
   152  	}
   153  	group := C._goboringcrypto_EC_KEY_get0_group(key)
   154  	pt := C._goboringcrypto_EC_KEY_get0_public_key(key)
   155  	bd := C._goboringcrypto_EC_KEY_get0_private_key(key)
   156  	if pt == nil || bd == nil {
   157  		return nil, nil, nil, fail("EC_KEY_get0_private_key")
   158  	}
   159  	bx := C._goboringcrypto_BN_new()
   160  	if bx == nil {
   161  		return nil, nil, nil, fail("BN_new")
   162  	}
   163  	defer C._goboringcrypto_BN_free(bx)
   164  	by := C._goboringcrypto_BN_new()
   165  	if by == nil {
   166  		return nil, nil, nil, fail("BN_new")
   167  	}
   168  	defer C._goboringcrypto_BN_free(by)
   169  	if C._goboringcrypto_EC_POINT_get_affine_coordinates_GFp(group, pt, bx, by, nil) == 0 {
   170  		return nil, nil, nil, fail("EC_POINT_get_affine_coordinates_GFp")
   171  	}
   172  	return bnToBig(bx), bnToBig(by), bnToBig(bd), nil
   173  }