1 //! Hold the implementation of [`Signer`] and [`Decryptor`] for [`KeyPair`].
2 //!
3 //! [`Signer`]: ../../asymmetric/trait.Signer.html
4 //! [`Decryptor`]: ../../asymmetric/trait.Decryptor.html
5 //! [`KeyPair`]: ../../asymmetric/struct.KeyPair.html
6 
7 use nettle::{curve25519, ecc, ecdh, ecdsa, ed25519, dsa, rsa, random::Yarrow};
8 
9 use crate::{Error, Result};
10 
11 use crate::packet::{self, key, Key};
12 use crate::crypto::asymmetric::{KeyPair, Decryptor, Signer};
13 use crate::crypto::mpi::{self, MPI, PublicKey};
14 use crate::crypto::SessionKey;
15 use crate::types::{Curve, HashAlgorithm};
16 
17 impl Signer for KeyPair {
public(&self) -> &Key<key::PublicParts, key::UnspecifiedRole>18     fn public(&self) -> &Key<key::PublicParts, key::UnspecifiedRole> {
19         KeyPair::public(self)
20     }
21 
sign(&mut self, hash_algo: HashAlgorithm, digest: &[u8]) -> Result<mpi::Signature>22     fn sign(&mut self, hash_algo: HashAlgorithm, digest: &[u8])
23             -> Result<mpi::Signature>
24     {
25         use crate::PublicKeyAlgorithm::*;
26 
27         let mut rng = Yarrow::default();
28 
29         self.secret().map(|secret| {
30             #[allow(deprecated)]
31             match (self.public().pk_algo(), self.public().mpis(), secret)
32         {
33             (RSASign,
34              &PublicKey::RSA { ref e, ref n },
35              &mpi::SecretKeyMaterial::RSA { ref p, ref q, ref d, .. }) |
36             (RSAEncryptSign,
37              &PublicKey::RSA { ref e, ref n },
38              &mpi::SecretKeyMaterial::RSA { ref p, ref q, ref d, .. }) => {
39                 let public = rsa::PublicKey::new(n.value(), e.value())?;
40                 let secret = rsa::PrivateKey::new(d.value(), p.value(),
41                                                   q.value(), Option::None)?;
42 
43                 // The signature has the length of the modulus.
44                 let mut sig = vec![0u8; n.value().len()];
45 
46                 // As described in [Section 5.2.2 and 5.2.3 of RFC 4880],
47                 // to verify the signature, we need to encode the
48                 // signature data in a PKCS1-v1.5 packet.
49                 //
50                 //   [Section 5.2.2 and 5.2.3 of RFC 4880]:
51                 //   https://tools.ietf.org/html/rfc4880#section-5.2.2
52                 rsa::sign_digest_pkcs1(&public, &secret, digest,
53                                        hash_algo.oid()?,
54                                        &mut rng, &mut sig)?;
55 
56                 Ok(mpi::Signature::RSA {
57                     s: MPI::new(&sig),
58                 })
59             },
60 
61             (DSA,
62              &PublicKey::DSA { ref p, ref q, ref g, .. },
63              &mpi::SecretKeyMaterial::DSA { ref x }) => {
64                 let params = dsa::Params::new(p.value(), q.value(), g.value());
65                 let secret = dsa::PrivateKey::new(x.value());
66 
67                 let sig = dsa::sign(&params, &secret, digest, &mut rng)?;
68 
69                 Ok(mpi::Signature::DSA {
70                     r: MPI::new(&sig.r()),
71                     s: MPI::new(&sig.s()),
72                 })
73             },
74 
75             (EdDSA,
76              &PublicKey::EdDSA { ref curve, ref q },
77              &mpi::SecretKeyMaterial::EdDSA { ref scalar }) => match curve {
78                 Curve::Ed25519 => {
79                     let public = q.decode_point(&Curve::Ed25519)?.0;
80 
81                     let mut sig = vec![0; ed25519::ED25519_SIGNATURE_SIZE];
82 
83                     // Nettle expects the private key to be exactly
84                     // ED25519_KEY_SIZE bytes long but OpenPGP allows leading
85                     // zeros to be stripped.
86                     // Padding has to be unconditional; otherwise we have a
87                     // secret-dependent branch.
88                     let missing = ed25519::ED25519_KEY_SIZE
89                         .saturating_sub(scalar.value().len());
90                     let mut sec = [0u8; ed25519::ED25519_KEY_SIZE];
91                     sec[missing..].copy_from_slice(scalar.value());
92 
93                     let res = ed25519::sign(public, &sec[..], digest, &mut sig);
94                     unsafe {
95                         memsec::memzero(sec.as_mut_ptr(),
96                                         ed25519::ED25519_KEY_SIZE);
97                     }
98                     res?;
99 
100                     Ok(mpi::Signature::EdDSA {
101                         r: MPI::new(&sig[..32]),
102                         s: MPI::new(&sig[32..]),
103                     })
104                 },
105                 _ => Err(
106                     Error::UnsupportedEllipticCurve(curve.clone()).into()),
107             },
108 
109             (ECDSA,
110              &PublicKey::ECDSA { ref curve, .. },
111              &mpi::SecretKeyMaterial::ECDSA { ref scalar }) => {
112                 let secret = match curve {
113                     Curve::NistP256 =>
114                         ecc::Scalar::new::<ecc::Secp256r1>(
115                             scalar.value())?,
116                     Curve::NistP384 =>
117                         ecc::Scalar::new::<ecc::Secp384r1>(
118                             scalar.value())?,
119                     Curve::NistP521 =>
120                         ecc::Scalar::new::<ecc::Secp521r1>(
121                             scalar.value())?,
122                     _ =>
123                         return Err(
124                             Error::UnsupportedEllipticCurve(curve.clone())
125                                 .into()),
126                 };
127 
128                 let sig = ecdsa::sign(&secret, digest, &mut rng);
129 
130                 Ok(mpi::Signature::ECDSA {
131                     r: MPI::new(&sig.r()),
132                     s: MPI::new(&sig.s()),
133                 })
134             },
135 
136             (pk_algo, _, _) => Err(Error::InvalidOperation(format!(
137                 "unsupported combination of algorithm {:?}, key {:?}, \
138                  and secret key {:?}",
139                 pk_algo, self.public(), self.secret())).into()),
140         }})
141     }
142 }
143 
144 impl Decryptor for KeyPair {
public(&self) -> &Key<key::PublicParts, key::UnspecifiedRole>145     fn public(&self) -> &Key<key::PublicParts, key::UnspecifiedRole> {
146         KeyPair::public(self)
147     }
148 
decrypt(&mut self, ciphertext: &mpi::Ciphertext, plaintext_len: Option<usize>) -> Result<SessionKey>149     fn decrypt(&mut self, ciphertext: &mpi::Ciphertext,
150                plaintext_len: Option<usize>)
151                -> Result<SessionKey>
152     {
153         use crate::PublicKeyAlgorithm::*;
154 
155         self.secret().map(
156             |secret| Ok(match (self.public().mpis(), secret, ciphertext)
157         {
158             (PublicKey::RSA{ ref e, ref n },
159              mpi::SecretKeyMaterial::RSA{ ref p, ref q, ref d, .. },
160              mpi::Ciphertext::RSA{ ref c }) => {
161                 // Workaround for #440:  Make sure c is of the same
162                 // length as n.
163                 // XXX: Remove once we depend on nettle > 7.0.0.
164                 let c_ = if c.value().len() < n.value().len() {
165                     let mut c_ = vec![0; n.value().len() - c.value().len()];
166                     c_.extend_from_slice(c.value());
167                     Some(c_)
168                 }  else {
169                     // If it is bigger, then the packet is likely
170                     // corrupted, tough luck then.
171                     None
172                 };
173                 let c = if let Some(c_) = c_.as_ref() {
174                     &c_[..]
175                 } else {
176                     c.value()
177                 };
178                 // End of workaround.
179 
180                 let public = rsa::PublicKey::new(n.value(), e.value())?;
181                 let secret = rsa::PrivateKey::new(d.value(), p.value(),
182                                                   q.value(), Option::None)?;
183                 let mut rand = Yarrow::default();
184                 if let Some(l) = plaintext_len {
185                     let mut plaintext: SessionKey = vec![0; l].into();
186                     rsa::decrypt_pkcs1(&public, &secret, &mut rand,
187                                        c, plaintext.as_mut())?;
188                     plaintext
189                 } else {
190                     rsa::decrypt_pkcs1_insecure(&public, &secret,
191                                                 &mut rand, c)?
192                     .into()
193                 }
194             }
195 
196             (PublicKey::ElGamal{ .. },
197              mpi::SecretKeyMaterial::ElGamal{ .. },
198              mpi::Ciphertext::ElGamal{ .. }) =>
199                 return Err(
200                     Error::UnsupportedPublicKeyAlgorithm(ElGamalEncrypt).into()),
201 
202             (PublicKey::ECDH{ .. },
203              mpi::SecretKeyMaterial::ECDH { .. },
204              mpi::Ciphertext::ECDH { .. }) =>
205                 crate::crypto::ecdh::decrypt(self.public(), secret, ciphertext)?,
206 
207             (public, secret, ciphertext) =>
208                 return Err(Error::InvalidOperation(format!(
209                     "unsupported combination of key pair {:?}/{:?} \
210                      and ciphertext {:?}",
211                     public, secret, ciphertext)).into()),
212         }))
213     }
214 }
215 
216 
217 impl<P: key::KeyParts, R: key::KeyRole> Key<P, R> {
218     /// Encrypts the given data with this key.
encrypt(&self, data: &SessionKey) -> Result<mpi::Ciphertext>219     pub fn encrypt(&self, data: &SessionKey) -> Result<mpi::Ciphertext> {
220         use crate::PublicKeyAlgorithm::*;
221 
222         #[allow(deprecated)]
223         match self.pk_algo() {
224             RSAEncryptSign | RSAEncrypt => {
225                 // Extract the public recipient.
226                 match self.mpis() {
227                     mpi::PublicKey::RSA { e, n } => {
228                         // The ciphertext has the length of the modulus.
229                         let ciphertext_len = n.value().len();
230                         if data.len() + 11 > ciphertext_len {
231                             return Err(Error::InvalidArgument(
232                                 "Plaintext data too large".into()).into());
233                         }
234 
235                         let mut esk = vec![0u8; ciphertext_len];
236                         let mut rng = Yarrow::default();
237                         let pk = rsa::PublicKey::new(n.value(), e.value())?;
238                         rsa::encrypt_pkcs1(&pk, &mut rng, data,
239                                            &mut esk)?;
240                         Ok(mpi::Ciphertext::RSA {
241                             c: MPI::new(&esk),
242                         })
243                     },
244                     pk => {
245                         Err(Error::MalformedPacket(
246                             format!(
247                                 "Key: Expected RSA public key, got {:?}",
248                                 pk)).into())
249                     },
250                 }
251             },
252             ECDH => crate::crypto::ecdh::encrypt(self.parts_as_public(),
253                                                  data),
254             algo => Err(Error::UnsupportedPublicKeyAlgorithm(algo).into()),
255         }
256     }
257 
258     /// Verifies the given signature.
verify(&self, sig: &packet::Signature, digest: &[u8]) -> Result<()>259     pub fn verify(&self, sig: &packet::Signature, digest: &[u8]) -> Result<()>
260     {
261         use crate::PublicKeyAlgorithm::*;
262         use crate::crypto::mpi::Signature;
263 
264         #[allow(deprecated)]
265         let ok = match (sig.pk_algo(), self.mpis(), sig.mpis()) {
266             (RSASign,        PublicKey::RSA { e, n }, Signature::RSA { s }) |
267             (RSAEncryptSign, PublicKey::RSA { e, n }, Signature::RSA { s }) => {
268                 let key = rsa::PublicKey::new(n.value(), e.value())?;
269 
270                 // As described in [Section 5.2.2 and 5.2.3 of RFC 4880],
271                 // to verify the signature, we need to encode the
272                 // signature data in a PKCS1-v1.5 packet.
273                 //
274                 //   [Section 5.2.2 and 5.2.3 of RFC 4880]:
275                 //   https://tools.ietf.org/html/rfc4880#section-5.2.2
276                 rsa::verify_digest_pkcs1(&key, digest, sig.hash_algo().oid()?,
277                                          s.value())?
278             },
279             (DSA, PublicKey::DSA{ y, p, q, g }, Signature::DSA { s, r }) => {
280                 let key = dsa::PublicKey::new(y.value());
281                 let params = dsa::Params::new(p.value(), q.value(), g.value());
282                 let signature = dsa::Signature::new(r.value(), s.value());
283 
284                 dsa::verify(&params, &key, digest, &signature)
285             },
286             (EdDSA, PublicKey::EdDSA{ curve, q }, Signature::EdDSA { r, s }) =>
287               match curve {
288                 Curve::Ed25519 => {
289                     if q.value().get(0).map(|&b| b != 0x40).unwrap_or(true) {
290                         return Err(Error::MalformedPacket(
291                             "Invalid point encoding".into()).into());
292                     }
293 
294                     // OpenPGP encodes R and S separately, but our
295                     // cryptographic library expects them to be
296                     // concatenated.
297                     let mut signature =
298                         Vec::with_capacity(ed25519::ED25519_SIGNATURE_SIZE);
299 
300                     // We need to zero-pad them at the front, because
301                     // the MPI encoding drops leading zero bytes.
302                     let half = ed25519::ED25519_SIGNATURE_SIZE / 2;
303                     if r.value().len() < half {
304                         for _ in 0..half - r.value().len() {
305                             signature.push(0);
306                         }
307                     }
308                     signature.extend_from_slice(r.value());
309                     if s.value().len() < half {
310                         for _ in 0..half - s.value().len() {
311                             signature.push(0);
312                         }
313                     }
314                     signature.extend_from_slice(s.value());
315 
316                     // Let's see if we got it right.
317                     if signature.len() != ed25519::ED25519_SIGNATURE_SIZE {
318                         return Err(Error::MalformedPacket(
319                             format!(
320                                 "Invalid signature size: {}, r: {:?}, s: {:?}",
321                                 signature.len(), r.value(), s.value())).into());
322                     }
323 
324                     ed25519::verify(&q.value()[1..], digest, &signature)?
325                 },
326                 _ => return
327                     Err(Error::UnsupportedEllipticCurve(curve.clone()).into()),
328             },
329             (ECDSA, PublicKey::ECDSA{ curve, q }, Signature::ECDSA { s, r }) =>
330             {
331                 let (x, y) = q.decode_point(curve)?;
332                 let key = match curve {
333                     Curve::NistP256 => ecc::Point::new::<ecc::Secp256r1>(x, y)?,
334                     Curve::NistP384 => ecc::Point::new::<ecc::Secp384r1>(x, y)?,
335                     Curve::NistP521 => ecc::Point::new::<ecc::Secp521r1>(x, y)?,
336                     _ => return Err(
337                         Error::UnsupportedEllipticCurve(curve.clone()).into()),
338                 };
339 
340                 let signature = dsa::Signature::new(r.value(), s.value());
341                 ecdsa::verify(&key, digest, &signature)
342             },
343             _ => return Err(Error::MalformedPacket(format!(
344                 "unsupported combination of algorithm {}, key {} and \
345                  signature {:?}.",
346                 sig.pk_algo(), self.pk_algo(), sig.mpis())).into()),
347         };
348 
349         if ok {
350             Ok(())
351         } else {
352             Err(Error::ManipulatedMessage.into())
353         }
354     }
355 }
356 
357 use std::time::SystemTime;
358 use crate::crypto::mem::Protected;
359 use crate::packet::key::{Key4, SecretParts};
360 use crate::types::{PublicKeyAlgorithm, SymmetricAlgorithm};
361 
362 impl<R> Key4<SecretParts, R>
363     where R: key::KeyRole,
364 {
365 
366     /// Creates a new OpenPGP secret key packet for an existing X25519 key.
367     ///
368     /// The ECDH key will use hash algorithm `hash` and symmetric
369     /// algorithm `sym`.  If one or both are `None` secure defaults
370     /// will be used.  The key will have it's creation date set to
371     /// `ctime` or the current time if `None` is given.
import_secret_cv25519<H, S, T>(private_key: &[u8], hash: H, sym: S, ctime: T) -> Result<Self> where H: Into<Option<HashAlgorithm>>, S: Into<Option<SymmetricAlgorithm>>, T: Into<Option<SystemTime>>372     pub fn import_secret_cv25519<H, S, T>(private_key: &[u8],
373                                           hash: H, sym: S, ctime: T)
374         -> Result<Self> where H: Into<Option<HashAlgorithm>>,
375                               S: Into<Option<SymmetricAlgorithm>>,
376                               T: Into<Option<SystemTime>>
377     {
378         let mut public_key = [0; curve25519::CURVE25519_SIZE];
379         curve25519::mul_g(&mut public_key, private_key).unwrap();
380 
381         let mut private_key = Vec::from(private_key);
382         private_key.reverse();
383 
384         Self::with_secret(
385             ctime.into().unwrap_or_else(SystemTime::now),
386             PublicKeyAlgorithm::ECDH,
387             mpi::PublicKey::ECDH {
388                 curve: Curve::Cv25519,
389                 hash: hash.into().unwrap_or(HashAlgorithm::SHA512),
390                 sym: sym.into().unwrap_or(SymmetricAlgorithm::AES256),
391                 q: MPI::new_compressed_point(&public_key),
392             },
393             mpi::SecretKeyMaterial::ECDH {
394                 scalar: private_key.into(),
395             }.into())
396     }
397 
398     /// Creates a new OpenPGP secret key packet for an existing Ed25519 key.
399     ///
400     /// The ECDH key will use hash algorithm `hash` and symmetric
401     /// algorithm `sym`.  If one or both are `None` secure defaults
402     /// will be used.  The key will have it's creation date set to
403     /// `ctime` or the current time if `None` is given.
import_secret_ed25519<T>(private_key: &[u8], ctime: T) -> Result<Self> where T: Into<Option<SystemTime>>404     pub fn import_secret_ed25519<T>(private_key: &[u8], ctime: T)
405         -> Result<Self> where T: Into<Option<SystemTime>>
406     {
407         let mut public_key = [0; ed25519::ED25519_KEY_SIZE];
408         ed25519::public_key(&mut public_key, private_key).unwrap();
409 
410         Self::with_secret(
411             ctime.into().unwrap_or_else(SystemTime::now),
412             PublicKeyAlgorithm::EdDSA,
413             mpi::PublicKey::EdDSA {
414                 curve: Curve::Ed25519,
415                 q: MPI::new_compressed_point(&public_key),
416             },
417             mpi::SecretKeyMaterial::EdDSA {
418                 scalar: mpi::MPI::new(private_key).into(),
419             }.into())
420     }
421 
422     /// Creates a new OpenPGP public key packet for an existing RSA key.
423     ///
424     /// The RSA key will use public exponent `e` and modulo `n`. The key will
425     /// have it's creation date set to `ctime` or the current time if `None`
426     /// is given.
import_secret_rsa<T>(d: &[u8], p: &[u8], q: &[u8], ctime: T) -> Result<Self> where T: Into<Option<SystemTime>>427     pub fn import_secret_rsa<T>(d: &[u8], p: &[u8], q: &[u8], ctime: T)
428         -> Result<Self> where T: Into<Option<SystemTime>>
429     {
430         let sec = rsa::PrivateKey::new(d, p, q, None)?;
431         let key = sec.public_key()?;
432         let (a, b, c) = sec.as_rfc4880();
433 
434         Self::with_secret(
435             ctime.into().unwrap_or_else(SystemTime::now),
436             PublicKeyAlgorithm::RSAEncryptSign,
437             mpi::PublicKey::RSA {
438                 e: mpi::MPI::new(&key.e()[..]),
439                 n: mpi::MPI::new(&key.n()[..]),
440             },
441             mpi::SecretKeyMaterial::RSA {
442                 d: mpi::MPI::new(d).into(),
443                 p: mpi::MPI::new(&a[..]).into(),
444                 q: mpi::MPI::new(&b[..]).into(),
445                 u: mpi::MPI::new(&c[..]).into(),
446             }.into())
447     }
448 
449     /// Generates a new RSA key with a public modulos of size `bits`.
generate_rsa(bits: usize) -> Result<Self>450     pub fn generate_rsa(bits: usize) -> Result<Self> {
451         let mut rng = Yarrow::default();
452 
453         let (public, private) = rsa::generate_keypair(&mut rng, bits as u32)?;
454         let (p, q, u) = private.as_rfc4880();
455         let public_mpis = PublicKey::RSA {
456             e: MPI::new(&*public.e()).into(),
457             n: MPI::new(&*public.n()).into(),
458         };
459         let private_mpis = mpi::SecretKeyMaterial::RSA {
460             d: MPI::new(&*private.d()).into(),
461             p: MPI::new(&*p).into(),
462             q: MPI::new(&*q).into(),
463             u: MPI::new(&*u).into(),
464         };
465 
466         Self::with_secret(
467             SystemTime::now(),
468             PublicKeyAlgorithm::RSAEncryptSign,
469             public_mpis,
470             private_mpis.into())
471     }
472 
473     /// Generates a new ECC key over `curve`.
474     ///
475     /// If `for_signing` is false a ECDH key, if it's true either a
476     /// EdDSA or ECDSA key is generated.  Giving `for_signing == true` and
477     /// `curve == Cv25519` will produce an error. Likewise
478     /// `for_signing == false` and `curve == Ed25519` will produce an error.
generate_ecc(for_signing: bool, curve: Curve) -> Result<Self>479     pub fn generate_ecc(for_signing: bool, curve: Curve) -> Result<Self> {
480         use crate::PublicKeyAlgorithm::*;
481 
482         let mut rng = Yarrow::default();
483 
484         let (mpis, secret, pk_algo) = match (curve.clone(), for_signing) {
485             (Curve::Ed25519, true) => {
486                 let mut public = [0; ed25519::ED25519_KEY_SIZE];
487                 let private: Protected =
488                     ed25519::private_key(&mut rng).into();
489                 ed25519::public_key(&mut public, &private)?;
490 
491                 let public_mpis = PublicKey::EdDSA {
492                     curve: Curve::Ed25519,
493                     q: MPI::new_compressed_point(&public),
494                 };
495                 let private_mpis = mpi::SecretKeyMaterial::EdDSA {
496                     scalar: private.into(),
497                 };
498                 let sec = private_mpis.into();
499 
500                 (public_mpis, sec, EdDSA)
501             }
502 
503             (Curve::Cv25519, false) => {
504                 let mut public = [0; curve25519::CURVE25519_SIZE];
505                 let mut private: Protected =
506                     curve25519::private_key(&mut rng).into();
507                 curve25519::mul_g(&mut public, &private)?;
508 
509                 // Reverse the scalar.  See
510                 // https://lists.gnupg.org/pipermail/gnupg-devel/2018-February/033437.html.
511                 private.reverse();
512 
513                 let public_mpis = PublicKey::ECDH {
514                     curve: Curve::Cv25519,
515                     q: MPI::new_compressed_point(&public),
516                     hash: HashAlgorithm::SHA256,
517                     sym: SymmetricAlgorithm::AES256,
518                 };
519                 let private_mpis = mpi::SecretKeyMaterial::ECDH {
520                     scalar: private.into(),
521                 };
522                 let sec = private_mpis.into();
523 
524                 (public_mpis, sec, ECDH)
525             }
526 
527             (Curve::NistP256, true)  | (Curve::NistP384, true)
528             | (Curve::NistP521, true) => {
529                 let (public, private, field_sz) = match curve {
530                     Curve::NistP256 => {
531                         let (pu, sec) =
532                             ecdsa::generate_keypair::<ecc::Secp256r1, _>(&mut rng)?;
533                         (pu, sec, 256)
534                     }
535                     Curve::NistP384 => {
536                         let (pu, sec) =
537                             ecdsa::generate_keypair::<ecc::Secp384r1, _>(&mut rng)?;
538                         (pu, sec, 384)
539                     }
540                     Curve::NistP521 => {
541                         let (pu, sec) =
542                             ecdsa::generate_keypair::<ecc::Secp521r1, _>(&mut rng)?;
543                         (pu, sec, 521)
544                     }
545                     _ => unreachable!(),
546                 };
547                 let (pub_x, pub_y) = public.as_bytes();
548                 let public_mpis =  mpi::PublicKey::ECDSA{
549                     curve,
550                     q: MPI::new_point(&pub_x, &pub_y, field_sz),
551                 };
552                 let private_mpis = mpi::SecretKeyMaterial::ECDSA{
553                     scalar: MPI::new(&private.as_bytes()).into(),
554                 };
555                 let sec = private_mpis.into();
556 
557                 (public_mpis, sec, ECDSA)
558             }
559 
560             (Curve::NistP256, false)  | (Curve::NistP384, false)
561             | (Curve::NistP521, false) => {
562                     let (private, hash, field_sz) = match curve {
563                         Curve::NistP256 => {
564                             let pv =
565                                 ecc::Scalar::new_random::<ecc::Secp256r1, _>(&mut rng);
566 
567                             (pv, HashAlgorithm::SHA256, 256)
568                         }
569                         Curve::NistP384 => {
570                             let pv =
571                                 ecc::Scalar::new_random::<ecc::Secp384r1, _>(&mut rng);
572 
573                             (pv, HashAlgorithm::SHA384, 384)
574                         }
575                         Curve::NistP521 => {
576                             let pv =
577                                 ecc::Scalar::new_random::<ecc::Secp521r1, _>(&mut rng);
578 
579                             (pv, HashAlgorithm::SHA512, 521)
580                         }
581                         _ => unreachable!(),
582                     };
583                     let public = ecdh::point_mul_g(&private);
584                     let (pub_x, pub_y) = public.as_bytes();
585                     let public_mpis = mpi::PublicKey::ECDH{
586                         curve,
587                         q: MPI::new_point(&pub_x, &pub_y, field_sz),
588                         hash,
589                         sym: SymmetricAlgorithm::AES256,
590                     };
591                     let private_mpis = mpi::SecretKeyMaterial::ECDH{
592                         scalar: MPI::new(&private.as_bytes()).into(),
593                     };
594                     let sec = private_mpis.into();
595 
596                     (public_mpis, sec, ECDH)
597                 }
598 
599             (cv, _) => {
600                 return Err(Error::UnsupportedEllipticCurve(cv).into());
601             }
602         };
603 
604         Self::with_secret(
605             SystemTime::now(),
606             pk_algo,
607             mpis,
608             secret)
609     }
610 }
611