1 | //! Elliptic Curve |
2 | //! |
3 | //! Cryptography relies on the difficulty of solving mathematical problems, such as the factor |
4 | //! of large integers composed of two large prime numbers and the discrete logarithm of a |
5 | //! random elliptic curve. This module provides low-level features of the latter. |
6 | //! Elliptic Curve protocols can provide the same security with smaller keys. |
7 | //! |
8 | //! There are 2 forms of elliptic curves, `Fp` and `F2^m`. These curves use irreducible |
9 | //! trinomial or pentanomial. Being a generic interface to a wide range of algorithms, |
10 | //! the curves are generally referenced by [`EcGroup`]. There are many built-in groups |
11 | //! found in [`Nid`]. |
12 | //! |
13 | //! OpenSSL Wiki explains the fields and curves in detail at [Elliptic Curve Cryptography]. |
14 | //! |
15 | //! [`EcGroup`]: struct.EcGroup.html |
16 | //! [`Nid`]: ../nid/struct.Nid.html |
17 | //! [Elliptic Curve Cryptography]: https://wiki.openssl.org/index.php/Elliptic_Curve_Cryptography |
18 | use cfg_if::cfg_if; |
19 | use foreign_types::{ForeignType, ForeignTypeRef}; |
20 | use libc::c_int; |
21 | use std::fmt; |
22 | use std::ptr; |
23 | |
24 | use crate::bn::{BigNum, BigNumContextRef, BigNumRef}; |
25 | use crate::error::ErrorStack; |
26 | use crate::nid::Nid; |
27 | use crate::pkey::{HasParams, HasPrivate, HasPublic, Params, Private, Public}; |
28 | use crate::util::ForeignTypeRefExt; |
29 | use crate::{cvt, cvt_n, cvt_p, init}; |
30 | use openssl_macros::corresponds; |
31 | |
32 | cfg_if! { |
33 | if #[cfg(not(boringssl))] { |
34 | use std::ffi::CString; |
35 | use crate::string::OpensslString; |
36 | } |
37 | } |
38 | |
39 | /// Compressed or Uncompressed conversion |
40 | /// |
41 | /// Conversion from the binary value of the point on the curve is performed in one of |
42 | /// compressed, uncompressed, or hybrid conversions. The default is compressed, except |
43 | /// for binary curves. |
44 | /// |
45 | /// Further documentation is available in the [X9.62] standard. |
46 | /// |
47 | /// [X9.62]: http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.202.2977&rep=rep1&type=pdf |
48 | #[derive (Copy, Clone)] |
49 | pub struct PointConversionForm(ffi::point_conversion_form_t); |
50 | |
51 | impl PointConversionForm { |
52 | /// Compressed conversion from point value. |
53 | pub const COMPRESSED: PointConversionForm = |
54 | PointConversionForm(ffi::point_conversion_form_t::POINT_CONVERSION_COMPRESSED); |
55 | |
56 | /// Uncompressed conversion from point value. |
57 | pub const UNCOMPRESSED: PointConversionForm = |
58 | PointConversionForm(ffi::point_conversion_form_t::POINT_CONVERSION_UNCOMPRESSED); |
59 | |
60 | /// Performs both compressed and uncompressed conversions. |
61 | pub const HYBRID: PointConversionForm = |
62 | PointConversionForm(ffi::point_conversion_form_t::POINT_CONVERSION_HYBRID); |
63 | } |
64 | |
65 | /// Named Curve or Explicit |
66 | /// |
67 | /// This type acts as a boolean as to whether the `EcGroup` is named or explicit. |
68 | #[derive (Copy, Clone, Debug, PartialEq)] |
69 | pub struct Asn1Flag(c_int); |
70 | |
71 | impl Asn1Flag { |
72 | /// Curve defined using polynomial parameters |
73 | /// |
74 | /// Most applications use a named EC_GROUP curve, however, support |
75 | /// is included to explicitly define the curve used to calculate keys |
76 | /// This information would need to be known by both endpoint to make communication |
77 | /// effective. |
78 | /// |
79 | /// OPENSSL_EC_EXPLICIT_CURVE, but that was only added in 1.1. |
80 | /// Man page documents that 0 can be used in older versions. |
81 | /// |
82 | /// OpenSSL documentation at [`EC_GROUP`] |
83 | /// |
84 | /// [`EC_GROUP`]: https://www.openssl.org/docs/manmaster/crypto/EC_GROUP_get_seed_len.html |
85 | pub const EXPLICIT_CURVE: Asn1Flag = Asn1Flag(0); |
86 | |
87 | /// Standard Curves |
88 | /// |
89 | /// Curves that make up the typical encryption use cases. The collection of curves |
90 | /// are well known but extensible. |
91 | /// |
92 | /// OpenSSL documentation at [`EC_GROUP`] |
93 | /// |
94 | /// [`EC_GROUP`]: https://www.openssl.org/docs/manmaster/man3/EC_GROUP_order_bits.html |
95 | pub const NAMED_CURVE: Asn1Flag = Asn1Flag(ffi::OPENSSL_EC_NAMED_CURVE); |
96 | } |
97 | |
98 | foreign_type_and_impl_send_sync! { |
99 | type CType = ffi::EC_GROUP; |
100 | fn drop = ffi::EC_GROUP_free; |
101 | |
102 | /// Describes the curve |
103 | /// |
104 | /// A curve can be of the named curve type. These curves can be discovered |
105 | /// using openssl binary `openssl ecparam -list_curves`. Other operations |
106 | /// are available in the [wiki]. These named curves are available in the |
107 | /// [`Nid`] module. |
108 | /// |
109 | /// Curves can also be generated using prime field parameters or a binary field. |
110 | /// |
111 | /// Prime fields use the formula `y^2 mod p = x^3 + ax + b mod p`. Binary |
112 | /// fields use the formula `y^2 + xy = x^3 + ax^2 + b`. Named curves have |
113 | /// assured security. To prevent accidental vulnerabilities, they should |
114 | /// be preferred. |
115 | /// |
116 | /// [wiki]: https://wiki.openssl.org/index.php/Command_Line_Elliptic_Curve_Operations |
117 | /// [`Nid`]: ../nid/index.html |
118 | pub struct EcGroup; |
119 | /// Reference to [`EcGroup`] |
120 | /// |
121 | /// [`EcGroup`]: struct.EcGroup.html |
122 | pub struct EcGroupRef; |
123 | } |
124 | |
125 | impl EcGroup { |
126 | /// Returns the group of a standard named curve. |
127 | /// |
128 | /// # Examples |
129 | /// |
130 | /// ``` |
131 | /// # fn main() -> Result<(), Box<dyn std::error::Error>> { |
132 | /// use openssl::nid::Nid; |
133 | /// use openssl::ec::{EcGroup, EcKey}; |
134 | /// |
135 | /// let nid = Nid::X9_62_PRIME256V1; // NIST P-256 curve |
136 | /// let group = EcGroup::from_curve_name(nid)?; |
137 | /// let key = EcKey::generate(&group)?; |
138 | /// # Ok(()) } |
139 | /// ``` |
140 | #[corresponds (EC_GROUP_new_by_curve_name)] |
141 | pub fn from_curve_name(nid: Nid) -> Result<EcGroup, ErrorStack> { |
142 | unsafe { |
143 | init(); |
144 | cvt_p(ffi::EC_GROUP_new_by_curve_name(nid.as_raw())).map(EcGroup) |
145 | } |
146 | } |
147 | |
148 | /// Returns the group for given parameters |
149 | #[corresponds (EC_GROUP_new_curve_GFp)] |
150 | pub fn from_components( |
151 | p: BigNum, |
152 | a: BigNum, |
153 | b: BigNum, |
154 | ctx: &mut BigNumContextRef, |
155 | ) -> Result<EcGroup, ErrorStack> { |
156 | unsafe { |
157 | cvt_p(ffi::EC_GROUP_new_curve_GFp( |
158 | p.as_ptr(), |
159 | a.as_ptr(), |
160 | b.as_ptr(), |
161 | ctx.as_ptr(), |
162 | )) |
163 | .map(EcGroup) |
164 | } |
165 | } |
166 | } |
167 | |
168 | impl EcGroupRef { |
169 | /// Places the components of a curve over a prime field in the provided `BigNum`s. |
170 | /// The components make up the formula `y^2 mod p = x^3 + ax + b mod p`. |
171 | #[corresponds (EC_GROUP_get_curve_GFp)] |
172 | pub fn components_gfp( |
173 | &self, |
174 | p: &mut BigNumRef, |
175 | a: &mut BigNumRef, |
176 | b: &mut BigNumRef, |
177 | ctx: &mut BigNumContextRef, |
178 | ) -> Result<(), ErrorStack> { |
179 | unsafe { |
180 | cvt(ffi::EC_GROUP_get_curve_GFp( |
181 | self.as_ptr(), |
182 | p.as_ptr(), |
183 | a.as_ptr(), |
184 | b.as_ptr(), |
185 | ctx.as_ptr(), |
186 | )) |
187 | .map(|_| ()) |
188 | } |
189 | } |
190 | |
191 | /// Places the components of a curve over a binary field in the provided `BigNum`s. |
192 | /// The components make up the formula `y^2 + xy = x^3 + ax^2 + b`. |
193 | /// |
194 | /// In this form `p` relates to the irreducible polynomial. Each bit represents |
195 | /// a term in the polynomial. It will be set to 3 `1`s or 5 `1`s depending on |
196 | /// using a trinomial or pentanomial. |
197 | #[corresponds (EC_GROUP_get_curve_GF2m)] |
198 | #[cfg (not(osslconf = "OPENSSL_NO_EC2M" ))] |
199 | pub fn components_gf2m( |
200 | &self, |
201 | p: &mut BigNumRef, |
202 | a: &mut BigNumRef, |
203 | b: &mut BigNumRef, |
204 | ctx: &mut BigNumContextRef, |
205 | ) -> Result<(), ErrorStack> { |
206 | unsafe { |
207 | cvt(ffi::EC_GROUP_get_curve_GF2m( |
208 | self.as_ptr(), |
209 | p.as_ptr(), |
210 | a.as_ptr(), |
211 | b.as_ptr(), |
212 | ctx.as_ptr(), |
213 | )) |
214 | .map(|_| ()) |
215 | } |
216 | } |
217 | |
218 | /// Places the cofactor of the group in the provided `BigNum`. |
219 | #[corresponds (EC_GROUP_get_cofactor)] |
220 | pub fn cofactor( |
221 | &self, |
222 | cofactor: &mut BigNumRef, |
223 | ctx: &mut BigNumContextRef, |
224 | ) -> Result<(), ErrorStack> { |
225 | unsafe { |
226 | cvt(ffi::EC_GROUP_get_cofactor( |
227 | self.as_ptr(), |
228 | cofactor.as_ptr(), |
229 | ctx.as_ptr(), |
230 | )) |
231 | .map(|_| ()) |
232 | } |
233 | } |
234 | |
235 | /// Returns the degree of the curve. |
236 | #[corresponds (EC_GROUP_get_degree)] |
237 | pub fn degree(&self) -> u32 { |
238 | unsafe { ffi::EC_GROUP_get_degree(self.as_ptr()) as u32 } |
239 | } |
240 | |
241 | /// Returns the number of bits in the group order. |
242 | #[corresponds (EC_GROUP_order_bits)] |
243 | #[cfg (ossl110)] |
244 | pub fn order_bits(&self) -> u32 { |
245 | unsafe { ffi::EC_GROUP_order_bits(self.as_ptr()) as u32 } |
246 | } |
247 | |
248 | /// Returns the generator for the given curve as an [`EcPoint`]. |
249 | #[corresponds (EC_GROUP_get0_generator)] |
250 | pub fn generator(&self) -> &EcPointRef { |
251 | unsafe { |
252 | let ptr = ffi::EC_GROUP_get0_generator(self.as_ptr()); |
253 | EcPointRef::from_const_ptr(ptr) |
254 | } |
255 | } |
256 | |
257 | /// Sets the generator point for the given curve |
258 | #[corresponds (EC_GROUP_set_generator)] |
259 | pub fn set_generator( |
260 | &mut self, |
261 | generator: EcPoint, |
262 | order: BigNum, |
263 | cofactor: BigNum, |
264 | ) -> Result<(), ErrorStack> { |
265 | unsafe { |
266 | cvt(ffi::EC_GROUP_set_generator( |
267 | self.as_ptr(), |
268 | generator.as_ptr(), |
269 | order.as_ptr(), |
270 | cofactor.as_ptr(), |
271 | )) |
272 | .map(|_| ()) |
273 | } |
274 | } |
275 | |
276 | /// Places the order of the curve in the provided `BigNum`. |
277 | #[corresponds (EC_GROUP_get_order)] |
278 | pub fn order( |
279 | &self, |
280 | order: &mut BigNumRef, |
281 | ctx: &mut BigNumContextRef, |
282 | ) -> Result<(), ErrorStack> { |
283 | unsafe { |
284 | cvt(ffi::EC_GROUP_get_order( |
285 | self.as_ptr(), |
286 | order.as_ptr(), |
287 | ctx.as_ptr(), |
288 | )) |
289 | .map(|_| ()) |
290 | } |
291 | } |
292 | |
293 | /// Sets the flag determining if the group corresponds to a named curve or must be explicitly |
294 | /// parameterized. |
295 | /// |
296 | /// This defaults to `EXPLICIT_CURVE` in OpenSSL 1.0.1 and 1.0.2, but `NAMED_CURVE` in OpenSSL |
297 | /// 1.1.0. |
298 | #[corresponds (EC_GROUP_set_asn1_flag)] |
299 | pub fn set_asn1_flag(&mut self, flag: Asn1Flag) { |
300 | unsafe { |
301 | ffi::EC_GROUP_set_asn1_flag(self.as_ptr(), flag.0); |
302 | } |
303 | } |
304 | |
305 | /// Gets the flag determining if the group corresponds to a named curve. |
306 | #[corresponds (EC_GROUP_get_asn1_flag)] |
307 | pub fn asn1_flag(&self) -> Asn1Flag { |
308 | unsafe { Asn1Flag(ffi::EC_GROUP_get_asn1_flag(self.as_ptr())) } |
309 | } |
310 | |
311 | /// Returns the name of the curve, if a name is associated. |
312 | #[corresponds (EC_GROUP_get_curve_name)] |
313 | pub fn curve_name(&self) -> Option<Nid> { |
314 | let nid = unsafe { ffi::EC_GROUP_get_curve_name(self.as_ptr()) }; |
315 | if nid > 0 { |
316 | Some(Nid::from_raw(nid)) |
317 | } else { |
318 | None |
319 | } |
320 | } |
321 | } |
322 | |
323 | foreign_type_and_impl_send_sync! { |
324 | type CType = ffi::EC_POINT; |
325 | fn drop = ffi::EC_POINT_free; |
326 | |
327 | /// Represents a point on the curve |
328 | pub struct EcPoint; |
329 | /// A reference a borrowed [`EcPoint`]. |
330 | pub struct EcPointRef; |
331 | } |
332 | |
333 | impl EcPointRef { |
334 | /// Computes `a + b`, storing the result in `self`. |
335 | #[corresponds (EC_POINT_add)] |
336 | pub fn add( |
337 | &mut self, |
338 | group: &EcGroupRef, |
339 | a: &EcPointRef, |
340 | b: &EcPointRef, |
341 | ctx: &mut BigNumContextRef, |
342 | ) -> Result<(), ErrorStack> { |
343 | unsafe { |
344 | cvt(ffi::EC_POINT_add( |
345 | group.as_ptr(), |
346 | self.as_ptr(), |
347 | a.as_ptr(), |
348 | b.as_ptr(), |
349 | ctx.as_ptr(), |
350 | )) |
351 | .map(|_| ()) |
352 | } |
353 | } |
354 | |
355 | /// Computes `q * m`, storing the result in `self`. |
356 | #[corresponds (EC_POINT_mul)] |
357 | pub fn mul( |
358 | &mut self, |
359 | group: &EcGroupRef, |
360 | q: &EcPointRef, |
361 | m: &BigNumRef, |
362 | // FIXME should be &mut |
363 | ctx: &BigNumContextRef, |
364 | ) -> Result<(), ErrorStack> { |
365 | unsafe { |
366 | cvt(ffi::EC_POINT_mul( |
367 | group.as_ptr(), |
368 | self.as_ptr(), |
369 | ptr::null(), |
370 | q.as_ptr(), |
371 | m.as_ptr(), |
372 | ctx.as_ptr(), |
373 | )) |
374 | .map(|_| ()) |
375 | } |
376 | } |
377 | |
378 | /// Computes `generator * n`, storing the result in `self`. |
379 | #[corresponds (EC_POINT_mul)] |
380 | pub fn mul_generator( |
381 | &mut self, |
382 | group: &EcGroupRef, |
383 | n: &BigNumRef, |
384 | // FIXME should be &mut |
385 | ctx: &BigNumContextRef, |
386 | ) -> Result<(), ErrorStack> { |
387 | unsafe { |
388 | cvt(ffi::EC_POINT_mul( |
389 | group.as_ptr(), |
390 | self.as_ptr(), |
391 | n.as_ptr(), |
392 | ptr::null(), |
393 | ptr::null(), |
394 | ctx.as_ptr(), |
395 | )) |
396 | .map(|_| ()) |
397 | } |
398 | } |
399 | |
400 | /// Computes `generator * n + q * m`, storing the result in `self`. |
401 | #[corresponds (EC_POINT_mul)] |
402 | pub fn mul_full( |
403 | &mut self, |
404 | group: &EcGroupRef, |
405 | n: &BigNumRef, |
406 | q: &EcPointRef, |
407 | m: &BigNumRef, |
408 | ctx: &mut BigNumContextRef, |
409 | ) -> Result<(), ErrorStack> { |
410 | unsafe { |
411 | cvt(ffi::EC_POINT_mul( |
412 | group.as_ptr(), |
413 | self.as_ptr(), |
414 | n.as_ptr(), |
415 | q.as_ptr(), |
416 | m.as_ptr(), |
417 | ctx.as_ptr(), |
418 | )) |
419 | .map(|_| ()) |
420 | } |
421 | } |
422 | |
423 | /// Inverts `self`. |
424 | #[corresponds (EC_POINT_invert)] |
425 | // FIXME should be mutable |
426 | pub fn invert(&mut self, group: &EcGroupRef, ctx: &BigNumContextRef) -> Result<(), ErrorStack> { |
427 | unsafe { |
428 | cvt(ffi::EC_POINT_invert( |
429 | group.as_ptr(), |
430 | self.as_ptr(), |
431 | ctx.as_ptr(), |
432 | )) |
433 | .map(|_| ()) |
434 | } |
435 | } |
436 | |
437 | /// Serializes the point to a binary representation. |
438 | #[corresponds (EC_POINT_point2oct)] |
439 | pub fn to_bytes( |
440 | &self, |
441 | group: &EcGroupRef, |
442 | form: PointConversionForm, |
443 | ctx: &mut BigNumContextRef, |
444 | ) -> Result<Vec<u8>, ErrorStack> { |
445 | unsafe { |
446 | let len = ffi::EC_POINT_point2oct( |
447 | group.as_ptr(), |
448 | self.as_ptr(), |
449 | form.0, |
450 | ptr::null_mut(), |
451 | 0, |
452 | ctx.as_ptr(), |
453 | ); |
454 | if len == 0 { |
455 | return Err(ErrorStack::get()); |
456 | } |
457 | let mut buf = vec![0; len]; |
458 | let len = ffi::EC_POINT_point2oct( |
459 | group.as_ptr(), |
460 | self.as_ptr(), |
461 | form.0, |
462 | buf.as_mut_ptr(), |
463 | len, |
464 | ctx.as_ptr(), |
465 | ); |
466 | if len == 0 { |
467 | Err(ErrorStack::get()) |
468 | } else { |
469 | Ok(buf) |
470 | } |
471 | } |
472 | } |
473 | |
474 | /// Serializes the point to a hexadecimal string representation. |
475 | #[corresponds (EC_POINT_point2hex)] |
476 | #[cfg (not(boringssl))] |
477 | pub fn to_hex_str( |
478 | &self, |
479 | group: &EcGroupRef, |
480 | form: PointConversionForm, |
481 | ctx: &mut BigNumContextRef, |
482 | ) -> Result<OpensslString, ErrorStack> { |
483 | unsafe { |
484 | let buf = cvt_p(ffi::EC_POINT_point2hex( |
485 | group.as_ptr(), |
486 | self.as_ptr(), |
487 | form.0, |
488 | ctx.as_ptr(), |
489 | ))?; |
490 | Ok(OpensslString::from_ptr(buf)) |
491 | } |
492 | } |
493 | |
494 | /// Creates a new point on the specified curve with the same value. |
495 | #[corresponds (EC_POINT_dup)] |
496 | pub fn to_owned(&self, group: &EcGroupRef) -> Result<EcPoint, ErrorStack> { |
497 | unsafe { cvt_p(ffi::EC_POINT_dup(self.as_ptr(), group.as_ptr())).map(EcPoint) } |
498 | } |
499 | |
500 | /// Determines if this point is equal to another. |
501 | #[corresponds (EC_POINT_cmp)] |
502 | pub fn eq( |
503 | &self, |
504 | group: &EcGroupRef, |
505 | other: &EcPointRef, |
506 | ctx: &mut BigNumContextRef, |
507 | ) -> Result<bool, ErrorStack> { |
508 | unsafe { |
509 | let res = cvt_n(ffi::EC_POINT_cmp( |
510 | group.as_ptr(), |
511 | self.as_ptr(), |
512 | other.as_ptr(), |
513 | ctx.as_ptr(), |
514 | ))?; |
515 | Ok(res == 0) |
516 | } |
517 | } |
518 | |
519 | /// Places affine coordinates of a curve over a prime field in the provided |
520 | /// `x` and `y` `BigNum`s. |
521 | #[corresponds (EC_POINT_get_affine_coordinates)] |
522 | #[cfg (any(ossl111, boringssl, libressl350))] |
523 | pub fn affine_coordinates( |
524 | &self, |
525 | group: &EcGroupRef, |
526 | x: &mut BigNumRef, |
527 | y: &mut BigNumRef, |
528 | ctx: &mut BigNumContextRef, |
529 | ) -> Result<(), ErrorStack> { |
530 | unsafe { |
531 | cvt(ffi::EC_POINT_get_affine_coordinates( |
532 | group.as_ptr(), |
533 | self.as_ptr(), |
534 | x.as_ptr(), |
535 | y.as_ptr(), |
536 | ctx.as_ptr(), |
537 | )) |
538 | .map(|_| ()) |
539 | } |
540 | } |
541 | |
542 | /// Places affine coordinates of a curve over a prime field in the provided |
543 | /// `x` and `y` `BigNum`s |
544 | #[corresponds (EC_POINT_get_affine_coordinates_GFp)] |
545 | pub fn affine_coordinates_gfp( |
546 | &self, |
547 | group: &EcGroupRef, |
548 | x: &mut BigNumRef, |
549 | y: &mut BigNumRef, |
550 | ctx: &mut BigNumContextRef, |
551 | ) -> Result<(), ErrorStack> { |
552 | unsafe { |
553 | cvt(ffi::EC_POINT_get_affine_coordinates_GFp( |
554 | group.as_ptr(), |
555 | self.as_ptr(), |
556 | x.as_ptr(), |
557 | y.as_ptr(), |
558 | ctx.as_ptr(), |
559 | )) |
560 | .map(|_| ()) |
561 | } |
562 | } |
563 | |
564 | /// Sets affine coordinates of a curve over a prime field using the provided |
565 | /// `x` and `y` `BigNum`s |
566 | #[corresponds (EC_POINT_set_affine_coordinates_GFp)] |
567 | pub fn set_affine_coordinates_gfp( |
568 | &mut self, |
569 | group: &EcGroupRef, |
570 | x: &BigNumRef, |
571 | y: &BigNumRef, |
572 | ctx: &mut BigNumContextRef, |
573 | ) -> Result<(), ErrorStack> { |
574 | unsafe { |
575 | cvt(ffi::EC_POINT_set_affine_coordinates_GFp( |
576 | group.as_ptr(), |
577 | self.as_ptr(), |
578 | x.as_ptr(), |
579 | y.as_ptr(), |
580 | ctx.as_ptr(), |
581 | )) |
582 | .map(|_| ()) |
583 | } |
584 | } |
585 | |
586 | /// Places affine coordinates of a curve over a binary field in the provided |
587 | /// `x` and `y` `BigNum`s |
588 | #[corresponds (EC_POINT_get_affine_coordinates_GF2m)] |
589 | #[cfg (not(osslconf = "OPENSSL_NO_EC2M" ))] |
590 | pub fn affine_coordinates_gf2m( |
591 | &self, |
592 | group: &EcGroupRef, |
593 | x: &mut BigNumRef, |
594 | y: &mut BigNumRef, |
595 | ctx: &mut BigNumContextRef, |
596 | ) -> Result<(), ErrorStack> { |
597 | unsafe { |
598 | cvt(ffi::EC_POINT_get_affine_coordinates_GF2m( |
599 | group.as_ptr(), |
600 | self.as_ptr(), |
601 | x.as_ptr(), |
602 | y.as_ptr(), |
603 | ctx.as_ptr(), |
604 | )) |
605 | .map(|_| ()) |
606 | } |
607 | } |
608 | |
609 | /// Checks if point is infinity |
610 | #[corresponds (EC_POINT_is_at_infinity)] |
611 | pub fn is_infinity(&self, group: &EcGroupRef) -> bool { |
612 | unsafe { |
613 | let res = ffi::EC_POINT_is_at_infinity(group.as_ptr(), self.as_ptr()); |
614 | res == 1 |
615 | } |
616 | } |
617 | |
618 | /// Checks if point is on a given curve |
619 | #[corresponds (EC_POINT_is_on_curve)] |
620 | pub fn is_on_curve( |
621 | &self, |
622 | group: &EcGroupRef, |
623 | ctx: &mut BigNumContextRef, |
624 | ) -> Result<bool, ErrorStack> { |
625 | unsafe { |
626 | let res = cvt_n(ffi::EC_POINT_is_on_curve( |
627 | group.as_ptr(), |
628 | self.as_ptr(), |
629 | ctx.as_ptr(), |
630 | ))?; |
631 | Ok(res == 1) |
632 | } |
633 | } |
634 | } |
635 | |
636 | impl EcPoint { |
637 | /// Creates a new point on the specified curve. |
638 | #[corresponds (EC_POINT_new)] |
639 | pub fn new(group: &EcGroupRef) -> Result<EcPoint, ErrorStack> { |
640 | unsafe { cvt_p(ffi::EC_POINT_new(group.as_ptr())).map(EcPoint) } |
641 | } |
642 | |
643 | /// Creates point from a binary representation |
644 | #[corresponds (EC_POINT_oct2point)] |
645 | pub fn from_bytes( |
646 | group: &EcGroupRef, |
647 | buf: &[u8], |
648 | ctx: &mut BigNumContextRef, |
649 | ) -> Result<EcPoint, ErrorStack> { |
650 | let point = EcPoint::new(group)?; |
651 | unsafe { |
652 | cvt(ffi::EC_POINT_oct2point( |
653 | group.as_ptr(), |
654 | point.as_ptr(), |
655 | buf.as_ptr(), |
656 | buf.len(), |
657 | ctx.as_ptr(), |
658 | ))?; |
659 | } |
660 | Ok(point) |
661 | } |
662 | |
663 | /// Creates point from a hexadecimal string representation |
664 | #[corresponds (EC_POINT_hex2point)] |
665 | #[cfg (not(boringssl))] |
666 | pub fn from_hex_str( |
667 | group: &EcGroupRef, |
668 | s: &str, |
669 | ctx: &mut BigNumContextRef, |
670 | ) -> Result<EcPoint, ErrorStack> { |
671 | let point = EcPoint::new(group)?; |
672 | unsafe { |
673 | let c_str = CString::new(s.as_bytes()).unwrap(); |
674 | cvt_p(ffi::EC_POINT_hex2point( |
675 | group.as_ptr(), |
676 | c_str.as_ptr() as *const _, |
677 | point.as_ptr(), |
678 | ctx.as_ptr(), |
679 | ))?; |
680 | } |
681 | Ok(point) |
682 | } |
683 | } |
684 | |
685 | generic_foreign_type_and_impl_send_sync! { |
686 | type CType = ffi::EC_KEY; |
687 | fn drop = ffi::EC_KEY_free; |
688 | |
689 | /// Public and optional private key on the given curve. |
690 | pub struct EcKey<T>; |
691 | /// A reference to an [`EcKey`]. |
692 | pub struct EcKeyRef<T>; |
693 | } |
694 | |
695 | impl<T> EcKeyRef<T> |
696 | where |
697 | T: HasPrivate, |
698 | { |
699 | private_key_to_pem! { |
700 | /// Serializes the private key to a PEM-encoded ECPrivateKey structure. |
701 | /// |
702 | /// The output will have a header of `-----BEGIN EC PRIVATE KEY-----`. |
703 | #[corresponds (PEM_write_bio_ECPrivateKey)] |
704 | private_key_to_pem, |
705 | /// Serializes the private key to a PEM-encoded encrypted ECPrivateKey structure. |
706 | /// |
707 | /// The output will have a header of `-----BEGIN EC PRIVATE KEY-----`. |
708 | #[corresponds (PEM_write_bio_ECPrivateKey)] |
709 | private_key_to_pem_passphrase, |
710 | ffi::PEM_write_bio_ECPrivateKey |
711 | } |
712 | |
713 | to_der! { |
714 | /// Serializes the private key into a DER-encoded ECPrivateKey structure. |
715 | #[corresponds (i2d_ECPrivateKey)] |
716 | private_key_to_der, |
717 | ffi::i2d_ECPrivateKey |
718 | } |
719 | |
720 | /// Returns the private key value. |
721 | #[corresponds (EC_KEY_get0_private_key)] |
722 | pub fn private_key(&self) -> &BigNumRef { |
723 | unsafe { |
724 | let ptr = ffi::EC_KEY_get0_private_key(self.as_ptr()); |
725 | BigNumRef::from_const_ptr(ptr) |
726 | } |
727 | } |
728 | } |
729 | |
730 | impl<T> EcKeyRef<T> |
731 | where |
732 | T: HasPublic, |
733 | { |
734 | /// Returns the public key. |
735 | #[corresponds (EC_KEY_get0_public_key)] |
736 | pub fn public_key(&self) -> &EcPointRef { |
737 | unsafe { |
738 | let ptr = ffi::EC_KEY_get0_public_key(self.as_ptr()); |
739 | EcPointRef::from_const_ptr(ptr) |
740 | } |
741 | } |
742 | |
743 | to_pem! { |
744 | /// Serializes the public key into a PEM-encoded SubjectPublicKeyInfo structure. |
745 | /// |
746 | /// The output will have a header of `-----BEGIN PUBLIC KEY-----`. |
747 | #[corresponds (PEM_write_bio_EC_PUBKEY)] |
748 | public_key_to_pem, |
749 | ffi::PEM_write_bio_EC_PUBKEY |
750 | } |
751 | |
752 | to_der! { |
753 | /// Serializes the public key into a DER-encoded SubjectPublicKeyInfo structure. |
754 | #[corresponds (i2d_EC_PUBKEY)] |
755 | public_key_to_der, |
756 | ffi::i2d_EC_PUBKEY |
757 | } |
758 | } |
759 | |
760 | impl<T> EcKeyRef<T> |
761 | where |
762 | T: HasParams, |
763 | { |
764 | /// Returns the key's group. |
765 | #[corresponds (EC_KEY_get0_group)] |
766 | pub fn group(&self) -> &EcGroupRef { |
767 | unsafe { |
768 | let ptr: *const EC_GROUP = ffi::EC_KEY_get0_group(self.as_ptr()); |
769 | EcGroupRef::from_const_ptr(ptr) |
770 | } |
771 | } |
772 | |
773 | /// Checks the key for validity. |
774 | #[corresponds (EC_KEY_check_key)] |
775 | pub fn check_key(&self) -> Result<(), ErrorStack> { |
776 | unsafe { cvt(ffi::EC_KEY_check_key(self.as_ptr())).map(|_| ()) } |
777 | } |
778 | } |
779 | |
780 | impl<T> ToOwned for EcKeyRef<T> { |
781 | type Owned = EcKey<T>; |
782 | |
783 | fn to_owned(&self) -> EcKey<T> { |
784 | unsafe { |
785 | let r: i32 = ffi::EC_KEY_up_ref(self.as_ptr()); |
786 | assert!(r == 1); |
787 | EcKey::from_ptr(self.as_ptr()) |
788 | } |
789 | } |
790 | } |
791 | |
792 | impl EcKey<Params> { |
793 | /// Constructs an `EcKey` corresponding to a known curve. |
794 | /// |
795 | /// It will not have an associated public or private key. This kind of key is primarily useful |
796 | /// to be provided to the `set_tmp_ecdh` methods on `Ssl` and `SslContextBuilder`. |
797 | #[corresponds (EC_KEY_new_by_curve_name)] |
798 | pub fn from_curve_name(nid: Nid) -> Result<EcKey<Params>, ErrorStack> { |
799 | unsafe { |
800 | init(); |
801 | cvt_p(ffi::EC_KEY_new_by_curve_name(nid.as_raw())).map(|p| EcKey::from_ptr(p)) |
802 | } |
803 | } |
804 | |
805 | /// Constructs an `EcKey` corresponding to a curve. |
806 | #[corresponds (EC_KEY_set_group)] |
807 | pub fn from_group(group: &EcGroupRef) -> Result<EcKey<Params>, ErrorStack> { |
808 | unsafe { |
809 | cvt_p(ffi::EC_KEY_new()) |
810 | .map(|p| EcKey::from_ptr(p)) |
811 | .and_then(|key| { |
812 | cvt(ffi::EC_KEY_set_group(key.as_ptr(), group.as_ptr())).map(|_| key) |
813 | }) |
814 | } |
815 | } |
816 | } |
817 | |
818 | impl EcKey<Public> { |
819 | /// Constructs an `EcKey` from the specified group with the associated [`EcPoint`]: `public_key`. |
820 | /// |
821 | /// This will only have the associated `public_key`. |
822 | /// |
823 | /// # Example |
824 | /// |
825 | /// ``` |
826 | /// # fn main() -> Result<(), Box<dyn std::error::Error>> { |
827 | /// use openssl::bn::BigNumContext; |
828 | /// use openssl::ec::*; |
829 | /// use openssl::nid::Nid; |
830 | /// use openssl::pkey::PKey; |
831 | /// |
832 | /// let group = EcGroup::from_curve_name(Nid::SECP384R1)?; |
833 | /// let mut ctx = BigNumContext::new()?; |
834 | /// |
835 | /// // get bytes from somewhere |
836 | /// let public_key = // ... |
837 | /// # EcKey::generate(&group)?.public_key().to_bytes(&group, |
838 | /// # PointConversionForm::COMPRESSED, &mut ctx)?; |
839 | /// |
840 | /// // create an EcKey from the binary form of a EcPoint |
841 | /// let point = EcPoint::from_bytes(&group, &public_key, &mut ctx)?; |
842 | /// let key = EcKey::from_public_key(&group, &point)?; |
843 | /// key.check_key()?; |
844 | /// # Ok(()) } |
845 | /// ``` |
846 | #[corresponds (EC_KEY_set_public_key)] |
847 | pub fn from_public_key( |
848 | group: &EcGroupRef, |
849 | public_key: &EcPointRef, |
850 | ) -> Result<EcKey<Public>, ErrorStack> { |
851 | unsafe { |
852 | cvt_p(ffi::EC_KEY_new()) |
853 | .map(|p| EcKey::from_ptr(p)) |
854 | .and_then(|key| { |
855 | cvt(ffi::EC_KEY_set_group(key.as_ptr(), group.as_ptr())).map(|_| key) |
856 | }) |
857 | .and_then(|key| { |
858 | cvt(ffi::EC_KEY_set_public_key( |
859 | key.as_ptr(), |
860 | public_key.as_ptr(), |
861 | )) |
862 | .map(|_| key) |
863 | }) |
864 | } |
865 | } |
866 | |
867 | /// Constructs a public key from its affine coordinates. |
868 | #[corresponds (EC_KEY_set_public_key_affine_coordinates)] |
869 | pub fn from_public_key_affine_coordinates( |
870 | group: &EcGroupRef, |
871 | x: &BigNumRef, |
872 | y: &BigNumRef, |
873 | ) -> Result<EcKey<Public>, ErrorStack> { |
874 | unsafe { |
875 | cvt_p(ffi::EC_KEY_new()) |
876 | .map(|p| EcKey::from_ptr(p)) |
877 | .and_then(|key| { |
878 | cvt(ffi::EC_KEY_set_group(key.as_ptr(), group.as_ptr())).map(|_| key) |
879 | }) |
880 | .and_then(|key| { |
881 | cvt(ffi::EC_KEY_set_public_key_affine_coordinates( |
882 | key.as_ptr(), |
883 | x.as_ptr(), |
884 | y.as_ptr(), |
885 | )) |
886 | .map(|_| key) |
887 | }) |
888 | } |
889 | } |
890 | |
891 | from_pem! { |
892 | /// Decodes a PEM-encoded SubjectPublicKeyInfo structure containing a EC key. |
893 | /// |
894 | /// The input should have a header of `-----BEGIN PUBLIC KEY-----`. |
895 | #[corresponds (PEM_read_bio_EC_PUBKEY)] |
896 | public_key_from_pem, |
897 | EcKey<Public>, |
898 | ffi::PEM_read_bio_EC_PUBKEY |
899 | } |
900 | |
901 | from_der! { |
902 | /// Decodes a DER-encoded SubjectPublicKeyInfo structure containing a EC key. |
903 | #[corresponds (d2i_EC_PUBKEY)] |
904 | public_key_from_der, |
905 | EcKey<Public>, |
906 | ffi::d2i_EC_PUBKEY |
907 | } |
908 | } |
909 | |
910 | impl EcKey<Private> { |
911 | /// Generates a new public/private key pair on the specified curve. |
912 | /// |
913 | /// # Examples |
914 | /// |
915 | /// ``` |
916 | /// # fn main() -> Result<(), Box<dyn std::error::Error>> { |
917 | /// use openssl::bn::BigNumContext; |
918 | /// use openssl::nid::Nid; |
919 | /// use openssl::ec::{EcGroup, EcKey, PointConversionForm}; |
920 | /// |
921 | /// let nid = Nid::X9_62_PRIME256V1; // NIST P-256 curve |
922 | /// let group = EcGroup::from_curve_name(nid)?; |
923 | /// let key = EcKey::generate(&group)?; |
924 | /// |
925 | /// let mut ctx = BigNumContext::new()?; |
926 | /// |
927 | /// let public_key = &key.public_key().to_bytes( |
928 | /// &group, |
929 | /// PointConversionForm::COMPRESSED, |
930 | /// &mut ctx, |
931 | /// )?; |
932 | /// assert_eq!(public_key.len(), 33); |
933 | /// assert_ne!(public_key[0], 0x04); |
934 | /// |
935 | /// let private_key = key.private_key().to_vec(); |
936 | /// assert!(private_key.len() >= 31); |
937 | /// # Ok(()) } |
938 | /// ``` |
939 | #[corresponds (EC_KEY_generate_key)] |
940 | pub fn generate(group: &EcGroupRef) -> Result<EcKey<Private>, ErrorStack> { |
941 | unsafe { |
942 | cvt_p(ffi::EC_KEY_new()) |
943 | .map(|p| EcKey::from_ptr(p)) |
944 | .and_then(|key| { |
945 | cvt(ffi::EC_KEY_set_group(key.as_ptr(), group.as_ptr())).map(|_| key) |
946 | }) |
947 | .and_then(|key| cvt(ffi::EC_KEY_generate_key(key.as_ptr())).map(|_| key)) |
948 | } |
949 | } |
950 | |
951 | /// Constructs an public/private key pair given a curve, a private key and a public key point. |
952 | #[corresponds (EC_KEY_set_private_key)] |
953 | pub fn from_private_components( |
954 | group: &EcGroupRef, |
955 | private_number: &BigNumRef, |
956 | public_key: &EcPointRef, |
957 | ) -> Result<EcKey<Private>, ErrorStack> { |
958 | unsafe { |
959 | cvt_p(ffi::EC_KEY_new()) |
960 | .map(|p| EcKey::from_ptr(p)) |
961 | .and_then(|key| { |
962 | cvt(ffi::EC_KEY_set_group(key.as_ptr(), group.as_ptr())).map(|_| key) |
963 | }) |
964 | .and_then(|key| { |
965 | cvt(ffi::EC_KEY_set_private_key( |
966 | key.as_ptr(), |
967 | private_number.as_ptr(), |
968 | )) |
969 | .map(|_| key) |
970 | }) |
971 | .and_then(|key| { |
972 | cvt(ffi::EC_KEY_set_public_key( |
973 | key.as_ptr(), |
974 | public_key.as_ptr(), |
975 | )) |
976 | .map(|_| key) |
977 | }) |
978 | } |
979 | } |
980 | |
981 | private_key_from_pem! { |
982 | /// Deserializes a private key from a PEM-encoded ECPrivateKey structure. |
983 | /// |
984 | /// The input should have a header of `-----BEGIN EC PRIVATE KEY-----`. |
985 | #[corresponds (PEM_read_bio_ECPrivateKey)] |
986 | private_key_from_pem, |
987 | |
988 | /// Deserializes a private key from a PEM-encoded encrypted ECPrivateKey structure. |
989 | /// |
990 | /// The input should have a header of `-----BEGIN EC PRIVATE KEY-----`. |
991 | #[corresponds (PEM_read_bio_ECPrivateKey)] |
992 | private_key_from_pem_passphrase, |
993 | |
994 | /// Deserializes a private key from a PEM-encoded encrypted ECPrivateKey structure. |
995 | /// |
996 | /// The callback should fill the password into the provided buffer and return its length. |
997 | /// |
998 | /// The input should have a header of `-----BEGIN EC PRIVATE KEY-----`. |
999 | #[corresponds (PEM_read_bio_ECPrivateKey)] |
1000 | private_key_from_pem_callback, |
1001 | EcKey<Private>, |
1002 | ffi::PEM_read_bio_ECPrivateKey |
1003 | } |
1004 | |
1005 | from_der! { |
1006 | /// Decodes a DER-encoded elliptic curve private key structure. |
1007 | #[corresponds (d2i_ECPrivateKey)] |
1008 | private_key_from_der, |
1009 | EcKey<Private>, |
1010 | ffi::d2i_ECPrivateKey |
1011 | } |
1012 | } |
1013 | |
1014 | impl<T> Clone for EcKey<T> { |
1015 | fn clone(&self) -> EcKey<T> { |
1016 | (**self).to_owned() |
1017 | } |
1018 | } |
1019 | |
1020 | impl<T> fmt::Debug for EcKey<T> { |
1021 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
1022 | write!(f, "EcKey" ) |
1023 | } |
1024 | } |
1025 | |
1026 | #[cfg (test)] |
1027 | mod test { |
1028 | use hex::FromHex; |
1029 | |
1030 | use super::*; |
1031 | use crate::bn::{BigNum, BigNumContext}; |
1032 | use crate::nid::Nid; |
1033 | |
1034 | #[test ] |
1035 | fn key_new_by_curve_name() { |
1036 | EcKey::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); |
1037 | } |
1038 | |
1039 | #[test ] |
1040 | fn generate() { |
1041 | let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); |
1042 | EcKey::generate(&group).unwrap(); |
1043 | } |
1044 | |
1045 | #[test ] |
1046 | fn ec_group_from_components() { |
1047 | // parameters are from secp256r1 |
1048 | let p = BigNum::from_hex_str( |
1049 | "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF" , |
1050 | ) |
1051 | .unwrap(); |
1052 | let a = BigNum::from_hex_str( |
1053 | "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC" , |
1054 | ) |
1055 | .unwrap(); |
1056 | let b = BigNum::from_hex_str( |
1057 | "5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B" , |
1058 | ) |
1059 | .unwrap(); |
1060 | let mut ctx = BigNumContext::new().unwrap(); |
1061 | |
1062 | let _curve = EcGroup::from_components(p, a, b, &mut ctx).unwrap(); |
1063 | } |
1064 | |
1065 | #[test ] |
1066 | fn ec_point_set_affine() { |
1067 | // parameters are from secp256r1 |
1068 | let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); |
1069 | let mut ctx = BigNumContext::new().unwrap(); |
1070 | let mut gen_point = EcPoint::new(&group).unwrap(); |
1071 | let gen_x = BigNum::from_hex_str( |
1072 | "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296" , |
1073 | ) |
1074 | .unwrap(); |
1075 | let gen_y = BigNum::from_hex_str( |
1076 | "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5" , |
1077 | ) |
1078 | .unwrap(); |
1079 | gen_point |
1080 | .set_affine_coordinates_gfp(&group, &gen_x, &gen_y, &mut ctx) |
1081 | .unwrap(); |
1082 | assert!(gen_point.is_on_curve(&group, &mut ctx).unwrap()); |
1083 | } |
1084 | |
1085 | #[test ] |
1086 | fn ec_group_set_generator() { |
1087 | // parameters are from secp256r1 |
1088 | let mut ctx = BigNumContext::new().unwrap(); |
1089 | let p = BigNum::from_hex_str( |
1090 | "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF" , |
1091 | ) |
1092 | .unwrap(); |
1093 | let a = BigNum::from_hex_str( |
1094 | "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC" , |
1095 | ) |
1096 | .unwrap(); |
1097 | let b = BigNum::from_hex_str( |
1098 | "5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B" , |
1099 | ) |
1100 | .unwrap(); |
1101 | |
1102 | let mut group = EcGroup::from_components(p, a, b, &mut ctx).unwrap(); |
1103 | |
1104 | let mut gen_point = EcPoint::new(&group).unwrap(); |
1105 | let gen_x = BigNum::from_hex_str( |
1106 | "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296" , |
1107 | ) |
1108 | .unwrap(); |
1109 | let gen_y = BigNum::from_hex_str( |
1110 | "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5" , |
1111 | ) |
1112 | .unwrap(); |
1113 | gen_point |
1114 | .set_affine_coordinates_gfp(&group, &gen_x, &gen_y, &mut ctx) |
1115 | .unwrap(); |
1116 | |
1117 | let order = BigNum::from_hex_str( |
1118 | "FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551" , |
1119 | ) |
1120 | .unwrap(); |
1121 | let cofactor = BigNum::from_hex_str("01" ).unwrap(); |
1122 | group.set_generator(gen_point, order, cofactor).unwrap(); |
1123 | let mut constructed_order = BigNum::new().unwrap(); |
1124 | group.order(&mut constructed_order, &mut ctx).unwrap(); |
1125 | |
1126 | let named_group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); |
1127 | let mut named_order = BigNum::new().unwrap(); |
1128 | named_group.order(&mut named_order, &mut ctx).unwrap(); |
1129 | |
1130 | assert_eq!( |
1131 | constructed_order.ucmp(&named_order), |
1132 | std::cmp::Ordering::Equal |
1133 | ); |
1134 | } |
1135 | |
1136 | #[test ] |
1137 | fn cofactor() { |
1138 | let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); |
1139 | let mut ctx = BigNumContext::new().unwrap(); |
1140 | let mut cofactor = BigNum::new().unwrap(); |
1141 | group.cofactor(&mut cofactor, &mut ctx).unwrap(); |
1142 | let one = BigNum::from_u32(1).unwrap(); |
1143 | assert_eq!(cofactor, one); |
1144 | } |
1145 | |
1146 | #[test ] |
1147 | #[allow (clippy::redundant_clone)] |
1148 | fn dup() { |
1149 | let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); |
1150 | let key = EcKey::generate(&group).unwrap(); |
1151 | drop(key.clone()); |
1152 | } |
1153 | |
1154 | #[test ] |
1155 | fn point_new() { |
1156 | let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); |
1157 | EcPoint::new(&group).unwrap(); |
1158 | } |
1159 | |
1160 | #[test ] |
1161 | fn point_bytes() { |
1162 | let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); |
1163 | let key = EcKey::generate(&group).unwrap(); |
1164 | let point = key.public_key(); |
1165 | let mut ctx = BigNumContext::new().unwrap(); |
1166 | let bytes = point |
1167 | .to_bytes(&group, PointConversionForm::COMPRESSED, &mut ctx) |
1168 | .unwrap(); |
1169 | let point2 = EcPoint::from_bytes(&group, &bytes, &mut ctx).unwrap(); |
1170 | assert!(point.eq(&group, &point2, &mut ctx).unwrap()); |
1171 | } |
1172 | |
1173 | #[test ] |
1174 | #[cfg (not(boringssl))] |
1175 | fn point_hex_str() { |
1176 | let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); |
1177 | let key = EcKey::generate(&group).unwrap(); |
1178 | let point = key.public_key(); |
1179 | let mut ctx = BigNumContext::new().unwrap(); |
1180 | let hex = point |
1181 | .to_hex_str(&group, PointConversionForm::COMPRESSED, &mut ctx) |
1182 | .unwrap(); |
1183 | let point2 = EcPoint::from_hex_str(&group, &hex, &mut ctx).unwrap(); |
1184 | assert!(point.eq(&group, &point2, &mut ctx).unwrap()); |
1185 | } |
1186 | |
1187 | #[test ] |
1188 | fn point_owned() { |
1189 | let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); |
1190 | let key = EcKey::generate(&group).unwrap(); |
1191 | let point = key.public_key(); |
1192 | let owned = point.to_owned(&group).unwrap(); |
1193 | let mut ctx = BigNumContext::new().unwrap(); |
1194 | assert!(owned.eq(&group, point, &mut ctx).unwrap()); |
1195 | } |
1196 | |
1197 | #[test ] |
1198 | fn mul_generator() { |
1199 | let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); |
1200 | let key = EcKey::generate(&group).unwrap(); |
1201 | let mut ctx = BigNumContext::new().unwrap(); |
1202 | let mut public_key = EcPoint::new(&group).unwrap(); |
1203 | public_key |
1204 | .mul_generator(&group, key.private_key(), &ctx) |
1205 | .unwrap(); |
1206 | assert!(public_key.eq(&group, key.public_key(), &mut ctx).unwrap()); |
1207 | } |
1208 | |
1209 | #[test ] |
1210 | fn generator() { |
1211 | let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); |
1212 | let gen = group.generator(); |
1213 | let one = BigNum::from_u32(1).unwrap(); |
1214 | let mut ctx = BigNumContext::new().unwrap(); |
1215 | let mut ecp = EcPoint::new(&group).unwrap(); |
1216 | ecp.mul_generator(&group, &one, &ctx).unwrap(); |
1217 | assert!(ecp.eq(&group, gen, &mut ctx).unwrap()); |
1218 | } |
1219 | |
1220 | #[test ] |
1221 | fn key_from_public_key() { |
1222 | let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); |
1223 | let key = EcKey::generate(&group).unwrap(); |
1224 | let mut ctx = BigNumContext::new().unwrap(); |
1225 | let bytes = key |
1226 | .public_key() |
1227 | .to_bytes(&group, PointConversionForm::COMPRESSED, &mut ctx) |
1228 | .unwrap(); |
1229 | |
1230 | drop(key); |
1231 | let public_key = EcPoint::from_bytes(&group, &bytes, &mut ctx).unwrap(); |
1232 | let ec_key = EcKey::from_public_key(&group, &public_key).unwrap(); |
1233 | assert!(ec_key.check_key().is_ok()); |
1234 | } |
1235 | |
1236 | #[test ] |
1237 | fn key_from_private_components() { |
1238 | let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); |
1239 | let key = EcKey::generate(&group).unwrap(); |
1240 | |
1241 | let dup_key = |
1242 | EcKey::from_private_components(&group, key.private_key(), key.public_key()).unwrap(); |
1243 | dup_key.check_key().unwrap(); |
1244 | |
1245 | assert!(key.private_key() == dup_key.private_key()); |
1246 | } |
1247 | |
1248 | #[test ] |
1249 | fn key_from_affine_coordinates() { |
1250 | let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); |
1251 | let x = Vec::from_hex("30a0424cd21c2944838a2d75c92b37e76ea20d9f00893a3b4eee8a3c0aafec3e" ) |
1252 | .unwrap(); |
1253 | let y = Vec::from_hex("e04b65e92456d9888b52b379bdfbd51ee869ef1f0fc65b6659695b6cce081723" ) |
1254 | .unwrap(); |
1255 | |
1256 | let xbn = BigNum::from_slice(&x).unwrap(); |
1257 | let ybn = BigNum::from_slice(&y).unwrap(); |
1258 | |
1259 | let ec_key = EcKey::from_public_key_affine_coordinates(&group, &xbn, &ybn).unwrap(); |
1260 | assert!(ec_key.check_key().is_ok()); |
1261 | } |
1262 | |
1263 | #[cfg (any(ossl111, boringssl, libressl350))] |
1264 | #[test ] |
1265 | fn get_affine_coordinates() { |
1266 | let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); |
1267 | let x = Vec::from_hex("30a0424cd21c2944838a2d75c92b37e76ea20d9f00893a3b4eee8a3c0aafec3e" ) |
1268 | .unwrap(); |
1269 | let y = Vec::from_hex("e04b65e92456d9888b52b379bdfbd51ee869ef1f0fc65b6659695b6cce081723" ) |
1270 | .unwrap(); |
1271 | |
1272 | let xbn = BigNum::from_slice(&x).unwrap(); |
1273 | let ybn = BigNum::from_slice(&y).unwrap(); |
1274 | |
1275 | let ec_key = EcKey::from_public_key_affine_coordinates(&group, &xbn, &ybn).unwrap(); |
1276 | |
1277 | let mut xbn2 = BigNum::new().unwrap(); |
1278 | let mut ybn2 = BigNum::new().unwrap(); |
1279 | let mut ctx = BigNumContext::new().unwrap(); |
1280 | let ec_key_pk = ec_key.public_key(); |
1281 | ec_key_pk |
1282 | .affine_coordinates(&group, &mut xbn2, &mut ybn2, &mut ctx) |
1283 | .unwrap(); |
1284 | assert_eq!(xbn2, xbn); |
1285 | assert_eq!(ybn2, ybn); |
1286 | } |
1287 | |
1288 | #[test ] |
1289 | fn get_affine_coordinates_gfp() { |
1290 | let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); |
1291 | let x = Vec::from_hex("30a0424cd21c2944838a2d75c92b37e76ea20d9f00893a3b4eee8a3c0aafec3e" ) |
1292 | .unwrap(); |
1293 | let y = Vec::from_hex("e04b65e92456d9888b52b379bdfbd51ee869ef1f0fc65b6659695b6cce081723" ) |
1294 | .unwrap(); |
1295 | |
1296 | let xbn = BigNum::from_slice(&x).unwrap(); |
1297 | let ybn = BigNum::from_slice(&y).unwrap(); |
1298 | |
1299 | let ec_key = EcKey::from_public_key_affine_coordinates(&group, &xbn, &ybn).unwrap(); |
1300 | |
1301 | let mut xbn2 = BigNum::new().unwrap(); |
1302 | let mut ybn2 = BigNum::new().unwrap(); |
1303 | let mut ctx = BigNumContext::new().unwrap(); |
1304 | let ec_key_pk = ec_key.public_key(); |
1305 | ec_key_pk |
1306 | .affine_coordinates_gfp(&group, &mut xbn2, &mut ybn2, &mut ctx) |
1307 | .unwrap(); |
1308 | assert_eq!(xbn2, xbn); |
1309 | assert_eq!(ybn2, ybn); |
1310 | } |
1311 | |
1312 | #[test ] |
1313 | fn is_infinity() { |
1314 | let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); |
1315 | let mut ctx = BigNumContext::new().unwrap(); |
1316 | let g = group.generator(); |
1317 | assert!(!g.is_infinity(&group)); |
1318 | |
1319 | let mut order = BigNum::new().unwrap(); |
1320 | group.order(&mut order, &mut ctx).unwrap(); |
1321 | let mut inf = EcPoint::new(&group).unwrap(); |
1322 | inf.mul_generator(&group, &order, &ctx).unwrap(); |
1323 | assert!(inf.is_infinity(&group)); |
1324 | } |
1325 | |
1326 | #[test ] |
1327 | #[cfg (not(osslconf = "OPENSSL_NO_EC2M" ))] |
1328 | fn is_on_curve() { |
1329 | let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); |
1330 | let mut ctx = BigNumContext::new().unwrap(); |
1331 | let g = group.generator(); |
1332 | assert!(g.is_on_curve(&group, &mut ctx).unwrap()); |
1333 | |
1334 | let group2 = EcGroup::from_curve_name(Nid::X9_62_PRIME239V3).unwrap(); |
1335 | assert!(!g.is_on_curve(&group2, &mut ctx).unwrap()); |
1336 | } |
1337 | |
1338 | #[test ] |
1339 | #[cfg (any(boringssl, ossl111, libressl350))] |
1340 | fn asn1_flag() { |
1341 | let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); |
1342 | let flag = group.asn1_flag(); |
1343 | assert_eq!(flag, Asn1Flag::NAMED_CURVE); |
1344 | } |
1345 | } |
1346 | |