1use std::time::Duration;
2
3use chrono::SubsecRound;
4use derive_builder::Builder;
5use rand::{CryptoRng, Rng};
6use smallvec::SmallVec;
7
8use crate::composed::{KeyDetails, SecretKey, SecretSubkey};
9use crate::crypto::aead::AeadAlgorithm;
10use crate::crypto::ecc_curve::ECCCurve;
11use crate::crypto::hash::HashAlgorithm;
12use crate::crypto::public_key::PublicKeyAlgorithm;
13use crate::crypto::sym::SymmetricKeyAlgorithm;
14use crate::crypto::{dsa, ecdh, ecdsa, eddsa, rsa, x25519};
15use crate::errors::Result;
16use crate::packet::{self, KeyFlags, UserAttribute, UserId};
17use crate::types::{self, CompressionAlgorithm, PublicParams, RevocationKey, S2kParams};
18
19#[derive(Debug, PartialEq, Eq, Builder)]
20#[builder(build_fn(validate = "Self::validate"))]
21pub struct SecretKeyParams {
22 key_type: KeyType,
23
24 #[builder(default)]
26 can_sign: bool,
27 #[builder(default)]
28 can_certify: bool,
29 #[builder(default)]
30 can_encrypt: bool,
31
32 #[builder(default)]
35 preferred_symmetric_algorithms: SmallVec<[SymmetricKeyAlgorithm; 8]>,
36 #[builder(default)]
38 preferred_hash_algorithms: SmallVec<[HashAlgorithm; 8]>,
39 #[builder(default)]
41 preferred_compression_algorithms: SmallVec<[CompressionAlgorithm; 8]>,
42 #[builder(default)]
43 preferred_aead_algorithms: SmallVec<[(SymmetricKeyAlgorithm, AeadAlgorithm); 4]>,
44 #[builder(default)]
45 revocation_key: Option<RevocationKey>,
46
47 #[builder]
48 primary_user_id: String,
49
50 #[builder(default)]
51 user_ids: Vec<String>,
52 #[builder(default)]
53 user_attributes: Vec<UserAttribute>,
54 #[builder(default)]
55 passphrase: Option<String>,
56 #[builder(default)]
57 s2k: Option<S2kParams>,
58 #[builder(default = "chrono::Utc::now().trunc_subsecs(0)")]
59 created_at: chrono::DateTime<chrono::Utc>,
60 #[builder(default)]
61 packet_version: types::Version,
62 #[builder(default)]
63 version: types::KeyVersion,
64 #[builder(default)]
65 expiration: Option<Duration>,
66
67 #[builder(default)]
68 subkeys: Vec<SubkeyParams>,
69}
70
71#[derive(Debug, Clone, PartialEq, Eq, Builder)]
72pub struct SubkeyParams {
73 key_type: KeyType,
74
75 #[builder(default)]
76 can_sign: bool,
77 #[builder(default)]
78 can_certify: bool,
79 #[builder(default)]
80 can_encrypt: bool,
81 #[builder(default)]
82 can_authenticate: bool,
83
84 #[builder(default)]
85 user_ids: Vec<UserId>,
86 #[builder(default)]
87 user_attributes: Vec<UserAttribute>,
88 #[builder(default)]
89 passphrase: Option<String>,
90 #[builder(default)]
91 s2k: Option<S2kParams>,
92 #[builder(default = "chrono::Utc::now().trunc_subsecs(0)")]
93 created_at: chrono::DateTime<chrono::Utc>,
94 #[builder(default)]
95 packet_version: types::Version,
96 #[builder(default)]
97 version: types::KeyVersion,
98 #[builder(default)]
99 expiration: Option<Duration>,
100}
101
102impl SecretKeyParamsBuilder {
103 fn validate(&self) -> std::result::Result<(), String> {
104 match &self.key_type {
105 Some(KeyType::Rsa(size)) => {
106 if *size < 2048 {
107 return Err("Keys with less than 2048bits are considered insecure".into());
108 }
109 }
110 Some(KeyType::EdDSALegacy) => {
111 if let Some(can_encrypt) = self.can_encrypt {
112 if can_encrypt {
113 return Err("EdDSA can only be used for signing keys".into());
114 }
115 }
116 }
117 Some(KeyType::ECDSA(curve)) => {
118 if let Some(can_encrypt) = self.can_encrypt {
119 if can_encrypt {
120 return Err("ECDSA can only be used for signing keys".into());
121 }
122 };
123 match curve {
124 ECCCurve::P256 | ECCCurve::P384 | ECCCurve::P521 | ECCCurve::Secp256k1 => {}
125 _ => return Err(format!("Curve {} is not supported for ECDSA", curve.name())),
126 }
127 }
128 Some(KeyType::ECDH(_)) => {
129 if let Some(can_sign) = self.can_sign {
130 if can_sign {
131 return Err("ECDH can only be used for encryption keys".into());
132 }
133 }
134 }
135 Some(KeyType::Dsa(_)) => {
136 if let Some(can_encrypt) = self.can_encrypt {
137 if can_encrypt {
138 return Err("DSA can only be used for signing keys".into());
139 }
140 }
141 }
142 _ => {}
143 }
144
145 Ok(())
146 }
147
148 pub fn user_id<VALUE: Into<String>>(&mut self, value: VALUE) -> &mut Self {
149 if let Some(ref mut user_ids) = self.user_ids {
150 user_ids.push(value.into());
151 } else {
152 self.user_ids = Some(vec![value.into()]);
153 }
154 self
155 }
156
157 pub fn subkey<VALUE: Into<SubkeyParams>>(&mut self, value: VALUE) -> &mut Self {
158 if let Some(ref mut subkeys) = self.subkeys {
159 subkeys.push(value.into());
160 } else {
161 self.subkeys = Some(vec![value.into()]);
162 }
163 self
164 }
165}
166
167impl SecretKeyParams {
168 pub fn generate<R: Rng + CryptoRng>(self, mut rng: R) -> Result<SecretKey> {
169 let passphrase = self.passphrase;
170 let s2k = self
171 .s2k
172 .unwrap_or_else(|| S2kParams::new_default(&mut rng, self.version));
173 let (public_params, secret_params) = self.key_type.generate(&mut rng)?;
174 let mut primary_key = packet::SecretKey::new(
175 packet::PublicKey::new(
176 self.packet_version,
177 self.version,
178 self.key_type.to_alg(),
179 self.created_at,
180 self.expiration.map(|v| v.as_secs() as u16),
181 public_params,
182 )?,
183 secret_params,
184 );
185 if let Some(passphrase) = passphrase {
186 primary_key.set_password_with_s2k(|| passphrase, s2k)?;
187 }
188
189 let mut keyflags = KeyFlags::default();
190 keyflags.set_certify(self.can_certify);
191 keyflags.set_encrypt_comms(self.can_encrypt);
192 keyflags.set_encrypt_storage(self.can_encrypt);
193 keyflags.set_sign(self.can_sign);
194
195 Ok(SecretKey::new(
196 primary_key,
197 KeyDetails::new(
198 UserId::from_str(Default::default(), &self.primary_user_id),
199 self.user_ids
200 .iter()
201 .map(|m| UserId::from_str(Default::default(), m))
202 .collect(),
203 self.user_attributes,
204 keyflags,
205 self.preferred_symmetric_algorithms,
206 self.preferred_hash_algorithms,
207 self.preferred_compression_algorithms,
208 self.preferred_aead_algorithms,
209 self.revocation_key,
210 ),
211 Default::default(),
212 self.subkeys
213 .into_iter()
214 .map(|subkey| {
215 let passphrase = subkey.passphrase;
216 let s2k = subkey
217 .s2k
218 .unwrap_or_else(|| S2kParams::new_default(&mut rng, subkey.version));
219 let (public_params, secret_params) = subkey.key_type.generate(&mut rng)?;
220 let mut keyflags = KeyFlags::default();
221 keyflags.set_certify(subkey.can_certify);
222 keyflags.set_encrypt_comms(subkey.can_encrypt);
223 keyflags.set_encrypt_storage(subkey.can_encrypt);
224 keyflags.set_sign(subkey.can_sign);
225 keyflags.set_authentication(subkey.can_authenticate);
226
227 let mut sub = packet::SecretSubkey::new(
228 packet::PublicSubkey::new(
229 subkey.packet_version,
230 subkey.version,
231 subkey.key_type.to_alg(),
232 subkey.created_at,
233 subkey.expiration.map(|v| v.as_secs() as u16),
234 public_params,
235 )?,
236 secret_params,
237 );
238
239 if let Some(passphrase) = passphrase {
240 sub.set_password_with_s2k(|| passphrase, s2k)?;
241 }
242
243 Ok(SecretSubkey::new(sub, keyflags))
244 })
245 .collect::<Result<Vec<_>>>()?,
246 ))
247 }
248}
249
250#[derive(Clone, Debug, PartialEq, Eq)]
251pub enum KeyType {
252 Rsa(u32),
254 ECDH(ECCCurve),
256 EdDSALegacy,
258 ECDSA(ECCCurve),
260 Dsa(DsaKeySize),
262 Ed25519,
264 X25519,
266 X448,
268}
269
270#[derive(Clone, Debug, Copy, PartialEq, Eq)]
271#[repr(u32)]
272pub enum DsaKeySize {
273 B1024 = 1024,
275 B2048 = 2048,
277 B3072 = 3072,
279}
280
281impl From<DsaKeySize> for dsa::KeySize {
282 fn from(value: DsaKeySize) -> Self {
283 match value {
284 #[allow(deprecated)]
285 DsaKeySize::B1024 => dsa::KeySize::DSA_1024_160,
286 DsaKeySize::B2048 => dsa::KeySize::DSA_2048_256,
287 DsaKeySize::B3072 => dsa::KeySize::DSA_3072_256,
288 }
289 }
290}
291
292impl KeyType {
293 pub fn to_alg(&self) -> PublicKeyAlgorithm {
294 match self {
295 KeyType::Rsa(_) => PublicKeyAlgorithm::RSA,
296 KeyType::ECDH(_) => PublicKeyAlgorithm::ECDH,
297 KeyType::EdDSALegacy => PublicKeyAlgorithm::EdDSALegacy,
298 KeyType::ECDSA(_) => PublicKeyAlgorithm::ECDSA,
299 KeyType::Dsa(_) => PublicKeyAlgorithm::DSA,
300 KeyType::Ed25519 => PublicKeyAlgorithm::Ed25519,
301 KeyType::X25519 => PublicKeyAlgorithm::X25519,
302 KeyType::X448 => PublicKeyAlgorithm::X448,
303 }
304 }
305
306 pub fn generate<R: Rng + CryptoRng>(
307 &self,
308 rng: R,
309 ) -> Result<(PublicParams, types::SecretParams)> {
310 let (pub_params, plain) = match self {
311 KeyType::Rsa(bit_size) => rsa::generate_key(rng, *bit_size as usize)?,
312 KeyType::ECDH(curve) => ecdh::generate_key(rng, curve)?,
313 KeyType::EdDSALegacy => eddsa::generate_key(rng, eddsa::Mode::EdDSALegacy),
314 KeyType::ECDSA(curve) => ecdsa::generate_key(rng, curve)?,
315 KeyType::Dsa(key_size) => dsa::generate_key(rng, (*key_size).into())?,
316 KeyType::Ed25519 => eddsa::generate_key(rng, eddsa::Mode::Ed25519),
317 KeyType::X25519 => x25519::generate_key(rng),
318 KeyType::X448 => crate::crypto::x448::generate_key(rng),
319 };
320
321 Ok((pub_params, types::SecretParams::Plain(plain)))
322 }
323}
324
325#[cfg(test)]
326mod tests {
327 #![allow(clippy::unwrap_used)]
328
329 use rand::SeedableRng;
330 use rand_chacha::ChaCha8Rng;
331 use smallvec::smallvec;
332
333 use super::*;
334 use crate::composed::{Deserializable, SignedPublicKey, SignedSecretKey};
335 use crate::types::{KeyVersion, SecretKeyTrait};
336
337 #[test]
338 #[ignore] fn test_key_gen_rsa_2048() {
340 let _ = pretty_env_logger::try_init();
341 let mut rng = ChaCha8Rng::seed_from_u64(0);
342
343 for key_version in [KeyVersion::V4, KeyVersion::V6] {
344 println!("key version {:?}", key_version);
345
346 for i in 0..50 {
347 println!("round {i}");
348 gen_rsa_2048(&mut rng, key_version);
349 }
350 }
351 }
352
353 fn gen_rsa_2048<R: Rng + CryptoRng>(mut rng: R, version: KeyVersion) {
354 let mut key_params = SecretKeyParamsBuilder::default();
355 key_params
356 .version(version)
357 .key_type(KeyType::Rsa(2048))
358 .can_certify(true)
359 .can_sign(true)
360 .primary_user_id("Me <me@mail.com>".into())
361 .preferred_symmetric_algorithms(smallvec![
362 SymmetricKeyAlgorithm::MKV128256,
363 SymmetricKeyAlgorithm::MKV128192,
364 SymmetricKeyAlgorithm::MKV128128,
365 SymmetricKeyAlgorithm::AES256,
366 SymmetricKeyAlgorithm::AES192,
367 SymmetricKeyAlgorithm::AES128,
368 ])
369 .preferred_hash_algorithms(smallvec![
370 HashAlgorithm::SHA2_256,
371 HashAlgorithm::SHA2_384,
372 HashAlgorithm::SHA2_512,
373 HashAlgorithm::SHA2_224,
374 HashAlgorithm::SHA1,
375 ])
376 .preferred_compression_algorithms(smallvec![
377 CompressionAlgorithm::ZLIB,
378 CompressionAlgorithm::ZIP,
379 ]);
380
381 let key_params_enc = key_params
382 .clone()
383 .passphrase(Some("hello".into()))
384 .subkey(
385 SubkeyParamsBuilder::default()
386 .version(version)
387 .key_type(KeyType::Rsa(2048))
388 .passphrase(Some("hello".into()))
389 .can_encrypt(true)
390 .build()
391 .unwrap(),
392 )
393 .build()
394 .unwrap();
395 let key_enc = key_params_enc
396 .generate(&mut rng)
397 .expect("failed to generate secret key, encrypted");
398
399 let key_params_plain = key_params
400 .passphrase(None)
401 .subkey(
402 SubkeyParamsBuilder::default()
403 .version(version)
404 .key_type(KeyType::Rsa(2048))
405 .can_encrypt(true)
406 .build()
407 .unwrap(),
408 )
409 .build()
410 .unwrap();
411 let key_plain = key_params_plain
412 .generate(&mut rng)
413 .expect("failed to generate secret key");
414
415 let signed_key_enc = key_enc
416 .sign(&mut rng, || "hello".into())
417 .expect("failed to sign key");
418 let signed_key_plain = key_plain
419 .sign(&mut rng, || "".into())
420 .expect("failed to sign key");
421
422 let armor_enc = signed_key_enc
423 .to_armored_string(None.into())
424 .expect("failed to serialize key");
425 let armor_plain = signed_key_plain
426 .to_armored_string(None.into())
427 .expect("failed to serialize key");
428
429 let (signed_key2_enc, _headers) =
433 SignedSecretKey::from_string(&armor_enc).expect("failed to parse key (enc)");
434 signed_key2_enc.verify().expect("invalid key (enc)");
435
436 let (signed_key2_plain, _headers) =
437 SignedSecretKey::from_string(&armor_plain).expect("failed to parse key (plain)");
438 signed_key2_plain.verify().expect("invalid key (plain)");
439
440 signed_key2_enc
441 .unlock(|| "hello".into(), |_| Ok(()))
442 .expect("failed to unlock parsed key (enc)");
443 signed_key2_plain
444 .unlock(|| "".into(), |_| Ok(()))
445 .expect("failed to unlock parsed key (plain)");
446
447 assert_eq!(signed_key_plain, signed_key2_plain);
448
449 let public_key = signed_key_plain.public_key();
450
451 let public_signed_key = public_key
452 .sign(&mut rng, &signed_key_plain, || "".into())
453 .expect("failed to sign public key");
454
455 public_signed_key.verify().expect("invalid public key");
456
457 let armor = public_signed_key
458 .to_armored_string(None.into())
459 .expect("failed to serialize public key");
460
461 let (signed_key2, _headers) =
464 SignedPublicKey::from_string(&armor).expect("failed to parse public key");
465 signed_key2.verify().expect("invalid public key");
466 }
467
468 #[ignore]
469 #[test]
470 fn key_gen_25519_legacy_long() {
471 let mut rng = ChaCha8Rng::seed_from_u64(0);
472 for i in 0..10_000 {
473 println!("round {i}");
474 gen_25519_legacy(&mut rng);
475 }
476 }
477
478 #[test]
479 fn key_gen_25519_legacy_short() {
480 let mut rng = ChaCha8Rng::seed_from_u64(0);
481 for _ in 0..100 {
482 gen_25519_legacy(&mut rng);
483 }
484 }
485
486 fn gen_25519_legacy<R: Rng + CryptoRng>(mut rng: R) {
487 let _ = pretty_env_logger::try_init();
490
491 let key_params = SecretKeyParamsBuilder::default()
492 .key_type(KeyType::EdDSALegacy)
493 .can_certify(true)
494 .can_sign(true)
495 .primary_user_id("Me-X <me-25519-legacy@mail.com>".into())
496 .passphrase(None)
497 .preferred_symmetric_algorithms(smallvec![
498 SymmetricKeyAlgorithm::MKV128256,
499 SymmetricKeyAlgorithm::MKV128192,
500 SymmetricKeyAlgorithm::MKV128128,
501 SymmetricKeyAlgorithm::AES256,
502 SymmetricKeyAlgorithm::AES192,
503 SymmetricKeyAlgorithm::AES128,
504 ])
505 .preferred_hash_algorithms(smallvec![
506 HashAlgorithm::SHA2_256,
507 HashAlgorithm::SHA2_384,
508 HashAlgorithm::SHA2_512,
509 HashAlgorithm::SHA2_224,
510 HashAlgorithm::SHA1,
511 ])
512 .preferred_compression_algorithms(smallvec![
513 CompressionAlgorithm::ZLIB,
514 CompressionAlgorithm::ZIP,
515 ])
516 .subkey(
517 SubkeyParamsBuilder::default()
518 .key_type(KeyType::ECDH(ECCCurve::Curve25519))
519 .can_encrypt(true)
520 .passphrase(None)
521 .build()
522 .unwrap(),
523 )
524 .build()
525 .unwrap();
526
527 let key = key_params
528 .generate(&mut rng)
529 .expect("failed to generate secret key");
530
531 let signed_key = key
532 .sign(&mut rng, || "".into())
533 .expect("failed to sign key");
534
535 let armor = signed_key
536 .to_armored_string(None.into())
537 .expect("failed to serialize key");
538
539 let (signed_key2, _headers) =
542 SignedSecretKey::from_string(&armor).expect("failed to parse key");
543 signed_key2.verify().expect("invalid key");
544
545 assert_eq!(signed_key, signed_key2);
546
547 let public_key = signed_key.public_key();
548
549 let public_signed_key = public_key
550 .sign(&mut rng, &signed_key, || "".into())
551 .expect("failed to sign public key");
552
553 public_signed_key.verify().expect("invalid public key");
554
555 let armor = public_signed_key
556 .to_armored_string(None.into())
557 .expect("failed to serialize public key");
558
559 let (signed_key2, _headers) =
562 SignedPublicKey::from_string(&armor).expect("failed to parse public key");
563 signed_key2.verify().expect("invalid public key");
564 }
565
566 #[ignore]
567 #[test]
568 fn key_gen_25519_rfc9580_long() {
569 let mut rng = ChaCha8Rng::seed_from_u64(0);
570
571 for key_version in [KeyVersion::V4, KeyVersion::V6] {
572 println!("key version {:?}", key_version);
573
574 for i in 0..10_000 {
575 println!("round {i}");
576 gen_25519_rfc9580(&mut rng, key_version);
577 }
578 }
579 }
580
581 #[test]
582 fn key_gen_25519_rfc9580_short() {
583 let mut rng = ChaCha8Rng::seed_from_u64(0);
584
585 for key_version in [KeyVersion::V4, KeyVersion::V6] {
586 println!("key version {:?}", key_version);
587
588 for _ in 0..100 {
589 gen_25519_rfc9580(&mut rng, key_version);
590 }
591 }
592 }
593
594 fn gen_25519_rfc9580<R: Rng + CryptoRng>(mut rng: R, version: KeyVersion) {
595 let _ = pretty_env_logger::try_init();
598
599 let key_params = SecretKeyParamsBuilder::default()
600 .version(version)
601 .key_type(KeyType::Ed25519)
602 .can_certify(true)
603 .can_sign(true)
604 .primary_user_id("Me-X <me-25519-rfc9580@mail.com>".into())
605 .passphrase(None)
606 .preferred_symmetric_algorithms(smallvec![
607 SymmetricKeyAlgorithm::MKV128256,
608 SymmetricKeyAlgorithm::MKV128192,
609 SymmetricKeyAlgorithm::MKV128128,
610 SymmetricKeyAlgorithm::AES256,
611 SymmetricKeyAlgorithm::AES192,
612 SymmetricKeyAlgorithm::AES128,
613 ])
614 .preferred_hash_algorithms(smallvec![
615 HashAlgorithm::SHA2_256,
616 HashAlgorithm::SHA2_384,
617 HashAlgorithm::SHA2_512,
618 HashAlgorithm::SHA2_224,
619 HashAlgorithm::SHA1,
620 ])
621 .preferred_compression_algorithms(smallvec![
622 CompressionAlgorithm::ZLIB,
623 CompressionAlgorithm::ZIP,
624 ])
625 .subkey(
626 SubkeyParamsBuilder::default()
627 .version(version)
628 .key_type(KeyType::X25519)
629 .can_encrypt(true)
630 .passphrase(None)
631 .build()
632 .unwrap(),
633 )
634 .build()
635 .unwrap();
636
637 let key = key_params
638 .generate(&mut rng)
639 .expect("failed to generate secret key");
640
641 let signed_key = key
642 .sign(&mut rng, || "".into())
643 .expect("failed to sign key");
644
645 let armor = signed_key
646 .to_armored_string(None.into())
647 .expect("failed to serialize key");
648
649 let (signed_key2, _headers) =
652 SignedSecretKey::from_string(&armor).expect("failed to parse key");
653 signed_key2.verify().expect("invalid key");
654
655 assert_eq!(signed_key, signed_key2);
656
657 let public_key = signed_key.public_key();
658
659 let public_signed_key = public_key
660 .sign(&mut rng, &signed_key, || "".into())
661 .expect("failed to sign public key");
662
663 public_signed_key.verify().expect("invalid public key");
664
665 let armor = public_signed_key
666 .to_armored_string(None.into())
667 .expect("failed to serialize public key");
668
669 let (signed_key2, _headers) =
672 SignedPublicKey::from_string(&armor).expect("failed to parse public key");
673 signed_key2.verify().expect("invalid public key");
674 }
675
676 fn gen_ecdsa_ecdh<R: Rng + CryptoRng>(
677 mut rng: R,
678 ecdsa: ECCCurve,
679 ecdh: ECCCurve,
680 version: KeyVersion,
681 ) {
682 let _ = pretty_env_logger::try_init();
683
684 let key_params = SecretKeyParamsBuilder::default()
685 .version(version)
686 .key_type(KeyType::ECDSA(ecdsa.clone()))
687 .can_certify(true)
688 .can_sign(true)
689 .primary_user_id("Me-X <me-ecdsa@mail.com>".into())
690 .passphrase(None)
691 .preferred_symmetric_algorithms(smallvec![
692 SymmetricKeyAlgorithm::MKV128256,
693 SymmetricKeyAlgorithm::MKV128192,
694 SymmetricKeyAlgorithm::MKV128128,
695 SymmetricKeyAlgorithm::AES256,
696 SymmetricKeyAlgorithm::AES192,
697 SymmetricKeyAlgorithm::AES128,
698 ])
699 .preferred_hash_algorithms(smallvec![
700 HashAlgorithm::SHA2_256,
701 HashAlgorithm::SHA2_384,
702 HashAlgorithm::SHA2_512,
703 HashAlgorithm::SHA2_224,
704 HashAlgorithm::SHA1,
705 ])
706 .preferred_compression_algorithms(smallvec![
707 CompressionAlgorithm::ZLIB,
708 CompressionAlgorithm::ZIP,
709 ])
710 .subkey(
711 SubkeyParamsBuilder::default()
712 .version(version)
713 .key_type(KeyType::ECDH(ecdh.clone()))
714 .can_encrypt(true)
715 .passphrase(None)
716 .build()
717 .unwrap(),
718 )
719 .build()
720 .unwrap();
721
722 let key = key_params
723 .generate(&mut rng)
724 .expect("failed to generate secret key");
725
726 let signed_key = key
727 .sign(&mut rng, || "".into())
728 .expect("failed to sign key");
729
730 let armor = signed_key
731 .to_armored_string(None.into())
732 .expect("failed to serialize key");
733
734 let (signed_key2, _headers) =
741 SignedSecretKey::from_string(&armor).expect("failed to parse key");
742 signed_key2.verify().expect("invalid key");
743
744 assert_eq!(signed_key, signed_key2);
745
746 let public_key = signed_key.public_key();
747
748 let public_signed_key = public_key
749 .sign(&mut rng, &signed_key, || "".into())
750 .expect("failed to sign public key");
751
752 public_signed_key.verify().expect("invalid public key");
753
754 let armor = public_signed_key
755 .to_armored_string(None.into())
756 .expect("failed to serialize public key");
757
758 let (signed_key2, _headers) =
765 SignedPublicKey::from_string(&armor).expect("failed to parse public key");
766 signed_key2.verify().expect("invalid public key");
767 }
768
769 #[test]
770 fn key_gen_ecdsa_p256() {
771 let mut rng = &mut ChaCha8Rng::seed_from_u64(0);
772
773 for key_version in [KeyVersion::V4, KeyVersion::V6] {
774 println!("key version {:?}", key_version);
775
776 for _ in 0..=175 {
777 gen_ecdsa_ecdh(&mut rng, ECCCurve::P256, ECCCurve::P256, key_version);
778 }
779 }
780 }
781
782 #[test]
783 fn key_gen_ecdsa_p384() {
784 let mut rng = &mut ChaCha8Rng::seed_from_u64(0);
785
786 for key_version in [KeyVersion::V4, KeyVersion::V6] {
787 println!("key version {:?}", key_version);
788
789 for _ in 0..100 {
790 gen_ecdsa_ecdh(&mut rng, ECCCurve::P384, ECCCurve::P384, key_version);
791 }
792 }
793 }
794
795 #[test]
796 fn key_gen_ecdsa_p521() {
797 let mut rng = &mut ChaCha8Rng::seed_from_u64(0);
798
799 for key_version in [KeyVersion::V4, KeyVersion::V6] {
800 println!("key version {:?}", key_version);
801
802 for _ in 0..100 {
803 gen_ecdsa_ecdh(&mut rng, ECCCurve::P521, ECCCurve::P521, key_version);
804 }
805 }
806 }
807
808 #[test]
809 fn key_gen_ecdsa_secp256k1() {
810 let mut rng = &mut ChaCha8Rng::seed_from_u64(0);
811
812 for _ in 0..100 {
813 gen_ecdsa_ecdh(
814 &mut rng,
815 ECCCurve::Secp256k1,
816 ECCCurve::Curve25519, KeyVersion::V4, );
819 }
820 }
821
822 fn gen_dsa<R: Rng + CryptoRng>(mut rng: R, key_size: DsaKeySize) {
823 let _ = pretty_env_logger::try_init();
824
825 let key_params = SecretKeyParamsBuilder::default()
826 .key_type(KeyType::Dsa(key_size))
827 .can_certify(true)
828 .can_sign(true)
829 .primary_user_id("Me-X <me-dsa@mail.com>".into())
830 .passphrase(None)
831 .preferred_symmetric_algorithms(smallvec![
832 SymmetricKeyAlgorithm::MKV128256,
833 SymmetricKeyAlgorithm::MKV128192,
834 SymmetricKeyAlgorithm::MKV128128,
835 SymmetricKeyAlgorithm::AES256,
836 SymmetricKeyAlgorithm::AES192,
837 SymmetricKeyAlgorithm::AES128,
838 ])
839 .preferred_hash_algorithms(smallvec![
840 HashAlgorithm::SHA2_256,
841 HashAlgorithm::SHA2_384,
842 HashAlgorithm::SHA2_512,
843 HashAlgorithm::SHA2_224,
844 HashAlgorithm::SHA1,
845 ])
846 .preferred_compression_algorithms(smallvec![
847 CompressionAlgorithm::ZLIB,
848 CompressionAlgorithm::ZIP,
849 ])
850 .subkey(
851 SubkeyParamsBuilder::default()
852 .key_type(KeyType::ECDH(ECCCurve::Curve25519))
853 .can_encrypt(true)
854 .passphrase(None)
855 .build()
856 .unwrap(),
857 )
858 .build()
859 .unwrap();
860
861 let key = key_params
862 .generate(&mut rng)
863 .expect("failed to generate secret key");
864
865 let signed_key = key
866 .sign(&mut rng, || "".into())
867 .expect("failed to sign key");
868
869 let armor = signed_key
870 .to_armored_string(None.into())
871 .expect("failed to serialize key");
872
873 let (signed_key2, _headers) =
876 SignedSecretKey::from_string(&armor).expect("failed to parse key");
877 signed_key2.verify().expect("invalid key");
878
879 assert_eq!(signed_key, signed_key2);
880
881 let public_key = signed_key.public_key();
882
883 let public_signed_key = public_key
884 .sign(&mut rng, &signed_key, || "".into())
885 .expect("failed to sign public key");
886
887 public_signed_key.verify().expect("invalid public key");
888
889 let armor = public_signed_key
890 .to_armored_string(None.into())
891 .expect("failed to serialize public key");
892
893 let (signed_key2, _headers) =
896 SignedPublicKey::from_string(&armor).expect("failed to parse public key");
897 signed_key2.verify().expect("invalid public key");
898 }
899
900 #[test]
902 #[ignore]
903 fn key_gen_dsa() {
904 let mut rng = &mut ChaCha8Rng::seed_from_u64(0);
905 for _ in 0..10 {
906 gen_dsa(&mut rng, DsaKeySize::B1024);
907 gen_dsa(&mut rng, DsaKeySize::B2048);
908 gen_dsa(&mut rng, DsaKeySize::B3072);
909 }
910 }
911}