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(¶ms, &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(¶ms, &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