github.com/JimmyHuang454/JLS-go@v0.0.0-20230831150107-90d536585ba0/boring/ecdh.go (about) 1 // Copyright 2022 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 PublicKeyECDH struct { 18 curve string 19 key *C.GO_EC_POINT 20 group *C.GO_EC_GROUP 21 bytes []byte 22 } 23 24 func (k *PublicKeyECDH) finalize() { 25 C._goboringcrypto_EC_POINT_free(k.key) 26 } 27 28 type PrivateKeyECDH struct { 29 curve string 30 key *C.GO_EC_KEY 31 } 32 33 func (k *PrivateKeyECDH) finalize() { 34 C._goboringcrypto_EC_KEY_free(k.key) 35 } 36 37 func NewPublicKeyECDH(curve string, bytes []byte) (*PublicKeyECDH, error) { 38 if len(bytes) < 1 { 39 return nil, errors.New("NewPublicKeyECDH: missing key") 40 } 41 42 nid, err := curveNID(curve) 43 if err != nil { 44 return nil, err 45 } 46 47 group := C._goboringcrypto_EC_GROUP_new_by_curve_name(nid) 48 if group == nil { 49 return nil, fail("EC_GROUP_new_by_curve_name") 50 } 51 defer C._goboringcrypto_EC_GROUP_free(group) 52 key := C._goboringcrypto_EC_POINT_new(group) 53 if key == nil { 54 return nil, fail("EC_POINT_new") 55 } 56 ok := C._goboringcrypto_EC_POINT_oct2point(group, key, (*C.uint8_t)(unsafe.Pointer(&bytes[0])), C.size_t(len(bytes)), nil) != 0 57 if !ok { 58 C._goboringcrypto_EC_POINT_free(key) 59 return nil, errors.New("point not on curve") 60 } 61 62 k := &PublicKeyECDH{curve, key, group, append([]byte(nil), bytes...)} 63 // Note: Because of the finalizer, any time k.key is passed to cgo, 64 // that call must be followed by a call to runtime.KeepAlive(k), 65 // to make sure k is not collected (and finalized) before the cgo 66 // call returns. 67 runtime.SetFinalizer(k, (*PublicKeyECDH).finalize) 68 return k, nil 69 } 70 71 func (k *PublicKeyECDH) Bytes() []byte { return k.bytes } 72 73 func NewPrivateKeyECDH(curve string, bytes []byte) (*PrivateKeyECDH, error) { 74 nid, err := curveNID(curve) 75 if err != nil { 76 return nil, err 77 } 78 key := C._goboringcrypto_EC_KEY_new_by_curve_name(nid) 79 if key == nil { 80 return nil, fail("EC_KEY_new_by_curve_name") 81 } 82 b := bytesToBN(bytes) 83 ok := b != nil && C._goboringcrypto_EC_KEY_set_private_key(key, b) != 0 84 if b != nil { 85 C._goboringcrypto_BN_free(b) 86 } 87 if !ok { 88 C._goboringcrypto_EC_KEY_free(key) 89 return nil, fail("EC_KEY_set_private_key") 90 } 91 k := &PrivateKeyECDH{curve, key} 92 // Note: Same as in NewPublicKeyECDH regarding finalizer and KeepAlive. 93 runtime.SetFinalizer(k, (*PrivateKeyECDH).finalize) 94 return k, nil 95 } 96 97 func (k *PrivateKeyECDH) PublicKey() (*PublicKeyECDH, error) { 98 defer runtime.KeepAlive(k) 99 100 group := C._goboringcrypto_EC_KEY_get0_group(k.key) 101 if group == nil { 102 return nil, fail("EC_KEY_get0_group") 103 } 104 kbig := C._goboringcrypto_EC_KEY_get0_private_key(k.key) 105 if kbig == nil { 106 return nil, fail("EC_KEY_get0_private_key") 107 } 108 pt := C._goboringcrypto_EC_POINT_new(group) 109 if pt == nil { 110 return nil, fail("EC_POINT_new") 111 } 112 if C._goboringcrypto_EC_POINT_mul(group, pt, kbig, nil, nil, nil) == 0 { 113 C._goboringcrypto_EC_POINT_free(pt) 114 return nil, fail("EC_POINT_mul") 115 } 116 bytes, err := pointBytesECDH(k.curve, group, pt) 117 if err != nil { 118 C._goboringcrypto_EC_POINT_free(pt) 119 return nil, err 120 } 121 pub := &PublicKeyECDH{k.curve, pt, group, bytes} 122 // Note: Same as in NewPublicKeyECDH regarding finalizer and KeepAlive. 123 runtime.SetFinalizer(pub, (*PublicKeyECDH).finalize) 124 return pub, nil 125 } 126 127 func pointBytesECDH(curve string, group *C.GO_EC_GROUP, pt *C.GO_EC_POINT) ([]byte, error) { 128 out := make([]byte, 1+2*curveSize(curve)) 129 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) 130 if int(n) != len(out) { 131 return nil, fail("EC_POINT_point2oct") 132 } 133 return out, nil 134 } 135 136 func ECDH(priv *PrivateKeyECDH, pub *PublicKeyECDH) ([]byte, error) { 137 group := C._goboringcrypto_EC_KEY_get0_group(priv.key) 138 if group == nil { 139 return nil, fail("EC_KEY_get0_group") 140 } 141 privBig := C._goboringcrypto_EC_KEY_get0_private_key(priv.key) 142 if privBig == nil { 143 return nil, fail("EC_KEY_get0_private_key") 144 } 145 pt := C._goboringcrypto_EC_POINT_new(group) 146 if pt == nil { 147 return nil, fail("EC_POINT_new") 148 } 149 defer C._goboringcrypto_EC_POINT_free(pt) 150 if C._goboringcrypto_EC_POINT_mul(group, pt, nil, pub.key, privBig, nil) == 0 { 151 return nil, fail("EC_POINT_mul") 152 } 153 out, err := xCoordBytesECDH(priv.curve, group, pt) 154 if err != nil { 155 return nil, err 156 } 157 return out, nil 158 } 159 160 func xCoordBytesECDH(curve string, group *C.GO_EC_GROUP, pt *C.GO_EC_POINT) ([]byte, error) { 161 big := C._goboringcrypto_BN_new() 162 defer C._goboringcrypto_BN_free(big) 163 if C._goboringcrypto_EC_POINT_get_affine_coordinates_GFp(group, pt, big, nil, nil) == 0 { 164 return nil, fail("EC_POINT_get_affine_coordinates_GFp") 165 } 166 return bigBytesECDH(curve, big) 167 } 168 169 func bigBytesECDH(curve string, big *C.GO_BIGNUM) ([]byte, error) { 170 out := make([]byte, curveSize(curve)) 171 if C._goboringcrypto_BN_bn2bin_padded((*C.uint8_t)(&out[0]), C.size_t(len(out)), big) == 0 { 172 return nil, fail("BN_bn2bin_padded") 173 } 174 return out, nil 175 } 176 177 func curveSize(curve string) int { 178 switch curve { 179 default: 180 panic("crypto/internal/boring: unknown curve " + curve) 181 case "P-256": 182 return 256 / 8 183 case "P-384": 184 return 384 / 8 185 case "P-521": 186 return (521 + 7) / 8 187 } 188 } 189 190 func GenerateKeyECDH(curve string) (*PrivateKeyECDH, []byte, error) { 191 nid, err := curveNID(curve) 192 if err != nil { 193 return nil, nil, err 194 } 195 key := C._goboringcrypto_EC_KEY_new_by_curve_name(nid) 196 if key == nil { 197 return nil, nil, fail("EC_KEY_new_by_curve_name") 198 } 199 if C._goboringcrypto_EC_KEY_generate_key_fips(key) == 0 { 200 C._goboringcrypto_EC_KEY_free(key) 201 return nil, nil, fail("EC_KEY_generate_key_fips") 202 } 203 204 group := C._goboringcrypto_EC_KEY_get0_group(key) 205 if group == nil { 206 C._goboringcrypto_EC_KEY_free(key) 207 return nil, nil, fail("EC_KEY_get0_group") 208 } 209 b := C._goboringcrypto_EC_KEY_get0_private_key(key) 210 if b == nil { 211 C._goboringcrypto_EC_KEY_free(key) 212 return nil, nil, fail("EC_KEY_get0_private_key") 213 } 214 bytes, err := bigBytesECDH(curve, b) 215 if err != nil { 216 C._goboringcrypto_EC_KEY_free(key) 217 return nil, nil, err 218 } 219 220 k := &PrivateKeyECDH{curve, key} 221 // Note: Same as in NewPublicKeyECDH regarding finalizer and KeepAlive. 222 runtime.SetFinalizer(k, (*PrivateKeyECDH).finalize) 223 return k, bytes, nil 224 }