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