3 //! Cryptology 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 eliptic curve. This module provides low-level features of the latter.
6 //! Elliptic Curve protocols can provide the same security with smaller keys.
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 cuves are generally referenced by [`EcGroup`]. There are many built in groups
13 //! OpenSSL Wiki explains the fields and curves in detail at [Eliptic Curve Cryptography].
15 //! [`EcGroup`]: struct.EcGroup.html
16 //! [`Nid`]: ../nid/struct.Nid.html
17 //! [Eliptic Curve Cryptography]: https://wiki.openssl.org/index.php/Elliptic_Curve_Cryptography
18 use foreign_types
::{ForeignType, ForeignTypeRef}
;
23 use crate::bn
::{BigNumContextRef, BigNumRef}
;
24 use crate::error
::ErrorStack
;
26 use crate::pkey
::{HasParams, HasPrivate, HasPublic, Params, Private, Public}
;
27 use crate::util
::ForeignTypeRefExt
;
28 use crate::{cvt, cvt_n, cvt_p, init}
;
30 /// Compressed or Uncompressed conversion
32 /// Conversion from the binary value of the point on the curve is performed in one of
33 /// compressed, uncompressed, or hybrid conversions. The default is compressed, except
34 /// for binary curves.
36 /// Further documentation is available in the [X9.62] standard.
38 /// [X9.62]: http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.202.2977&rep=rep1&type=pdf
39 #[derive(Copy, Clone)]
40 pub struct PointConversionForm(ffi
::point_conversion_form_t
);
42 impl PointConversionForm
{
43 /// Compressed conversion from point value.
44 pub const COMPRESSED
: PointConversionForm
=
45 PointConversionForm(ffi
::point_conversion_form_t
::POINT_CONVERSION_COMPRESSED
);
47 /// Uncompressed conversion from point value.
48 pub const UNCOMPRESSED
: PointConversionForm
=
49 PointConversionForm(ffi
::point_conversion_form_t
::POINT_CONVERSION_UNCOMPRESSED
);
51 /// Performs both compressed and uncompressed conversions.
52 pub const HYBRID
: PointConversionForm
=
53 PointConversionForm(ffi
::point_conversion_form_t
::POINT_CONVERSION_HYBRID
);
56 /// Named Curve or Explicit
58 /// This type acts as a boolean as to whether the `EcGroup` is named or explicit.
59 #[derive(Copy, Clone)]
60 pub struct Asn1Flag(c_int
);
63 /// Curve defined using polynomial parameters
65 /// Most applications use a named EC_GROUP curve, however, support
66 /// is included to explicitly define the curve used to calculate keys
67 /// This information would need to be known by both endpoint to make communication
70 /// OPENSSL_EC_EXPLICIT_CURVE, but that was only added in 1.1.
71 /// Man page documents that 0 can be used in older versions.
73 /// OpenSSL documentation at [`EC_GROUP`]
75 /// [`EC_GROUP`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_GROUP_get_seed_len.html
76 pub const EXPLICIT_CURVE
: Asn1Flag
= Asn1Flag(0);
80 /// Curves that make up the typical encryption use cases. The collection of curves
81 /// are well known but extensible.
83 /// OpenSSL documentation at [`EC_GROUP`]
85 /// [`EC_GROUP`]: https://www.openssl.org/docs/manmaster/man3/EC_GROUP_order_bits.html
86 pub const NAMED_CURVE
: Asn1Flag
= Asn1Flag(ffi
::OPENSSL_EC_NAMED_CURVE
);
89 foreign_type_and_impl_send_sync
! {
90 type CType
= ffi
::EC_GROUP
;
91 fn drop
= ffi
::EC_GROUP_free
;
93 /// Describes the curve
95 /// A curve can be of the named curve type. These curves can be discovered
96 /// using openssl binary `openssl ecparam -list_curves`. Other operations
97 /// are available in the [wiki]. These named curves are available in the
100 /// Curves can also be generated using prime field parameters or a binary field.
102 /// Prime fields use the formula `y^2 mod p = x^3 + ax + b mod p`. Binary
103 /// fields use the formula `y^2 + xy = x^3 + ax^2 + b`. Named curves have
104 /// assured security. To prevent accidental vulnerabilities, they should
107 /// [wiki]: https://wiki.openssl.org/index.php/Command_Line_Elliptic_Curve_Operations
108 /// [`Nid`]: ../nid/index.html
110 /// Reference to [`EcGroup`]
112 /// [`EcGroup`]: struct.EcGroup.html
113 pub struct EcGroupRef
;
117 /// Returns the group of a standard named curve.
119 /// OpenSSL documentation at [`EC_GROUP_new`].
121 /// [`EC_GROUP_new`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_GROUP_new.html
122 pub fn from_curve_name(nid
: Nid
) -> Result
<EcGroup
, ErrorStack
> {
125 cvt_p(ffi
::EC_GROUP_new_by_curve_name(nid
.as_raw())).map(EcGroup
)
131 /// Places the components of a curve over a prime field in the provided `BigNum`s.
132 /// The components make up the formula `y^2 mod p = x^3 + ax + b mod p`.
134 /// OpenSSL documentation available at [`EC_GROUP_get_curve_GFp`]
136 /// [`EC_GROUP_get_curve_GFp`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_GROUP_get_curve_GFp.html
137 pub fn components_gfp(
142 ctx
: &mut BigNumContextRef
,
143 ) -> Result
<(), ErrorStack
> {
145 cvt(ffi
::EC_GROUP_get_curve_GFp(
156 /// Places the components of a curve over a binary field in the provided `BigNum`s.
157 /// The components make up the formula `y^2 + xy = x^3 + ax^2 + b`.
159 /// In this form `p` relates to the irreducible polynomial. Each bit represents
160 /// a term in the polynomial. It will be set to 3 `1`s or 5 `1`s depending on
161 /// using a trinomial or pentanomial.
163 /// OpenSSL documentation at [`EC_GROUP_get_curve_GF2m`].
165 /// [`EC_GROUP_get_curve_GF2m`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_GROUP_get_curve_GF2m.html
166 #[cfg(not(osslconf = "OPENSSL_NO_EC2M"))]
167 pub fn components_gf2m(
172 ctx
: &mut BigNumContextRef
,
173 ) -> Result
<(), ErrorStack
> {
175 cvt(ffi
::EC_GROUP_get_curve_GF2m(
186 /// Places the cofactor of the group in the provided `BigNum`.
188 /// OpenSSL documentation at [`EC_GROUP_get_cofactor`]
190 /// [`EC_GROUP_get_cofactor`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_GROUP_get_cofactor.html
193 cofactor
: &mut BigNumRef
,
194 ctx
: &mut BigNumContextRef
,
195 ) -> Result
<(), ErrorStack
> {
197 cvt(ffi
::EC_GROUP_get_cofactor(
206 /// Returns the degree of the curve.
208 /// OpenSSL documentation at [`EC_GROUP_get_degree`]
210 /// [`EC_GROUP_get_degree`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_GROUP_get_degree.html
211 pub fn degree(&self) -> u32 {
212 unsafe { ffi::EC_GROUP_get_degree(self.as_ptr()) as u32 }
215 /// Returns the number of bits in the group order.
217 /// OpenSSL documentation at [`EC_GROUP_order_bits`]
219 /// [`EC_GROUP_order_bits`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_GROUP_order_bits.html
221 pub fn order_bits(&self) -> u32 {
222 unsafe { ffi::EC_GROUP_order_bits(self.as_ptr()) as u32 }
225 /// Returns the generator for the given curve as a [`EcPoint`].
227 /// OpenSSL documentation at [`EC_GROUP_get0_generator`]
229 /// [`EC_GROUP_get0_generator`]: https://www.openssl.org/docs/man1.1.0/man3/EC_GROUP_get0_generator.html
230 pub fn generator(&self) -> &EcPointRef
{
232 let ptr
= ffi
::EC_GROUP_get0_generator(self.as_ptr());
233 EcPointRef
::from_const_ptr(ptr
)
237 /// Places the order of the curve in the provided `BigNum`.
239 /// OpenSSL documentation at [`EC_GROUP_get_order`]
241 /// [`EC_GROUP_get_order`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_GROUP_get_order.html
244 order
: &mut BigNumRef
,
245 ctx
: &mut BigNumContextRef
,
246 ) -> Result
<(), ErrorStack
> {
248 cvt(ffi
::EC_GROUP_get_order(
257 /// Sets the flag determining if the group corresponds to a named curve or must be explicitly
260 /// This defaults to `EXPLICIT_CURVE` in OpenSSL 1.0.1 and 1.0.2, but `NAMED_CURVE` in OpenSSL
262 pub fn set_asn1_flag(&mut self, flag
: Asn1Flag
) {
264 ffi
::EC_GROUP_set_asn1_flag(self.as_ptr(), flag
.0);
268 /// Returns the name of the curve, if a name is associated.
270 /// OpenSSL documentation at [`EC_GROUP_get_curve_name`]
272 /// [`EC_GROUP_get_curve_name`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_GROUP_get_curve_name.html
273 pub fn curve_name(&self) -> Option
<Nid
> {
274 let nid
= unsafe { ffi::EC_GROUP_get_curve_name(self.as_ptr()) }
;
276 Some(Nid
::from_raw(nid
))
283 foreign_type_and_impl_send_sync
! {
284 type CType
= ffi
::EC_POINT
;
285 fn drop
= ffi
::EC_POINT_free
;
287 /// Represents a point on the curve
289 /// OpenSSL documentation at [`EC_POINT_new`]
291 /// [`EC_POINT_new`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_POINT_new.html
293 /// Reference to [`EcPoint`]
295 /// [`EcPoint`]: struct.EcPoint.html
296 pub struct EcPointRef
;
300 /// Computes `a + b`, storing the result in `self`.
302 /// OpenSSL documentation at [`EC_POINT_add`]
304 /// [`EC_POINT_add`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_POINT_add.html
310 ctx
: &mut BigNumContextRef
,
311 ) -> Result
<(), ErrorStack
> {
313 cvt(ffi
::EC_POINT_add(
324 /// Computes `q * m`, storing the result in `self`.
326 /// OpenSSL documentation at [`EC_POINT_mul`]
328 /// [`EC_POINT_mul`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_POINT_mul.html
334 // FIXME should be &mut
335 ctx
: &BigNumContextRef
,
336 ) -> Result
<(), ErrorStack
> {
338 cvt(ffi
::EC_POINT_mul(
350 /// Computes `generator * n`, storing the result in `self`.
351 pub fn mul_generator(
355 // FIXME should be &mut
356 ctx
: &BigNumContextRef
,
357 ) -> Result
<(), ErrorStack
> {
359 cvt(ffi
::EC_POINT_mul(
371 /// Computes `generator * n + q * m`, storing the result in `self`.
378 ctx
: &mut BigNumContextRef
,
379 ) -> Result
<(), ErrorStack
> {
381 cvt(ffi
::EC_POINT_mul(
395 /// OpenSSL documentation at [`EC_POINT_invert`]
397 /// [`EC_POINT_invert`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_POINT_invert.html
398 pub fn invert(&mut self, group
: &EcGroupRef
, ctx
: &BigNumContextRef
) -> Result
<(), ErrorStack
> {
400 cvt(ffi
::EC_POINT_invert(
409 /// Serializes the point to a binary representation.
411 /// OpenSSL documentation at [`EC_POINT_point2oct`]
413 /// [`EC_POINT_point2oct`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_POINT_point2oct.html
417 form
: PointConversionForm
,
418 ctx
: &mut BigNumContextRef
,
419 ) -> Result
<Vec
<u8>, ErrorStack
> {
421 let len
= ffi
::EC_POINT_point2oct(
430 return Err(ErrorStack
::get());
432 let mut buf
= vec
![0; len
];
433 let len
= ffi
::EC_POINT_point2oct(
442 Err(ErrorStack
::get())
449 /// Creates a new point on the specified curve with the same value.
451 /// OpenSSL documentation at [`EC_POINT_dup`]
453 /// [`EC_POINT_dup`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_POINT_dup.html
454 pub fn to_owned(&self, group
: &EcGroupRef
) -> Result
<EcPoint
, ErrorStack
> {
455 unsafe { cvt_p(ffi::EC_POINT_dup(self.as_ptr(), group.as_ptr())).map(EcPoint) }
458 /// Determines if this point is equal to another.
460 /// OpenSSL doucmentation at [`EC_POINT_cmp`]
462 /// [`EC_POINT_cmp`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_POINT_cmp.html
467 ctx
: &mut BigNumContextRef
,
468 ) -> Result
<bool
, ErrorStack
> {
470 let res
= cvt_n(ffi
::EC_POINT_cmp(
480 /// Place affine coordinates of a curve over a prime field in the provided
481 /// `x` and `y` `BigNum`s
483 /// OpenSSL documentation at [`EC_POINT_get_affine_coordinates`]
485 /// [`EC_POINT_get_affine_coordinates`]: https://www.openssl.org/docs/man1.1.1/man3/EC_POINT_get_affine_coordinates.html
487 pub fn affine_coordinates(
492 ctx
: &mut BigNumContextRef
,
493 ) -> Result
<(), ErrorStack
> {
495 cvt(ffi
::EC_POINT_get_affine_coordinates(
506 /// Place affine coordinates of a curve over a prime field in the provided
507 /// `x` and `y` `BigNum`s
509 /// OpenSSL documentation at [`EC_POINT_get_affine_coordinates_GFp`]
511 /// [`EC_POINT_get_affine_coordinates_GFp`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_POINT_get_affine_coordinates_GFp.html
512 pub fn affine_coordinates_gfp(
517 ctx
: &mut BigNumContextRef
,
518 ) -> Result
<(), ErrorStack
> {
520 cvt(ffi
::EC_POINT_get_affine_coordinates_GFp(
531 /// Place affine coordinates of a curve over a binary field in the provided
532 /// `x` and `y` `BigNum`s
534 /// OpenSSL documentation at [`EC_POINT_get_affine_coordinates_GF2m`]
536 /// [`EC_POINT_get_affine_coordinates_GF2m`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_POINT_get_affine_coordinates_GF2m.html
537 #[cfg(not(osslconf = "OPENSSL_NO_EC2M"))]
538 pub fn affine_coordinates_gf2m(
543 ctx
: &mut BigNumContextRef
,
544 ) -> Result
<(), ErrorStack
> {
546 cvt(ffi
::EC_POINT_get_affine_coordinates_GF2m(
557 /// Checks if point is infinity
559 /// OpenSSL documentation at [`EC_POINT_is_at_infinity`]
561 /// [`EC_POINT_is_at_infinity`]: https://www.openssl.org/docs/man1.1.0/man3/EC_POINT_is_at_infinity.html
562 pub fn is_infinity(&self, group
: &EcGroupRef
) -> bool
{
564 let res
= ffi
::EC_POINT_is_at_infinity(group
.as_ptr(), self.as_ptr());
569 /// Checks if point is on a given curve
571 /// OpenSSL documentation at [`EC_POINT_is_on_curve`]
573 /// [`EC_POINT_is_on_curve`]: https://www.openssl.org/docs/man1.1.0/man3/EC_POINT_is_on_curve.html
577 ctx
: &mut BigNumContextRef
,
578 ) -> Result
<bool
, ErrorStack
> {
580 let res
= cvt_n(ffi
::EC_POINT_is_on_curve(
591 /// Creates a new point on the specified curve.
593 /// OpenSSL documentation at [`EC_POINT_new`]
595 /// [`EC_POINT_new`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_POINT_new.html
596 pub fn new(group
: &EcGroupRef
) -> Result
<EcPoint
, ErrorStack
> {
597 unsafe { cvt_p(ffi::EC_POINT_new(group.as_ptr())).map(EcPoint) }
600 /// Creates point from a binary representation
602 /// OpenSSL documentation at [`EC_POINT_oct2point`]
604 /// [`EC_POINT_oct2point`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_POINT_oct2point.html
608 ctx
: &mut BigNumContextRef
,
609 ) -> Result
<EcPoint
, ErrorStack
> {
610 let point
= EcPoint
::new(group
)?
;
612 cvt(ffi
::EC_POINT_oct2point(
624 generic_foreign_type_and_impl_send_sync
! {
625 type CType
= ffi
::EC_KEY
;
626 fn drop
= ffi
::EC_KEY_free
;
628 /// Public and optional Private key on the given curve
630 /// OpenSSL documentation at [`EC_KEY_new`]
632 /// [`EC_KEY_new`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_KEY_new.html
635 /// Reference to [`EcKey`]
637 /// [`EcKey`]: struct.EcKey.html
638 pub struct EcKeyRef
<T
>;
645 private_key_to_pem
! {
646 /// Serializes the private key to a PEM-encoded ECPrivateKey structure.
648 /// The output will have a header of `-----BEGIN EC PRIVATE KEY-----`.
650 /// This corresponds to [`PEM_write_bio_ECPrivateKey`].
652 /// [`PEM_write_bio_ECPrivateKey`]: https://www.openssl.org/docs/man1.1.0/crypto/PEM_write_bio_ECPrivateKey.html
654 /// Serializes the private key to a PEM-encoded encrypted ECPrivateKey structure.
656 /// The output will have a header of `-----BEGIN EC PRIVATE KEY-----`.
658 /// This corresponds to [`PEM_write_bio_ECPrivateKey`].
660 /// [`PEM_write_bio_ECPrivateKey`]: https://www.openssl.org/docs/man1.1.0/crypto/PEM_write_bio_ECPrivateKey.html
661 private_key_to_pem_passphrase
,
662 ffi
::PEM_write_bio_ECPrivateKey
666 /// Serializes the private key into a DER-encoded ECPrivateKey structure.
668 /// This corresponds to [`i2d_ECPrivateKey`].
670 /// [`i2d_ECPrivateKey`]: https://www.openssl.org/docs/man1.0.2/crypto/d2i_ECPrivate_key.html
672 ffi
::i2d_ECPrivateKey
675 /// Return [`EcPoint`] associated with the private key
677 /// OpenSSL documentation at [`EC_KEY_get0_private_key`]
679 /// [`EC_KEY_get0_private_key`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_KEY_get0_private_key.html
680 pub fn private_key(&self) -> &BigNumRef
{
682 let ptr
= ffi
::EC_KEY_get0_private_key(self.as_ptr());
683 BigNumRef
::from_const_ptr(ptr
)
692 /// Returns the public key.
694 /// OpenSSL documentation at [`EC_KEY_get0_public_key`]
696 /// [`EC_KEY_get0_public_key`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_KEY_get0_public_key.html
697 pub fn public_key(&self) -> &EcPointRef
{
699 let ptr
= ffi
::EC_KEY_get0_public_key(self.as_ptr());
700 EcPointRef
::from_const_ptr(ptr
)
705 /// Serialies the public key into a PEM-encoded SubjectPublicKeyInfo structure.
707 /// The output will have a header of `-----BEGIN PUBLIC KEY-----`.
709 /// This corresponds to [`PEM_write_bio_EC_PUBKEY`].
711 /// [`PEM_write_bio_EC_PUBKEY`]: https://www.openssl.org/docs/man1.1.0/crypto/PEM_write_bio_EC_PUBKEY.html
713 ffi
::PEM_write_bio_EC_PUBKEY
717 /// Serializes the public key into a DER-encoded SubjectPublicKeyInfo structure.
719 /// This corresponds to [`i2d_EC_PUBKEY`].
721 /// [`i2d_EC_PUBKEY`]: https://www.openssl.org/docs/man1.1.0/crypto/i2d_EC_PUBKEY.html
731 /// Return [`EcGroup`] of the `EcKey`
733 /// OpenSSL documentation at [`EC_KEY_get0_group`]
735 /// [`EC_KEY_get0_group`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_KEY_get0_group.html
736 pub fn group(&self) -> &EcGroupRef
{
738 let ptr
= ffi
::EC_KEY_get0_group(self.as_ptr());
739 EcGroupRef
::from_const_ptr(ptr
)
743 /// Checks the key for validity.
745 /// OpenSSL documenation at [`EC_KEY_check_key`]
747 /// [`EC_KEY_check_key`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_KEY_check_key.html
748 pub fn check_key(&self) -> Result
<(), ErrorStack
> {
749 unsafe { cvt(ffi::EC_KEY_check_key(self.as_ptr())).map(|_| ()) }
753 impl<T
> ToOwned
for EcKeyRef
<T
> {
754 type Owned
= EcKey
<T
>;
756 fn to_owned(&self) -> EcKey
<T
> {
758 let r
= ffi
::EC_KEY_up_ref(self.as_ptr());
760 EcKey
::from_ptr(self.as_ptr())
766 /// Constructs an `EcKey` corresponding to a known curve.
768 /// It will not have an associated public or private key. This kind of key is primarily useful
769 /// to be provided to the `set_tmp_ecdh` methods on `Ssl` and `SslContextBuilder`.
771 /// OpenSSL documenation at [`EC_KEY_new_by_curve_name`]
773 /// [`EC_KEY_new_by_curve_name`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_KEY_new_by_curve_name.html
774 pub fn from_curve_name(nid
: Nid
) -> Result
<EcKey
<Params
>, ErrorStack
> {
777 cvt_p(ffi
::EC_KEY_new_by_curve_name(nid
.as_raw())).map(|p
| EcKey
::from_ptr(p
))
781 /// Constructs an `EcKey` corresponding to a curve.
783 /// This corresponds to [`EC_KEY_set_group`].
785 /// [`EC_KEY_set_group`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_KEY_new.html
786 pub fn from_group(group
: &EcGroupRef
) -> Result
<EcKey
<Params
>, ErrorStack
> {
788 cvt_p(ffi
::EC_KEY_new())
789 .map(|p
| EcKey
::from_ptr(p
))
791 cvt(ffi
::EC_KEY_set_group(key
.as_ptr(), group
.as_ptr())).map(|_
| key
)
798 /// Constructs an `EcKey` from the specified group with the associated `EcPoint`, public_key.
800 /// This will only have the associated public_key.
805 /// use openssl::bn::BigNumContext;
806 /// use openssl::ec::*;
807 /// use openssl::nid::Nid;
808 /// use openssl::pkey::PKey;
810 /// // get bytes from somewhere, i.e. this will not produce a valid key
811 /// let public_key: Vec<u8> = vec![];
813 /// // create an EcKey from the binary form of a EcPoint
814 /// let group = EcGroup::from_curve_name(Nid::SECP256K1).unwrap();
815 /// let mut ctx = BigNumContext::new().unwrap();
816 /// let point = EcPoint::from_bytes(&group, &public_key, &mut ctx).unwrap();
817 /// let key = EcKey::from_public_key(&group, &point);
819 pub fn from_public_key(
821 public_key
: &EcPointRef
,
822 ) -> Result
<EcKey
<Public
>, ErrorStack
> {
824 cvt_p(ffi
::EC_KEY_new())
825 .map(|p
| EcKey
::from_ptr(p
))
827 cvt(ffi
::EC_KEY_set_group(key
.as_ptr(), group
.as_ptr())).map(|_
| key
)
830 cvt(ffi
::EC_KEY_set_public_key(
839 /// Constructs a public key from its affine coordinates.
840 pub fn from_public_key_affine_coordinates(
844 ) -> Result
<EcKey
<Public
>, ErrorStack
> {
846 cvt_p(ffi
::EC_KEY_new())
847 .map(|p
| EcKey
::from_ptr(p
))
849 cvt(ffi
::EC_KEY_set_group(key
.as_ptr(), group
.as_ptr())).map(|_
| key
)
852 cvt(ffi
::EC_KEY_set_public_key_affine_coordinates(
863 /// Decodes a PEM-encoded SubjectPublicKeyInfo structure containing a EC key.
865 /// The input should have a header of `-----BEGIN PUBLIC KEY-----`.
867 /// This corresponds to [`PEM_read_bio_EC_PUBKEY`].
869 /// [`PEM_read_bio_EC_PUBKEY`]: https://www.openssl.org/docs/man1.1.0/crypto/PEM_read_bio_EC_PUBKEY.html
872 ffi
::PEM_read_bio_EC_PUBKEY
876 /// Decodes a DER-encoded SubjectPublicKeyInfo structure containing a EC key.
878 /// This corresponds to [`d2i_EC_PUBKEY`].
880 /// [`d2i_EC_PUBKEY`]: https://www.openssl.org/docs/man1.1.0/crypto/d2i_EC_PUBKEY.html
887 impl EcKey
<Private
> {
888 /// Generates a new public/private key pair on the specified curve.
889 pub fn generate(group
: &EcGroupRef
) -> Result
<EcKey
<Private
>, ErrorStack
> {
891 cvt_p(ffi
::EC_KEY_new())
892 .map(|p
| EcKey
::from_ptr(p
))
894 cvt(ffi
::EC_KEY_set_group(key
.as_ptr(), group
.as_ptr())).map(|_
| key
)
896 .and_then(|key
| cvt(ffi
::EC_KEY_generate_key(key
.as_ptr())).map(|_
| key
))
900 /// Constructs an public/private key pair given a curve, a private key and a public key point.
901 pub fn from_private_components(
903 private_number
: &BigNumRef
,
904 public_key
: &EcPointRef
,
905 ) -> Result
<EcKey
<Private
>, ErrorStack
> {
907 cvt_p(ffi
::EC_KEY_new())
908 .map(|p
| EcKey
::from_ptr(p
))
910 cvt(ffi
::EC_KEY_set_group(key
.as_ptr(), group
.as_ptr())).map(|_
| key
)
913 cvt(ffi
::EC_KEY_set_private_key(
915 private_number
.as_ptr(),
920 cvt(ffi
::EC_KEY_set_public_key(
929 private_key_from_pem
! {
930 /// Deserializes a private key from a PEM-encoded ECPrivateKey structure.
932 /// The input should have a header of `-----BEGIN EC PRIVATE KEY-----`.
934 /// This corresponds to `PEM_read_bio_ECPrivateKey`.
935 private_key_from_pem
,
937 /// Deserializes a private key from a PEM-encoded encrypted ECPrivateKey structure.
939 /// The input should have a header of `-----BEGIN EC PRIVATE KEY-----`.
941 /// This corresponds to `PEM_read_bio_ECPrivateKey`.
942 private_key_from_pem_passphrase
,
944 /// Deserializes a private key from a PEM-encoded encrypted ECPrivateKey structure.
946 /// The callback should fill the password into the provided buffer and return its length.
948 /// The input should have a header of `-----BEGIN EC PRIVATE KEY-----`.
950 /// This corresponds to `PEM_read_bio_ECPrivateKey`.
951 private_key_from_pem_callback
,
953 ffi
::PEM_read_bio_ECPrivateKey
957 /// Decodes a DER-encoded elliptic curve private key structure.
959 /// This corresponds to [`d2i_ECPrivateKey`].
961 /// [`d2i_ECPrivateKey`]: https://www.openssl.org/docs/man1.0.2/crypto/d2i_ECPrivate_key.html
962 private_key_from_der
,
964 ffi
::d2i_ECPrivateKey
968 impl<T
> Clone
for EcKey
<T
> {
969 fn clone(&self) -> EcKey
<T
> {
974 impl<T
> fmt
::Debug
for EcKey
<T
> {
975 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
985 use crate::bn
::{BigNum, BigNumContext}
;
989 fn key_new_by_curve_name() {
990 EcKey
::from_curve_name(Nid
::X9_62_PRIME256V1
).unwrap();
995 let group
= EcGroup
::from_curve_name(Nid
::X9_62_PRIME256V1
).unwrap();
996 EcKey
::generate(&group
).unwrap();
1001 let group
= EcGroup
::from_curve_name(Nid
::X9_62_PRIME256V1
).unwrap();
1002 let mut ctx
= BigNumContext
::new().unwrap();
1003 let mut cofactor
= BigNum
::new().unwrap();
1004 group
.cofactor(&mut cofactor
, &mut ctx
).unwrap();
1005 let one
= BigNum
::from_u32(1).unwrap();
1006 assert_eq
!(cofactor
, one
);
1010 #[allow(clippy::redundant_clone)]
1012 let group
= EcGroup
::from_curve_name(Nid
::X9_62_PRIME256V1
).unwrap();
1013 let key
= EcKey
::generate(&group
).unwrap();
1019 let group
= EcGroup
::from_curve_name(Nid
::X9_62_PRIME256V1
).unwrap();
1020 EcPoint
::new(&group
).unwrap();
1025 let group
= EcGroup
::from_curve_name(Nid
::X9_62_PRIME256V1
).unwrap();
1026 let key
= EcKey
::generate(&group
).unwrap();
1027 let point
= key
.public_key();
1028 let mut ctx
= BigNumContext
::new().unwrap();
1030 .to_bytes(&group
, PointConversionForm
::COMPRESSED
, &mut ctx
)
1032 let point2
= EcPoint
::from_bytes(&group
, &bytes
, &mut ctx
).unwrap();
1033 assert
!(point
.eq(&group
, &point2
, &mut ctx
).unwrap());
1038 let group
= EcGroup
::from_curve_name(Nid
::X9_62_PRIME256V1
).unwrap();
1039 let key
= EcKey
::generate(&group
).unwrap();
1040 let point
= key
.public_key();
1041 let owned
= point
.to_owned(&group
).unwrap();
1042 let mut ctx
= BigNumContext
::new().unwrap();
1043 assert
!(owned
.eq(&group
, point
, &mut ctx
).unwrap());
1047 fn mul_generator() {
1048 let group
= EcGroup
::from_curve_name(Nid
::X9_62_PRIME256V1
).unwrap();
1049 let key
= EcKey
::generate(&group
).unwrap();
1050 let mut ctx
= BigNumContext
::new().unwrap();
1051 let mut public_key
= EcPoint
::new(&group
).unwrap();
1053 .mul_generator(&group
, key
.private_key(), &ctx
)
1055 assert
!(public_key
.eq(&group
, key
.public_key(), &mut ctx
).unwrap());
1060 let group
= EcGroup
::from_curve_name(Nid
::X9_62_PRIME256V1
).unwrap();
1061 let gen
= group
.generator();
1062 let one
= BigNum
::from_u32(1).unwrap();
1063 let mut ctx
= BigNumContext
::new().unwrap();
1064 let mut ecp
= EcPoint
::new(&group
).unwrap();
1065 ecp
.mul_generator(&group
, &one
, &ctx
).unwrap();
1066 assert
!(ecp
.eq(&group
, gen
, &mut ctx
).unwrap());
1070 fn key_from_public_key() {
1071 let group
= EcGroup
::from_curve_name(Nid
::X9_62_PRIME256V1
).unwrap();
1072 let key
= EcKey
::generate(&group
).unwrap();
1073 let mut ctx
= BigNumContext
::new().unwrap();
1076 .to_bytes(&group
, PointConversionForm
::COMPRESSED
, &mut ctx
)
1080 let public_key
= EcPoint
::from_bytes(&group
, &bytes
, &mut ctx
).unwrap();
1081 let ec_key
= EcKey
::from_public_key(&group
, &public_key
).unwrap();
1082 assert
!(ec_key
.check_key().is_ok());
1086 fn key_from_private_components() {
1087 let group
= EcGroup
::from_curve_name(Nid
::X9_62_PRIME256V1
).unwrap();
1088 let key
= EcKey
::generate(&group
).unwrap();
1091 EcKey
::from_private_components(&group
, key
.private_key(), key
.public_key()).unwrap();
1092 dup_key
.check_key().unwrap();
1094 assert
!(key
.private_key() == dup_key
.private_key());
1098 fn key_from_affine_coordinates() {
1099 let group
= EcGroup
::from_curve_name(Nid
::X9_62_PRIME256V1
).unwrap();
1100 let x
= Vec
::from_hex("30a0424cd21c2944838a2d75c92b37e76ea20d9f00893a3b4eee8a3c0aafec3e")
1102 let y
= Vec
::from_hex("e04b65e92456d9888b52b379bdfbd51ee869ef1f0fc65b6659695b6cce081723")
1105 let xbn
= BigNum
::from_slice(&x
).unwrap();
1106 let ybn
= BigNum
::from_slice(&y
).unwrap();
1108 let ec_key
= EcKey
::from_public_key_affine_coordinates(&group
, &xbn
, &ybn
).unwrap();
1109 assert
!(ec_key
.check_key().is_ok());
1114 fn get_affine_coordinates() {
1115 let group
= EcGroup
::from_curve_name(Nid
::X9_62_PRIME256V1
).unwrap();
1116 let x
= Vec
::from_hex("30a0424cd21c2944838a2d75c92b37e76ea20d9f00893a3b4eee8a3c0aafec3e")
1118 let y
= Vec
::from_hex("e04b65e92456d9888b52b379bdfbd51ee869ef1f0fc65b6659695b6cce081723")
1121 let xbn
= BigNum
::from_slice(&x
).unwrap();
1122 let ybn
= BigNum
::from_slice(&y
).unwrap();
1124 let ec_key
= EcKey
::from_public_key_affine_coordinates(&group
, &xbn
, &ybn
).unwrap();
1126 let mut xbn2
= BigNum
::new().unwrap();
1127 let mut ybn2
= BigNum
::new().unwrap();
1128 let mut ctx
= BigNumContext
::new().unwrap();
1129 let ec_key_pk
= ec_key
.public_key();
1131 .affine_coordinates(&group
, &mut xbn2
, &mut ybn2
, &mut ctx
)
1133 assert_eq
!(xbn2
, xbn
);
1134 assert_eq
!(ybn2
, ybn
);
1138 fn get_affine_coordinates_gfp() {
1139 let group
= EcGroup
::from_curve_name(Nid
::X9_62_PRIME256V1
).unwrap();
1140 let x
= Vec
::from_hex("30a0424cd21c2944838a2d75c92b37e76ea20d9f00893a3b4eee8a3c0aafec3e")
1142 let y
= Vec
::from_hex("e04b65e92456d9888b52b379bdfbd51ee869ef1f0fc65b6659695b6cce081723")
1145 let xbn
= BigNum
::from_slice(&x
).unwrap();
1146 let ybn
= BigNum
::from_slice(&y
).unwrap();
1148 let ec_key
= EcKey
::from_public_key_affine_coordinates(&group
, &xbn
, &ybn
).unwrap();
1150 let mut xbn2
= BigNum
::new().unwrap();
1151 let mut ybn2
= BigNum
::new().unwrap();
1152 let mut ctx
= BigNumContext
::new().unwrap();
1153 let ec_key_pk
= ec_key
.public_key();
1155 .affine_coordinates_gfp(&group
, &mut xbn2
, &mut ybn2
, &mut ctx
)
1157 assert_eq
!(xbn2
, xbn
);
1158 assert_eq
!(ybn2
, ybn
);
1163 let group
= EcGroup
::from_curve_name(Nid
::X9_62_PRIME256V1
).unwrap();
1164 let mut ctx
= BigNumContext
::new().unwrap();
1165 let g
= group
.generator();
1166 assert_eq
!(g
.is_infinity(&group
), false);
1168 let mut order
= BigNum
::new().unwrap();
1169 group
.order(&mut order
, &mut ctx
).unwrap();
1170 let mut inf
= EcPoint
::new(&group
).unwrap();
1171 inf
.mul_generator(&group
, &order
, &ctx
).unwrap();
1172 assert_eq
!(inf
.is_infinity(&group
), true);
1177 let group
= EcGroup
::from_curve_name(Nid
::X9_62_PRIME256V1
).unwrap();
1178 let mut ctx
= BigNumContext
::new().unwrap();
1179 let g
= group
.generator();
1180 assert_eq
!(g
.is_on_curve(&group
, &mut ctx
).unwrap(), true);
1182 let group2
= EcGroup
::from_curve_name(Nid
::X9_62_PRIME239V3
).unwrap();
1183 assert_eq
!(g
.is_on_curve(&group2
, &mut ctx
).unwrap(), false);