1use std::fmt;
18use std::cmp::Ordering;
19use std::io::Write;
20use std::borrow::Cow;
21
22#[cfg(test)]
23use quickcheck::{Arbitrary, Gen};
24
25use crate::fmt::hex;
26use crate::types::{
27 Curve,
28 HashAlgorithm,
29 PublicKeyAlgorithm,
30 SymmetricAlgorithm,
31};
32use crate::crypto::hash::{self, Hash};
33use crate::crypto::mem::{secure_cmp, Protected};
34use crate::serialize::Marshal;
35
36use crate::Error;
37use crate::Result;
38
39#[derive(Clone)]
41pub struct MPI {
42 value: Box<[u8]>,
44}
45assert_send_and_sync!(MPI);
46
47impl From<Vec<u8>> for MPI {
48 fn from(v: Vec<u8>) -> Self {
49 Self::new(&v)
56 }
57}
58
59impl From<Box<[u8]>> for MPI {
60 fn from(v: Box<[u8]>) -> Self {
61 Self::new(&v)
68 }
69}
70
71impl MPI {
72 fn trim_leading_zeros(v: &[u8]) -> &[u8] {
74 let offset = v.iter().take_while(|&&o| o == 0).count();
75 &v[offset..]
76 }
77
78 pub fn new(value: &[u8]) -> Self {
82 let value = Self::trim_leading_zeros(value).to_vec().into_boxed_slice();
83
84 MPI {
85 value,
86 }
87 }
88
89 pub fn new_point(x: &[u8], y: &[u8], field_bits: usize) -> Self {
98 Self::new_point_common(x, y, field_bits).into()
99 }
100
101 fn new_point_common(x: &[u8], y: &[u8], field_bits: usize) -> Vec<u8> {
103 let field_sz = if field_bits % 8 > 0 { 1 } else { 0 } + field_bits / 8;
104 let mut val = vec![0x0u8; 1 + 2 * field_sz];
105 let x_missing = field_sz - x.len();
106 let y_missing = field_sz - y.len();
107
108 val[0] = 0x4;
109 val[1 + x_missing..1 + field_sz].copy_from_slice(x);
110 val[1 + field_sz + y_missing..].copy_from_slice(y);
111 val
112 }
113
114 pub fn new_compressed_point(x: &[u8]) -> Self {
124 Self::new_compressed_point_common(x).into()
125 }
126
127 fn new_compressed_point_common(x: &[u8]) -> Vec<u8> {
129 let mut val = vec![0; 1 + x.len()];
130 val[0] = 0x40;
131 val[1..].copy_from_slice(x);
132 val
133 }
134
135 pub fn zero() -> Self {
137 Self::new(&[])
138 }
139
140 pub fn is_zero(&self) -> bool {
142 self.value().is_empty()
143 }
144
145 pub fn bits(&self) -> usize {
149 self.value.len() * 8
150 - self.value.get(0).map(|&b| b.leading_zeros() as usize)
151 .unwrap_or(0)
152 }
153
154 pub fn value(&self) -> &[u8] {
159 &self.value
160 }
161
162 pub fn value_padded(&self, to: usize) -> Result<Cow<'_, [u8]>> {
168 crate::crypto::pad(self.value(), to)
169 }
170
171 pub fn decode_point(&self, curve: &Curve) -> Result<(&[u8], &[u8])> {
188 Self::decode_point_common(self.value(), curve)
189 }
190
191 fn decode_point_common<'a>(value: &'a [u8], curve: &Curve)
193 -> Result<(&'a [u8], &'a [u8])> {
194 const ED25519_KEY_SIZE: usize = 32;
195 const CURVE25519_SIZE: usize = 32;
196 use self::Curve::*;
197 match &curve {
198 Ed25519 | Cv25519 => {
199 assert_eq!(CURVE25519_SIZE, ED25519_KEY_SIZE);
200 if value.len() != 1 + CURVE25519_SIZE {
203 return Err(Error::MalformedMPI(
204 format!("Bad size of Curve25519 key: {} expected: {}",
205 value.len(),
206 1 + CURVE25519_SIZE
207 )
208 ).into());
209 }
210
211 if value.get(0).map(|&b| b != 0x40).unwrap_or(true) {
212 return Err(Error::MalformedMPI(
213 "Bad encoding of Curve25519 key".into()).into());
214 }
215
216 Ok((&value[1..], &[]))
217 },
218
219 NistP256
220 | NistP384
221 | NistP521
222 | BrainpoolP256
223 | BrainpoolP384
224 | BrainpoolP512
225 =>
226 {
227 let coordinate_length = curve.field_size()?;
229
230 let expected_length =
232 1 + (2 * coordinate_length);
235
236 if value.len() != expected_length {
237 return Err(Error::MalformedMPI(
238 format!("Invalid length of MPI: {} (expected {})",
239 value.len(), expected_length)).into());
240 }
241
242 if value.get(0).map(|&b| b != 0x04).unwrap_or(true) {
243 return Err(Error::MalformedMPI(
244 format!("Bad prefix: {:?} (expected Some(0x04))",
245 value.get(0))).into());
246 }
247
248 Ok((&value[1..1 + coordinate_length],
249 &value[1 + coordinate_length..]))
250 },
251
252 Unknown(_) =>
253 Err(Error::UnsupportedEllipticCurve(curve.clone()).into()),
254 }
255 }
256
257 fn secure_memcmp(&self, other: &Self) -> Ordering {
259 let cmp = unsafe {
260 if self.value.len() == other.value.len() {
261 ::memsec::memcmp(self.value.as_ptr(), other.value.as_ptr(),
262 other.value.len())
263 } else {
264 self.value.len() as i32 - other.value.len() as i32
265 }
266 };
267
268 match cmp {
269 0 => Ordering::Equal,
270 x if x < 0 => Ordering::Less,
271 _ => Ordering::Greater,
272 }
273 }
274}
275
276impl fmt::Debug for MPI {
277 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
278 f.write_fmt(format_args!(
279 "{} bits: {}", self.bits(),
280 crate::fmt::to_hex(&*self.value, true)))
281 }
282}
283
284impl Hash for MPI {
285 fn hash(&self, hash: &mut hash::Context) -> Result<()> {
286 let len = self.bits() as u16;
287
288 hash.update(&len.to_be_bytes());
289 hash.update(&self.value);
290 Ok(())
291 }
292}
293
294#[cfg(test)]
295impl Arbitrary for MPI {
296 fn arbitrary(g: &mut Gen) -> Self {
297 loop {
298 let buf = <Vec<u8>>::arbitrary(g);
299
300 if !buf.is_empty() && buf[0] != 0 {
301 break MPI::new(&buf);
302 }
303 }
304 }
305}
306
307impl PartialOrd for MPI {
308 fn partial_cmp(&self, other: &MPI) -> Option<Ordering> {
309 Some(self.cmp(other))
310 }
311}
312
313impl Ord for MPI {
314 fn cmp(&self, other: &MPI) -> Ordering {
315 self.secure_memcmp(other)
316 }
317}
318
319impl PartialEq for MPI {
320 fn eq(&self, other: &MPI) -> bool {
321 self.cmp(other) == Ordering::Equal
322 }
323}
324
325impl Eq for MPI {}
326
327impl std::hash::Hash for MPI {
328 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
329 self.value.hash(state);
330 }
331}
332
333#[derive(Clone)]
339pub struct ProtectedMPI {
340 value: Protected,
342}
343assert_send_and_sync!(ProtectedMPI);
344
345impl From<&[u8]> for ProtectedMPI {
346 fn from(m: &[u8]) -> Self {
347 let value = Protected::from(MPI::trim_leading_zeros(m));
348 ProtectedMPI {
349 value,
350 }
351 }
352}
353
354impl From<Vec<u8>> for ProtectedMPI {
355 fn from(m: Vec<u8>) -> Self {
356 let value = Protected::from(MPI::trim_leading_zeros(&m));
357 drop(Protected::from(m)); ProtectedMPI {
359 value,
360 }
361 }
362}
363
364impl From<Box<[u8]>> for ProtectedMPI {
365 fn from(m: Box<[u8]>) -> Self {
366 let value = Protected::from(MPI::trim_leading_zeros(&m));
367 drop(Protected::from(m)); ProtectedMPI {
369 value,
370 }
371 }
372}
373
374impl From<Protected> for ProtectedMPI {
375 fn from(m: Protected) -> Self {
376 let value = Protected::from(MPI::trim_leading_zeros(&m));
377 drop(m); ProtectedMPI {
379 value,
380 }
381 }
382}
383
384impl PartialOrd for ProtectedMPI {
385 fn partial_cmp(&self, other: &ProtectedMPI) -> Option<Ordering> {
386 Some(self.cmp(other))
387 }
388}
389
390impl Ord for ProtectedMPI {
391 fn cmp(&self, other: &ProtectedMPI) -> Ordering {
392 self.secure_memcmp(other)
393 }
394}
395
396impl PartialEq for ProtectedMPI {
397 fn eq(&self, other: &ProtectedMPI) -> bool {
398 self.cmp(other) == Ordering::Equal
399 }
400}
401
402impl Eq for ProtectedMPI {}
403
404impl std::hash::Hash for ProtectedMPI {
405 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
406 self.value.hash(state);
407 }
408}
409
410#[cfg(test)]
411impl Arbitrary for ProtectedMPI {
412 fn arbitrary(g: &mut Gen) -> Self {
413 loop {
414 let buf = <Vec<u8>>::arbitrary(g);
415
416 if ! buf.is_empty() && buf[0] != 0 {
417 break ProtectedMPI::from(buf);
418 }
419 }
420 }
421}
422
423impl ProtectedMPI {
424 pub fn new_point(x: &[u8], y: &[u8], field_bits: usize) -> Self {
433 MPI::new_point_common(x, y, field_bits).into()
434 }
435
436 pub fn new_compressed_point(x: &[u8]) -> Self {
446 MPI::new_compressed_point_common(x).into()
447 }
448
449 pub fn bits(&self) -> usize {
453 self.value.len() * 8
454 - self.value.get(0).map(|&b| b.leading_zeros() as usize)
455 .unwrap_or(0)
456 }
457
458 pub fn value(&self) -> &[u8] {
463 &self.value
464 }
465
466 pub fn value_padded(&self, to: usize) -> Protected {
473 let missing = to.saturating_sub(self.value.len());
474 let limit = self.value.len().min(to);
475 let mut v: Protected = vec![0; to].into();
476 v[missing..].copy_from_slice(&self.value()[..limit]);
477 v
478 }
479
480 pub fn decode_point(&self, curve: &Curve) -> Result<(&[u8], &[u8])> {
497 MPI::decode_point_common(self.value(), curve)
498 }
499
500 fn secure_memcmp(&self, other: &Self) -> Ordering {
502 (self.value.len() as i32).cmp(&(other.value.len() as i32))
503 .then(
504 self.value.cmp(&other.value))
506 }
507}
508
509impl fmt::Debug for ProtectedMPI {
510 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
511 if cfg!(debug_assertions) {
512 f.write_fmt(format_args!(
513 "{} bits: {}", self.bits(),
514 crate::fmt::to_hex(&*self.value, true)))
515 } else {
516 f.write_str("<Redacted>")
517 }
518 }
519}
520
521#[non_exhaustive]
528#[allow(non_camel_case_types)]
529#[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
530pub enum PublicKey {
531 RSA {
533 e: MPI,
535 n: MPI,
537 },
538
539 DSA {
541 p: MPI,
543 q: MPI,
545 g: MPI,
547 y: MPI,
549 },
550
551 ElGamal {
553 p: MPI,
555 g: MPI,
557 y: MPI,
559 },
560
561 EdDSA {
563 curve: Curve,
565 q: MPI,
567 },
568
569 ECDSA {
571 curve: Curve,
573 q: MPI,
575 },
576
577 ECDH {
579 curve: Curve,
581 q: MPI,
583 hash: HashAlgorithm,
585 sym: SymmetricAlgorithm,
587 },
588
589 X25519 {
591 u: [u8; 32],
593 },
594
595 X448 {
597 u: Box<[u8; 56]>,
599 },
600
601 Ed25519 {
603 a: [u8; 32],
605 },
606
607 Ed448 {
609 a: Box<[u8; 57]>,
611 },
612
613 MLDSA65_Ed25519 {
615 eddsa: Box<[u8; 32]>,
617
618 mldsa: Box<[u8; 1952]>,
620 },
621
622 MLDSA87_Ed448 {
624 eddsa: Box<[u8; 57]>,
626
627 mldsa: Box<[u8; 2592]>,
629 },
630
631 SLHDSA128s {
633 public: [u8; 32],
635 },
636
637 SLHDSA128f {
639 public: [u8; 32],
641 },
642
643 SLHDSA256s {
645 public: Box<[u8; 64]>,
647 },
648
649 MLKEM768_X25519 {
651 ecdh: Box<[u8; 32]>,
653
654 mlkem: Box<[u8; 1184]>,
656 },
657
658 MLKEM1024_X448 {
660 ecdh: Box<[u8; 56]>,
662
663 mlkem: Box<[u8; 1568]>,
665 },
666
667 Unknown {
669 mpis: Box<[MPI]>,
671 rest: Box<[u8]>,
673 },
674}
675assert_send_and_sync!(PublicKey);
676
677impl fmt::Debug for PublicKey {
678 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
679 match self {
680 PublicKey::RSA { e, n } =>
681 f.debug_struct("RSA")
682 .field("e", e)
683 .field("n", n)
684 .finish(),
685
686 PublicKey::DSA { p, q, g, y } =>
687 f.debug_struct("DSA")
688 .field("p", p)
689 .field("q", q)
690 .field("g", g)
691 .field("y", y)
692 .finish(),
693
694 PublicKey::ElGamal { p, g, y } =>
695 f.debug_struct("ElGamal")
696 .field("p", p)
697 .field("g", g)
698 .field("y", y)
699 .finish(),
700
701 PublicKey::EdDSA { curve, q } =>
702 f.debug_struct("EdDSA")
703 .field("curve", curve)
704 .field("q", q)
705 .finish(),
706
707 PublicKey::ECDSA { curve, q } =>
708 f.debug_struct("ECDSA")
709 .field("curve", curve)
710 .field("q", q)
711 .finish(),
712
713 PublicKey::ECDH { curve, q, hash, sym } =>
714 f.debug_struct("ECDH")
715 .field("curve", curve)
716 .field("q", q)
717 .field("hash", hash)
718 .field("sym", sym)
719 .finish(),
720
721 PublicKey::X25519 { u } =>
722 f.debug_struct("X25519")
723 .field("u", &hex::encode(u))
724 .finish(),
725
726 PublicKey::X448 { u } =>
727 f.debug_struct("X448")
728 .field("u", &hex::encode(u.as_ref()))
729 .finish(),
730
731 PublicKey::Ed25519 { a } =>
732 f.debug_struct("Ed25519")
733 .field("a", &hex::encode(a))
734 .finish(),
735
736 PublicKey::Ed448 { a } =>
737 f.debug_struct("Ed448")
738 .field("a", &hex::encode(a.as_ref()))
739 .finish(),
740
741 PublicKey::MLDSA65_Ed25519 { eddsa, mldsa } =>
742 f.debug_struct("MLDSA65_Ed25519")
743 .field("eddsa", &hex::encode(eddsa.as_ref()))
744 .field("mldsa", &hex::encode(mldsa.as_ref()))
745 .finish(),
746
747 PublicKey::MLDSA87_Ed448 { eddsa, mldsa } =>
748 f.debug_struct("MLDSA87_Ed448")
749 .field("eddsa", &hex::encode(eddsa.as_ref()))
750 .field("mldsa", &hex::encode(mldsa.as_ref()))
751 .finish(),
752
753 PublicKey::SLHDSA128s { public } =>
754 f.debug_struct("SLHDSA128s")
755 .field("public", &hex::encode(public))
756 .finish(),
757
758 PublicKey::SLHDSA128f { public } =>
759 f.debug_struct("SLHDSA128f")
760 .field("public", &hex::encode(public))
761 .finish(),
762
763 PublicKey::SLHDSA256s { public } =>
764 f.debug_struct("SLHDSA256s")
765 .field("public", &hex::encode(public.as_ref()))
766 .finish(),
767
768 PublicKey::MLKEM768_X25519 { ecdh, mlkem } =>
769 f.debug_struct("MLKEM768_X25519")
770 .field("ecdh", &hex::encode(ecdh.as_ref()))
771 .field("mlkem", &hex::encode(mlkem.as_ref()))
772 .finish(),
773
774 PublicKey::MLKEM1024_X448 { ecdh, mlkem } =>
775 f.debug_struct("MLKEM1024_X448")
776 .field("ecdh", &hex::encode(ecdh.as_ref()))
777 .field("mlkem", &hex::encode(mlkem.as_ref()))
778 .finish(),
779
780 PublicKey::Unknown { mpis, rest } =>
781 f.debug_struct("Unknown")
782 .field("mpis", mpis)
783 .field("rest", &hex::encode(rest))
784 .finish(),
785 }
786 }
787}
788
789impl PublicKey {
790 pub fn bits(&self) -> Option<usize> {
801 use self::PublicKey::*;
802 match self {
803 RSA { ref n,.. } => Some(n.bits()),
804 DSA { ref p,.. } => Some(p.bits()),
805 ElGamal { ref p,.. } => Some(p.bits()),
806 EdDSA { ref curve,.. } => curve.bits().ok(),
807 ECDSA { ref curve,.. } => curve.bits().ok(),
808 ECDH { ref curve,.. } => curve.bits().ok(),
809 X25519 { .. } => Some(256),
810 X448 { .. } => Some(448),
811 Ed25519 { .. } => Some(256),
812 Ed448 { .. } => Some(456),
813 MLDSA65_Ed25519 { .. } => None,
814 MLDSA87_Ed448 { .. } => None,
815 SLHDSA128s { .. } => None,
816 SLHDSA128f { .. } => None,
817 SLHDSA256s { .. } => None,
818 MLKEM768_X25519 { .. } => None,
819 MLKEM1024_X448 { .. } => None,
820 Unknown { .. } => None,
821 }
822 }
823
824 pub fn algo(&self) -> Option<PublicKeyAlgorithm> {
827 use self::PublicKey::*;
828 #[allow(deprecated)]
829 match self {
830 RSA { .. } => Some(PublicKeyAlgorithm::RSAEncryptSign),
831 DSA { .. } => Some(PublicKeyAlgorithm::DSA),
832 ElGamal { .. } => Some(PublicKeyAlgorithm::ElGamalEncrypt),
833 EdDSA { .. } => Some(PublicKeyAlgorithm::EdDSA),
834 ECDSA { .. } => Some(PublicKeyAlgorithm::ECDSA),
835 ECDH { .. } => Some(PublicKeyAlgorithm::ECDH),
836 X25519 { .. } => Some(PublicKeyAlgorithm::X25519),
837 X448 { .. } => Some(PublicKeyAlgorithm::X448),
838 Ed25519 { .. } => Some(PublicKeyAlgorithm::Ed25519),
839 Ed448 { .. } => Some(PublicKeyAlgorithm::Ed448),
840 MLDSA65_Ed25519 { .. } =>
841 Some(PublicKeyAlgorithm::MLDSA65_Ed25519),
842 MLDSA87_Ed448 { .. } =>
843 Some(PublicKeyAlgorithm::MLDSA87_Ed448),
844 SLHDSA128s { .. } => Some(PublicKeyAlgorithm::SLHDSA128s),
845 SLHDSA128f { .. } => Some(PublicKeyAlgorithm::SLHDSA128f),
846 SLHDSA256s { .. } => Some(PublicKeyAlgorithm::SLHDSA256s),
847 MLKEM768_X25519 { .. } =>
848 Some(PublicKeyAlgorithm::MLKEM768_X25519),
849 MLKEM1024_X448 { .. } =>
850 Some(PublicKeyAlgorithm::MLKEM1024_X448),
851 Unknown { .. } => None,
852 }
853 }
854}
855
856impl Hash for PublicKey {
857 fn hash(&self, mut hash: &mut hash::Context) -> Result<()> {
858 self.serialize(&mut hash as &mut dyn Write)
859 }
860}
861
862#[cfg(test)]
863impl Arbitrary for PublicKey {
864 fn arbitrary(g: &mut Gen) -> Self {
865 use self::PublicKey::*;
866 use crate::arbitrary_helper::gen_arbitrary_from_range;
867
868 match gen_arbitrary_from_range(0..17, g) {
869 0 => RSA {
870 e: MPI::arbitrary(g),
871 n: MPI::arbitrary(g),
872 },
873
874 1 => DSA {
875 p: MPI::arbitrary(g),
876 q: MPI::arbitrary(g),
877 g: MPI::arbitrary(g),
878 y: MPI::arbitrary(g),
879 },
880
881 2 => ElGamal {
882 p: MPI::arbitrary(g),
883 g: MPI::arbitrary(g),
884 y: MPI::arbitrary(g),
885 },
886
887 3 => EdDSA {
888 curve: Curve::arbitrary(g),
889 q: MPI::arbitrary(g),
890 },
891
892 4 => ECDSA {
893 curve: Curve::arbitrary(g),
894 q: MPI::arbitrary(g),
895 },
896
897 5 => ECDH {
898 curve: Curve::arbitrary(g),
899 q: MPI::arbitrary(g),
900 hash: HashAlgorithm::arbitrary(g),
901 sym: SymmetricAlgorithm::arbitrary(g),
902 },
903
904 6 => X25519 { u: arbitrary(g) },
905 7 => X448 { u: Box::new(arbitrarize(g, [0; 56])) },
906 8 => Ed25519 { a: arbitrary(g) },
907 9 => Ed448 { a: Box::new(arbitrarize(g, [0; 57])) },
908
909 10 => MLDSA65_Ed25519 {
910 eddsa: Box::new(arbitrarize(g, [0; 32])),
911 mldsa: Box::new(arbitrarize(g, [0; 1952])),
912 },
913
914 11 => MLDSA87_Ed448 {
915 eddsa: Box::new(arbitrarize(g, [0; 57])),
916 mldsa: Box::new(arbitrarize(g, [0; 2592])),
917 },
918
919 12 => SLHDSA128s {
920 public: arbitrary(g),
921 },
922
923 13 => SLHDSA128f {
924 public: arbitrary(g),
925 },
926
927 14 => SLHDSA256s {
928 public: Box::new(arbitrarize(g, [0; 64])),
929 },
930
931 15 => MLKEM768_X25519 {
932 ecdh: Box::new(arbitrarize(g, [0; 32])),
933 mlkem: Box::new(arbitrarize(g, [0; 1184])),
934 },
935
936 16 => MLKEM1024_X448 {
937 ecdh: Box::new(arbitrarize(g, [0; 56])),
938 mlkem: Box::new(arbitrarize(g, [0; 1568])),
939 },
940
941 _ => unreachable!(),
942 }
943 }
944}
945
946#[cfg(test)]
947pub(crate) fn arbitrarize<T: AsMut<[u8]>>(g: &mut Gen, mut a: T) -> T
948{
949 a.as_mut().iter_mut().for_each(|p| *p = Arbitrary::arbitrary(g));
950 a
951}
952
953#[cfg(test)]
954pub(crate) fn arbitrary<T: Default + AsMut<[u8]>>(g: &mut Gen) -> T
955{
956 arbitrarize(g, Default::default())
957}
958
959
960#[non_exhaustive]
970#[allow(non_camel_case_types)]
971#[allow(clippy::derived_hash_with_manual_eq)]
972#[derive(Clone, Hash)]
973pub enum SecretKeyMaterial {
974 RSA {
976 d: ProtectedMPI,
978 p: ProtectedMPI,
980 q: ProtectedMPI,
982 u: ProtectedMPI,
984 },
985
986 DSA {
988 x: ProtectedMPI,
990 },
991
992 ElGamal {
994 x: ProtectedMPI,
996 },
997
998 EdDSA {
1000 scalar: ProtectedMPI,
1002 },
1003
1004 ECDSA {
1006 scalar: ProtectedMPI,
1008 },
1009
1010 ECDH {
1012 scalar: ProtectedMPI,
1014 },
1015
1016 X25519 {
1018 x: Protected,
1020 },
1021
1022 X448 {
1024 x: Protected,
1026 },
1027
1028 Ed25519 {
1030 x: Protected,
1032 },
1033
1034 Ed448 {
1036 x: Protected,
1038 },
1039
1040 MLDSA65_Ed25519 {
1042 eddsa: Protected,
1044
1045 mldsa: Protected,
1047 },
1048
1049 MLDSA87_Ed448 {
1051 eddsa: Protected,
1053
1054 mldsa: Protected,
1056 },
1057
1058 SLHDSA128s {
1060 secret: Protected,
1062 },
1063
1064 SLHDSA128f {
1066 secret: Protected,
1068 },
1069
1070 SLHDSA256s {
1072 secret: Protected,
1074 },
1075
1076 MLKEM768_X25519 {
1078 ecdh: Protected,
1080
1081 mlkem: Protected,
1083 },
1084
1085 MLKEM1024_X448 {
1087 ecdh: Protected,
1089
1090 mlkem: Protected,
1092 },
1093
1094 Unknown {
1096 mpis: Box<[ProtectedMPI]>,
1098 rest: Protected,
1100 },
1101}
1102assert_send_and_sync!(SecretKeyMaterial);
1103
1104impl fmt::Debug for SecretKeyMaterial {
1105 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1106 if cfg!(debug_assertions) {
1107 match self {
1108 SecretKeyMaterial::RSA { d, p, q, u } =>
1109 f.debug_struct("RSA")
1110 .field("d", d)
1111 .field("p", p)
1112 .field("q", q)
1113 .field("u", u)
1114 .finish(),
1115
1116 SecretKeyMaterial::DSA { x } =>
1117 f.debug_struct("DSA")
1118 .field("x", x)
1119 .finish(),
1120
1121 SecretKeyMaterial::ElGamal { x } =>
1122 f.debug_struct("ElGamal")
1123 .field("x", x)
1124 .finish(),
1125
1126 SecretKeyMaterial::EdDSA { scalar } =>
1127 f.debug_struct("EdDSA")
1128 .field("scalar", scalar)
1129 .finish(),
1130
1131 SecretKeyMaterial::ECDSA { scalar } =>
1132 f.debug_struct("ECDSA")
1133 .field("scalar", scalar)
1134 .finish(),
1135
1136 SecretKeyMaterial::ECDH { scalar } =>
1137 f.debug_struct("ECDH")
1138 .field("scalar", scalar)
1139 .finish(),
1140
1141 SecretKeyMaterial::X25519 { x } =>
1142 f.debug_struct("X25519")
1143 .field("x", &hex::encode(x))
1144 .finish(),
1145
1146 SecretKeyMaterial::X448 { x } =>
1147 f.debug_struct("X448")
1148 .field("x", &hex::encode(x))
1149 .finish(),
1150
1151 SecretKeyMaterial::Ed25519 { x } =>
1152 f.debug_struct("Ed25519")
1153 .field("x", &hex::encode(x))
1154 .finish(),
1155
1156 SecretKeyMaterial::Ed448 { x } =>
1157 f.debug_struct("Ed448")
1158 .field("x", &hex::encode(x))
1159 .finish(),
1160
1161 SecretKeyMaterial::MLDSA65_Ed25519 { eddsa, mldsa } =>
1162 f.debug_struct("MLDSA65_Ed25519")
1163 .field("eddsa", &hex::encode(eddsa))
1164 .field("mldsa", &hex::encode(mldsa))
1165 .finish(),
1166
1167 SecretKeyMaterial::MLDSA87_Ed448 { eddsa, mldsa } =>
1168 f.debug_struct("MLDSA87_Ed448")
1169 .field("eddsa", &hex::encode(eddsa))
1170 .field("mldsa", &hex::encode(mldsa))
1171 .finish(),
1172
1173 SecretKeyMaterial::SLHDSA128s { secret } =>
1174 f.debug_struct("SLHDSA128s")
1175 .field("secret", &hex::encode(secret.as_ref()))
1176 .finish(),
1177
1178 SecretKeyMaterial::SLHDSA128f { secret } =>
1179 f.debug_struct("SLHDSA128f")
1180 .field("secret", &hex::encode(secret.as_ref()))
1181 .finish(),
1182
1183 SecretKeyMaterial::SLHDSA256s { secret } =>
1184 f.debug_struct("SLHDSA256s")
1185 .field("secret", &hex::encode(secret.as_ref()))
1186 .finish(),
1187
1188 SecretKeyMaterial::MLKEM768_X25519 { ecdh, mlkem } =>
1189 f.debug_struct("MLKEM768_X25519")
1190 .field("ecdh", &hex::encode(ecdh))
1191 .field("mlkem", &hex::encode(mlkem))
1192 .finish(),
1193
1194 SecretKeyMaterial::MLKEM1024_X448 { ecdh, mlkem } =>
1195 f.debug_struct("MLKEM1024_X448")
1196 .field("ecdh", &hex::encode(ecdh))
1197 .field("mlkem", &hex::encode(mlkem))
1198 .finish(),
1199
1200 SecretKeyMaterial::Unknown{ mpis, rest } =>
1201 f.debug_struct("Unknown")
1202 .field("mpis", mpis)
1203 .field("rest", &hex::encode(rest))
1204 .finish(),
1205 }
1206 } else {
1207 match self {
1208 SecretKeyMaterial::RSA{ .. } =>
1209 f.write_str("RSA { <Redacted> }"),
1210 SecretKeyMaterial::DSA{ .. } =>
1211 f.write_str("DSA { <Redacted> }"),
1212 SecretKeyMaterial::ElGamal{ .. } =>
1213 f.write_str("ElGamal { <Redacted> }"),
1214 SecretKeyMaterial::EdDSA{ .. } =>
1215 f.write_str("EdDSA { <Redacted> }"),
1216 SecretKeyMaterial::ECDSA{ .. } =>
1217 f.write_str("ECDSA { <Redacted> }"),
1218 SecretKeyMaterial::ECDH{ .. } =>
1219 f.write_str("ECDH { <Redacted> }"),
1220 SecretKeyMaterial::X25519 { .. } =>
1221 f.write_str("X25519 { <Redacted> }"),
1222 SecretKeyMaterial::X448 { .. } =>
1223 f.write_str("X448 { <Redacted> }"),
1224 SecretKeyMaterial::Ed25519 { .. } =>
1225 f.write_str("Ed25519 { <Redacted> }"),
1226 SecretKeyMaterial::Ed448 { .. } =>
1227 f.write_str("Ed448 { <Redacted> }"),
1228 SecretKeyMaterial::MLDSA65_Ed25519 { .. } =>
1229 f.write_str("MLDSA65_Ed25519 { <Redacted> }"),
1230 SecretKeyMaterial::MLDSA87_Ed448 { .. } =>
1231 f.write_str("MLDSA87_Ed448 { <Redacted> }"),
1232 SecretKeyMaterial::SLHDSA128s { .. } =>
1233 f.write_str("SLHDSA128s { <Redacted> }"),
1234 SecretKeyMaterial::SLHDSA128f { .. } =>
1235 f.write_str("SLHDSA128f { <Redacted> }"),
1236 SecretKeyMaterial::SLHDSA256s { .. } =>
1237 f.write_str("SLHDSA256s { <Redacted> }"),
1238 SecretKeyMaterial::MLKEM768_X25519 { .. } =>
1239 f.write_str("MLKEM768_X25519 { <Redacted> }"),
1240 SecretKeyMaterial::MLKEM1024_X448 { .. } =>
1241 f.write_str("MLKEM1024_X448 { <Redacted> }"),
1242 SecretKeyMaterial::Unknown{ .. } =>
1243 f.write_str("Unknown { <Redacted> }"),
1244 }
1245 }
1246 }
1247}
1248
1249impl PartialOrd for SecretKeyMaterial {
1250 fn partial_cmp(&self, other: &SecretKeyMaterial) -> Option<Ordering> {
1251 Some(self.cmp(other))
1252 }
1253}
1254
1255impl Ord for SecretKeyMaterial {
1256 fn cmp(&self, other: &Self) -> Ordering {
1257 use std::iter;
1258
1259 fn discriminant(sk: &SecretKeyMaterial) -> usize {
1260 match sk {
1261 SecretKeyMaterial::RSA{ .. } => 0,
1262 SecretKeyMaterial::DSA{ .. } => 1,
1263 SecretKeyMaterial::ElGamal{ .. } => 2,
1264 SecretKeyMaterial::EdDSA{ .. } => 3,
1265 SecretKeyMaterial::ECDSA{ .. } => 4,
1266 SecretKeyMaterial::ECDH{ .. } => 5,
1267 SecretKeyMaterial::X25519 { .. } => 6,
1268 SecretKeyMaterial::X448 { .. } => 7,
1269 SecretKeyMaterial::Ed25519 { .. } => 8,
1270 SecretKeyMaterial::Ed448 { .. } => 9,
1271 SecretKeyMaterial::Unknown { .. } => 10,
1272 SecretKeyMaterial::MLDSA65_Ed25519 { .. } => 11,
1273 SecretKeyMaterial::MLDSA87_Ed448 { .. } => 12,
1274 SecretKeyMaterial::SLHDSA128s { .. } => 13,
1275 SecretKeyMaterial::SLHDSA128f { .. } => 14,
1276 SecretKeyMaterial::SLHDSA256s { .. } => 15,
1277 SecretKeyMaterial::MLKEM768_X25519 { .. } => 16,
1278 SecretKeyMaterial::MLKEM1024_X448 { .. } => 17,
1279 }
1280 }
1281
1282 let ret = match (self, other) {
1283 (&SecretKeyMaterial::RSA{ d: ref d1, p: ref p1, q: ref q1, u: ref u1 }
1284 ,&SecretKeyMaterial::RSA{ d: ref d2, p: ref p2, q: ref q2, u: ref u2 }) => {
1285 let o1 = d1.cmp(d2);
1286 let o2 = p1.cmp(p2);
1287 let o3 = q1.cmp(q2);
1288 let o4 = u1.cmp(u2);
1289
1290 if o1 != Ordering::Equal { return o1; }
1291 if o2 != Ordering::Equal { return o2; }
1292 if o3 != Ordering::Equal { return o3; }
1293 o4
1294 }
1295 (&SecretKeyMaterial::DSA{ x: ref x1 }
1296 ,&SecretKeyMaterial::DSA{ x: ref x2 }) => {
1297 x1.cmp(x2)
1298 }
1299 (&SecretKeyMaterial::ElGamal{ x: ref x1 }
1300 ,&SecretKeyMaterial::ElGamal{ x: ref x2 }) => {
1301 x1.cmp(x2)
1302 }
1303 (&SecretKeyMaterial::EdDSA{ scalar: ref scalar1 }
1304 ,&SecretKeyMaterial::EdDSA{ scalar: ref scalar2 }) => {
1305 scalar1.cmp(scalar2)
1306 }
1307 (&SecretKeyMaterial::ECDSA{ scalar: ref scalar1 }
1308 ,&SecretKeyMaterial::ECDSA{ scalar: ref scalar2 }) => {
1309 scalar1.cmp(scalar2)
1310 }
1311 (&SecretKeyMaterial::ECDH{ scalar: ref scalar1 }
1312 ,&SecretKeyMaterial::ECDH{ scalar: ref scalar2 }) => {
1313 scalar1.cmp(scalar2)
1314 }
1315 (SecretKeyMaterial::X25519 { x: x0 },
1316 SecretKeyMaterial::X25519 { x: x1 }) => x0.cmp(x1),
1317 (SecretKeyMaterial::X448 { x: x0 },
1318 SecretKeyMaterial::X448 { x: x1 }) => x0.cmp(x1),
1319 (SecretKeyMaterial::Ed25519 { x: x0 },
1320 SecretKeyMaterial::Ed25519 { x: x1 }) => x0.cmp(x1),
1321 (SecretKeyMaterial::Ed448 { x: x0 },
1322 SecretKeyMaterial::Ed448 { x: x1 }) => x0.cmp(x1),
1323
1324 (SecretKeyMaterial::MLDSA65_Ed25519 { eddsa: e0, mldsa: m0 },
1325 SecretKeyMaterial::MLDSA65_Ed25519 { eddsa: e1, mldsa: m1 }) =>
1326 iter::once(e0.cmp(e1))
1327 .chain(iter::once(m0.cmp(m1)))
1328 .fold(Ordering::Equal, |acc, x| acc.then(x)),
1329
1330 (SecretKeyMaterial::MLDSA87_Ed448 { eddsa: e0, mldsa: m0 },
1331 SecretKeyMaterial::MLDSA87_Ed448 { eddsa: e1, mldsa: m1 }) =>
1332 iter::once(e0.cmp(e1))
1333 .chain(iter::once(m0.cmp(m1)))
1334 .fold(Ordering::Equal, |acc, x| acc.then(x)),
1335
1336 (SecretKeyMaterial::SLHDSA128s { secret: s0 },
1337 SecretKeyMaterial::SLHDSA128s { secret: s1 }) => s0.cmp(s1),
1338
1339 (SecretKeyMaterial::SLHDSA128f { secret: s0 },
1340 SecretKeyMaterial::SLHDSA128f { secret: s1 }) => s0.cmp(s1),
1341
1342 (SecretKeyMaterial::SLHDSA256s { secret: s0 },
1343 SecretKeyMaterial::SLHDSA256s { secret: s1 }) => s0.cmp(s1),
1344
1345 (SecretKeyMaterial::MLKEM768_X25519 { ecdh: e0, mlkem: m0 },
1346 SecretKeyMaterial::MLKEM768_X25519 { ecdh: e1, mlkem: m1 }) =>
1347 iter::once(e0.cmp(e1))
1348 .chain(iter::once(m0.cmp(m1)))
1349 .fold(Ordering::Equal, |acc, x| acc.then(x)),
1350
1351 (SecretKeyMaterial::MLKEM1024_X448 { ecdh: e0, mlkem: m0 },
1352 SecretKeyMaterial::MLKEM1024_X448 { ecdh: e1, mlkem: m1 }) =>
1353 iter::once(e0.cmp(e1))
1354 .chain(iter::once(m0.cmp(m1)))
1355 .fold(Ordering::Equal, |acc, x| acc.then(x)),
1356
1357 (&SecretKeyMaterial::Unknown{ mpis: ref mpis1, rest: ref rest1 }
1358 ,&SecretKeyMaterial::Unknown{ mpis: ref mpis2, rest: ref rest2 }) => {
1359 let o1 = secure_cmp(rest1, rest2);
1360 let o2 = mpis1.len().cmp(&mpis2.len());
1361 let on = mpis1.iter().zip(mpis2.iter()).map(|(a,b)| {
1362 a.cmp(b)
1363 }).collect::<Vec<_>>();
1364
1365 iter::once(o1)
1366 .chain(iter::once(o2))
1367 .chain(on.iter().cloned())
1368 .fold(Ordering::Equal, |acc, x| acc.then(x))
1369 }
1370
1371 (a, b) => {
1372 let ret = discriminant(a).cmp(&discriminant(b));
1373
1374 assert!(ret != Ordering::Equal);
1375 ret
1376 }
1377 };
1378
1379 ret
1380 }
1381}
1382
1383impl PartialEq for SecretKeyMaterial {
1384 fn eq(&self, other: &Self) -> bool { self.cmp(other) == Ordering::Equal }
1385}
1386
1387impl Eq for SecretKeyMaterial {}
1388
1389impl SecretKeyMaterial {
1390 pub fn algo(&self) -> Option<PublicKeyAlgorithm> {
1393 use self::SecretKeyMaterial::*;
1394 #[allow(deprecated)]
1395 match self {
1396 RSA { .. } => Some(PublicKeyAlgorithm::RSAEncryptSign),
1397 DSA { .. } => Some(PublicKeyAlgorithm::DSA),
1398 ElGamal { .. } => Some(PublicKeyAlgorithm::ElGamalEncrypt),
1399 EdDSA { .. } => Some(PublicKeyAlgorithm::EdDSA),
1400 ECDSA { .. } => Some(PublicKeyAlgorithm::ECDSA),
1401 ECDH { .. } => Some(PublicKeyAlgorithm::ECDH),
1402 X25519 { .. } => Some(PublicKeyAlgorithm::X25519),
1403 X448 { .. } => Some(PublicKeyAlgorithm::X448),
1404 Ed25519 { .. } => Some(PublicKeyAlgorithm::Ed25519),
1405 Ed448 { .. } => Some(PublicKeyAlgorithm::Ed448),
1406 MLDSA65_Ed25519 { .. } => Some(PublicKeyAlgorithm::MLDSA65_Ed25519),
1407 MLDSA87_Ed448 { .. } => Some(PublicKeyAlgorithm::MLDSA87_Ed448),
1408 SLHDSA128s { .. } => Some(PublicKeyAlgorithm::SLHDSA128s),
1409 SLHDSA128f { .. } => Some(PublicKeyAlgorithm::SLHDSA128f),
1410 SLHDSA256s { .. } => Some(PublicKeyAlgorithm::SLHDSA256s),
1411 MLKEM768_X25519 { .. } => Some(PublicKeyAlgorithm::MLKEM768_X25519),
1412 MLKEM1024_X448 { .. } => Some(PublicKeyAlgorithm::MLKEM1024_X448),
1413 Unknown { .. } => None,
1414 }
1415 }
1416}
1417
1418impl Hash for SecretKeyMaterial {
1419 fn hash(&self, mut hash: &mut hash::Context) -> Result<()> {
1420 self.serialize(&mut hash as &mut dyn Write)
1421 }
1422}
1423
1424#[cfg(test)]
1425impl SecretKeyMaterial {
1426 pub(crate) fn arbitrary_for(g: &mut Gen, pk: PublicKeyAlgorithm) -> Result<Self> {
1427 use self::PublicKeyAlgorithm::*;
1428 #[allow(deprecated)]
1429 match pk {
1430 RSAEncryptSign | RSASign | RSAEncrypt => Ok(SecretKeyMaterial::RSA {
1431 d: ProtectedMPI::arbitrary(g),
1432 p: ProtectedMPI::arbitrary(g),
1433 q: ProtectedMPI::arbitrary(g),
1434 u: ProtectedMPI::arbitrary(g),
1435 }),
1436
1437 DSA => Ok(SecretKeyMaterial::DSA {
1438 x: ProtectedMPI::arbitrary(g),
1439 }),
1440
1441 ElGamalEncryptSign | ElGamalEncrypt => Ok(SecretKeyMaterial::ElGamal {
1442 x: ProtectedMPI::arbitrary(g),
1443 }),
1444
1445 EdDSA => Ok(SecretKeyMaterial::EdDSA {
1446 scalar: ProtectedMPI::arbitrary(g),
1447 }),
1448
1449 ECDSA => Ok(SecretKeyMaterial::ECDSA {
1450 scalar: ProtectedMPI::arbitrary(g),
1451 }),
1452
1453 ECDH => Ok(SecretKeyMaterial::ECDH {
1454 scalar: ProtectedMPI::arbitrary(g),
1455 }),
1456
1457 X25519 => Ok(SecretKeyMaterial::X25519 {
1458 x: arbitrarize(g, vec![0; 32]).into(),
1459 }),
1460 X448 => Ok(SecretKeyMaterial::X448 {
1461 x: arbitrarize(g, vec![0; 56]).into(),
1462 }),
1463 Ed25519 => Ok(SecretKeyMaterial::Ed25519 {
1464 x: arbitrarize(g, vec![0; 32]).into(),
1465 }),
1466 Ed448 => Ok(SecretKeyMaterial::Ed448 {
1467 x: arbitrarize(g, vec![0; 57]).into(),
1468 }),
1469
1470 MLDSA65_Ed25519 => Ok(SecretKeyMaterial::MLDSA65_Ed25519 {
1471 eddsa: arbitrarize(g, vec![0; 32]).into(),
1472 mldsa: arbitrarize(g, vec![0; 32]).into(),
1473 }),
1474
1475 MLDSA87_Ed448 => Ok(SecretKeyMaterial::MLDSA87_Ed448 {
1476 eddsa: arbitrarize(g, vec![0; 57]).into(),
1477 mldsa: arbitrarize(g, vec![0; 32]).into(),
1478 }),
1479
1480 SLHDSA128s => Ok(SecretKeyMaterial::SLHDSA128s {
1481 secret: arbitrarize(g, [0; 64]).into(),
1482 }),
1483
1484 SLHDSA128f => Ok(SecretKeyMaterial::SLHDSA128f {
1485 secret: arbitrarize(g, [0; 64]).into(),
1486 }),
1487
1488 SLHDSA256s => Ok(SecretKeyMaterial::SLHDSA256s {
1489 secret: arbitrarize(g, [0; 128]).into(),
1490 }),
1491
1492 MLKEM768_X25519 => Ok(SecretKeyMaterial::MLKEM768_X25519 {
1493 ecdh: arbitrarize(g, vec![0; 32]).into(),
1494 mlkem: arbitrarize(g, vec![0; 64]).into(),
1495 }),
1496
1497 MLKEM1024_X448 => Ok(SecretKeyMaterial::MLKEM1024_X448 {
1498 ecdh: arbitrarize(g, vec![0; 56]).into(),
1499 mlkem: arbitrarize(g, vec![0; 64]).into(),
1500 }),
1501
1502 Private(_) | Unknown(_) =>
1503 Err(Error::UnsupportedPublicKeyAlgorithm(pk).into()),
1504 }
1505 }
1506}
1507#[cfg(test)]
1508impl Arbitrary for SecretKeyMaterial {
1509 fn arbitrary(g: &mut Gen) -> Self {
1510 let pk = *g.choose(
1511 &crate::crypto::types::public_key_algorithm::PUBLIC_KEY_ALGORITHM_VARIANTS)
1512 .expect("not empty");
1513 Self::arbitrary_for(g, pk).expect("only known variants")
1514 }
1515}
1516
1517#[derive(PartialEq, Eq, Hash, Clone, Copy, Debug)]
1524pub enum SecretKeyChecksum {
1525 SHA1,
1527
1528 Sum16,
1530}
1531assert_send_and_sync!(SecretKeyChecksum);
1532
1533impl Default for SecretKeyChecksum {
1534 fn default() -> Self {
1535 SecretKeyChecksum::SHA1
1536 }
1537}
1538
1539impl SecretKeyChecksum {
1540 pub(crate) fn len(&self) -> usize {
1542 match self {
1543 SecretKeyChecksum::SHA1 => 20,
1544 SecretKeyChecksum::Sum16 => 2,
1545 }
1546 }
1547}
1548
1549#[non_exhaustive]
1556#[allow(non_camel_case_types)]
1557#[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
1558pub enum Ciphertext {
1559 RSA {
1561 c: MPI,
1563 },
1564
1565 ElGamal {
1567 e: MPI,
1569 c: MPI,
1571 },
1572
1573 ECDH {
1575 e: MPI,
1577 key: Box<[u8]>,
1579 },
1580
1581 X25519 {
1583 e: Box<[u8; 32]>,
1585 key: Box<[u8]>,
1587 },
1588
1589 X448 {
1591 e: Box<[u8; 56]>,
1593 key: Box<[u8]>,
1595 },
1596
1597 MLKEM768_X25519 {
1599 ecdh: Box<[u8; 32]>,
1601
1602 mlkem: Box<[u8; 1088]>,
1604
1605 esk: Box<[u8]>,
1607 },
1608
1609 MLKEM1024_X448 {
1611 ecdh: Box<[u8; 56]>,
1613
1614 mlkem: Box<[u8; 1568]>,
1616
1617 esk: Box<[u8]>,
1619 },
1620
1621 Unknown {
1623 mpis: Box<[MPI]>,
1625 rest: Box<[u8]>,
1627 },
1628}
1629assert_send_and_sync!(Ciphertext);
1630
1631impl fmt::Debug for Ciphertext {
1632 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1633 match self {
1634 Ciphertext::RSA { c } =>
1635 f.debug_struct("RSA")
1636 .field("c", c)
1637 .finish(),
1638
1639 Ciphertext::ElGamal { e, c } =>
1640 f.debug_struct("ElGamal")
1641 .field("e", e)
1642 .field("c", c)
1643 .finish(),
1644
1645 Ciphertext::ECDH { e, key } =>
1646 f.debug_struct("ECDH")
1647 .field("e", e)
1648 .field("key", &hex::encode(key))
1649 .finish(),
1650
1651 Ciphertext::X25519 { e, key } =>
1652 f.debug_struct("X25519")
1653 .field("e", &hex::encode(&e[..]))
1654 .field("key", &hex::encode(key))
1655 .finish(),
1656
1657 Ciphertext::X448 { e, key } =>
1658 f.debug_struct("X448")
1659 .field("e", &hex::encode(&e[..]))
1660 .field("key", &hex::encode(key))
1661 .finish(),
1662
1663 Ciphertext::MLKEM768_X25519 { ecdh, mlkem, esk } =>
1664 f.debug_struct("MLKEM768_X25519")
1665 .field("ecdh", &hex::encode(&ecdh[..]))
1666 .field("mlkem", &hex::encode(&mlkem[..]))
1667 .field("esk", &hex::encode(esk))
1668 .finish(),
1669
1670 Ciphertext::MLKEM1024_X448 { ecdh, mlkem, esk } =>
1671 f.debug_struct("MLKEM1024_X448")
1672 .field("ecdh", &hex::encode(&ecdh[..]))
1673 .field("mlkem", &hex::encode(&mlkem[..]))
1674 .field("esk", &hex::encode(esk))
1675 .finish(),
1676
1677 Ciphertext::Unknown { mpis, rest } =>
1678 f.debug_struct("Unknown")
1679 .field("mpis", mpis)
1680 .field("rest", &hex::encode(rest))
1681 .finish(),
1682 }
1683 }
1684}
1685
1686impl Ciphertext {
1687 pub fn pk_algo(&self) -> Option<PublicKeyAlgorithm> {
1690 use self::Ciphertext::*;
1691
1692 #[allow(deprecated)]
1696 match self {
1697 RSA { .. } => Some(PublicKeyAlgorithm::RSAEncryptSign),
1698 ElGamal { .. } => Some(PublicKeyAlgorithm::ElGamalEncrypt),
1699 ECDH { .. } => Some(PublicKeyAlgorithm::ECDH),
1700 X25519 { .. } => Some(PublicKeyAlgorithm::X25519),
1701 X448 { .. } => Some(PublicKeyAlgorithm::X448),
1702 MLKEM768_X25519 { .. } => Some(PublicKeyAlgorithm::MLKEM768_X25519),
1703 MLKEM1024_X448 { .. } => Some(PublicKeyAlgorithm::MLKEM1024_X448),
1704 Unknown { .. } => None,
1705 }
1706 }
1707}
1708
1709impl Hash for Ciphertext {
1710 fn hash(&self, mut hash: &mut hash::Context) -> Result<()> {
1711 self.serialize(&mut hash as &mut dyn Write)
1712 }
1713}
1714
1715#[cfg(test)]
1716impl Arbitrary for Ciphertext {
1717 fn arbitrary(g: &mut Gen) -> Self {
1718 use crate::arbitrary_helper::gen_arbitrary_from_range;
1719
1720 match gen_arbitrary_from_range(0..7, g) {
1721 0 => Ciphertext::RSA {
1722 c: MPI::arbitrary(g),
1723 },
1724
1725 1 => Ciphertext::ElGamal {
1726 e: MPI::arbitrary(g),
1727 c: MPI::arbitrary(g)
1728 },
1729
1730 2 => Ciphertext::ECDH {
1731 e: MPI::arbitrary(g),
1732 key: {
1733 let mut k = <Vec<u8>>::arbitrary(g);
1734 k.truncate(255);
1735 k.into_boxed_slice()
1736 },
1737 },
1738
1739 3 => Ciphertext::X25519 {
1740 e: Box::new(arbitrary(g)),
1741 key: {
1742 let mut k = <Vec<u8>>::arbitrary(g);
1743 k.truncate(255);
1744 k.into_boxed_slice()
1745 },
1746 },
1747
1748 4 => Ciphertext::X448 {
1749 e: Box::new(arbitrarize(g, [0; 56])),
1750 key: {
1751 let mut k = <Vec<u8>>::arbitrary(g);
1752 k.truncate(255);
1753 k.into_boxed_slice()
1754 },
1755 },
1756
1757 5 => Ciphertext::MLKEM768_X25519 {
1758 ecdh: Box::new(arbitrarize(g, [0; 32])),
1759 mlkem: Box::new(arbitrarize(g, [0; 1088])),
1760 esk: {
1761 let mut k = <Vec<u8>>::arbitrary(g);
1762 k.truncate(255);
1763 k.into_boxed_slice()
1764 },
1765 },
1766
1767 6 => Ciphertext::MLKEM1024_X448 {
1768 ecdh: Box::new(arbitrarize(g, [0; 56])),
1769 mlkem: Box::new(arbitrarize(g, [0; 1568])),
1770 esk: {
1771 let mut k = <Vec<u8>>::arbitrary(g);
1772 k.truncate(255);
1773 k.into_boxed_slice()
1774 },
1775 },
1776
1777 _ => unreachable!(),
1778 }
1779 }
1780}
1781
1782#[non_exhaustive]
1789#[allow(non_camel_case_types)]
1790#[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
1791pub enum Signature {
1792 RSA {
1794 s: MPI,
1796 },
1797
1798 DSA {
1800 r: MPI,
1802 s: MPI,
1804 },
1805
1806 ElGamal {
1808 r: MPI,
1810 s: MPI,
1812 },
1813
1814 EdDSA {
1816 r: MPI,
1818 s: MPI,
1820 },
1821
1822 ECDSA {
1824 r: MPI,
1826 s: MPI,
1828 },
1829
1830 Ed25519 {
1832 s: Box<[u8; 64]>,
1834 },
1835
1836 Ed448 {
1838 s: Box<[u8; 114]>,
1840 },
1841
1842 MLDSA65_Ed25519 {
1844 eddsa: Box<[u8; 64]>,
1846
1847 mldsa: Box<[u8; 3309]>,
1849 },
1850
1851 MLDSA87_Ed448 {
1853 eddsa: Box<[u8; 114]>,
1855
1856 mldsa: Box<[u8; 4627]>,
1858 },
1859
1860 SLHDSA128s {
1862 sig: Box<[u8; 7856]>,
1864 },
1865
1866 SLHDSA128f {
1868 sig: Box<[u8; 17088]>,
1870 },
1871
1872 SLHDSA256s {
1874 sig: Box<[u8; 29792]>,
1876 },
1877
1878 Unknown {
1880 mpis: Box<[MPI]>,
1882 rest: Box<[u8]>,
1884 },
1885}
1886assert_send_and_sync!(Signature);
1887
1888impl fmt::Debug for Signature {
1889 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1890 match self {
1891 Signature::RSA { s } =>
1892 f.debug_struct("RSA")
1893 .field("s", s)
1894 .finish(),
1895
1896 Signature::DSA { r, s } =>
1897 f.debug_struct("DSA")
1898 .field("r", r)
1899 .field("s", s)
1900 .finish(),
1901
1902 Signature::ElGamal { r, s } =>
1903 f.debug_struct("ElGamal")
1904 .field("r", r)
1905 .field("s", s)
1906 .finish(),
1907
1908 Signature::EdDSA { r, s } =>
1909 f.debug_struct("EdDSA")
1910 .field("r", r)
1911 .field("s", s)
1912 .finish(),
1913
1914 Signature::ECDSA { r, s } =>
1915 f.debug_struct("ECDSA")
1916 .field("r", r)
1917 .field("s", s)
1918 .finish(),
1919
1920 Signature::Ed25519 { s } =>
1921 f.debug_struct("Ed25519")
1922 .field("s", &hex::encode(&s[..]))
1923 .finish(),
1924
1925 Signature::Ed448 { s } =>
1926 f.debug_struct("Ed448")
1927 .field("s", &hex::encode(&s[..]))
1928 .finish(),
1929
1930 Signature::MLDSA65_Ed25519 { eddsa, mldsa } =>
1931 f.debug_struct("MLDSA65_Ed25519")
1932 .field("eddsa", &hex::encode(&eddsa[..]))
1933 .field("mldsa", &hex::encode(&mldsa[..]))
1934 .finish(),
1935
1936 Signature::MLDSA87_Ed448 { eddsa, mldsa } =>
1937 f.debug_struct("MLDSA87_Ed448")
1938 .field("eddsa", &hex::encode(&eddsa[..]))
1939 .field("mldsa", &hex::encode(&mldsa[..]))
1940 .finish(),
1941
1942 Signature::SLHDSA128s { sig } =>
1943 f.debug_struct("SLHDSA128s")
1944 .field("sig", &hex::encode(sig.as_ref()))
1945 .finish(),
1946
1947 Signature::SLHDSA128f { sig } =>
1948 f.debug_struct("SLHDSA128f")
1949 .field("sig", &hex::encode(sig.as_ref()))
1950 .finish(),
1951
1952 Signature::SLHDSA256s { sig } =>
1953 f.debug_struct("SLHDSA256s")
1954 .field("sig", &hex::encode(sig.as_ref()))
1955 .finish(),
1956
1957 Signature::Unknown { mpis, rest } =>
1958 f.debug_struct("Unknown")
1959 .field("mpis", mpis)
1960 .field("rest", &hex::encode(rest))
1961 .finish(),
1962 }
1963 }
1964}
1965
1966impl Hash for Signature {
1967 fn hash(&self, mut hash: &mut hash::Context) -> Result<()> {
1968 self.serialize(&mut hash as &mut dyn Write)
1969 }
1970}
1971
1972#[cfg(test)]
1973impl Arbitrary for Signature {
1974 fn arbitrary(g: &mut Gen) -> Self {
1975 use crate::arbitrary_helper::gen_arbitrary_from_range;
1976
1977 match gen_arbitrary_from_range(0..8, g) {
1978 0 => Signature::RSA {
1979 s: MPI::arbitrary(g),
1980 },
1981
1982 1 => Signature::DSA {
1983 r: MPI::arbitrary(g),
1984 s: MPI::arbitrary(g),
1985 },
1986
1987 2 => Signature::EdDSA {
1988 r: MPI::arbitrary(g),
1989 s: MPI::arbitrary(g),
1990 },
1991
1992 3 => Signature::ECDSA {
1993 r: MPI::arbitrary(g),
1994 s: MPI::arbitrary(g),
1995 },
1996
1997 4 => Signature::Ed25519 {
1998 s: Box::new(arbitrarize(g, [0; 64])),
1999 },
2000
2001 5 => Signature::Ed448 {
2002 s: Box::new(arbitrarize(g, [0; 114])),
2003 },
2004
2005 6 => Signature::MLDSA65_Ed25519 {
2006 eddsa: Box::new(arbitrarize(g, [0; 64])),
2007 mldsa: Box::new(arbitrarize(g, [0; 3309])),
2008 },
2009
2010 7 => Signature::MLDSA87_Ed448 {
2011 eddsa: Box::new(arbitrarize(g, [0; 114])),
2012 mldsa: Box::new(arbitrarize(g, [0; 4627])),
2013 },
2014
2015 _ => unreachable!(),
2016 }
2017 }
2018}
2019
2020#[cfg(test)]
2021mod tests {
2022 use super::*;
2023 use crate::parse::Parse;
2024
2025 quickcheck! {
2026 fn mpi_roundtrip(mpi: MPI) -> bool {
2027 let mut buf = Vec::new();
2028 mpi.serialize(&mut buf).unwrap();
2029 MPI::from_bytes(&buf).unwrap() == mpi
2030 }
2031 }
2032
2033 quickcheck! {
2034 fn pk_roundtrip(pk: PublicKey) -> bool {
2035 use std::io::Cursor;
2036
2037 let mut buf = Vec::new();
2038 pk.serialize(&mut buf).unwrap();
2039 let cur = Cursor::new(buf);
2040 let pk_ = PublicKey::parse(pk.algo().unwrap(), cur).unwrap();
2041
2042 pk == pk_
2043 }
2044 }
2045
2046 #[test]
2047 fn pk_bits() {
2048 for (name, key_no, bits) in &[
2049 ("testy.pgp", 0, 2048),
2050 ("testy-new.pgp", 1, 256),
2051 ("dennis-simon-anton.pgp", 0, 2048),
2052 ("dsa2048-elgamal3072.pgp", 1, 3072),
2053 ("emmelie-dorothea-dina-samantha-awina-ed25519.pgp", 0, 256),
2054 ("erika-corinna-daniela-simone-antonia-nistp256.pgp", 0, 256),
2055 ("erika-corinna-daniela-simone-antonia-nistp384.pgp", 0, 384),
2056 ("erika-corinna-daniela-simone-antonia-nistp521.pgp", 0, 521),
2057 ] {
2058 let cert = crate::Cert::from_bytes(crate::tests::key(name)).unwrap();
2059 let ka = cert.keys().nth(*key_no).unwrap();
2060 assert_eq!(ka.key().mpis().bits().unwrap(), *bits,
2061 "Cert {}, key no {}", name, *key_no);
2062 }
2063 }
2064
2065 quickcheck! {
2066 fn sk_roundtrip(sk: SecretKeyMaterial) -> bool {
2067 let mut buf = Vec::new();
2068 sk.serialize(&mut buf).unwrap();
2069 let sk_ =
2070 SecretKeyMaterial::from_bytes(sk.algo().unwrap(),
2071 &buf).unwrap();
2072
2073 sk == sk_
2074 }
2075 }
2076
2077 quickcheck! {
2078 fn ct_roundtrip(ct: Ciphertext) -> bool {
2079 use std::io::Cursor;
2080
2081 let mut buf = Vec::new();
2082 ct.serialize(&mut buf).unwrap();
2083 let cur = Cursor::new(buf);
2084 let ct_ = Ciphertext::parse(ct.pk_algo().unwrap(), cur).unwrap();
2085
2086 ct == ct_
2087 }
2088 }
2089
2090 quickcheck! {
2091 fn signature_roundtrip(sig: Signature) -> bool {
2092 use std::io::Cursor;
2093 use crate::PublicKeyAlgorithm::*;
2094
2095 let mut buf = Vec::new();
2096 sig.serialize(&mut buf).unwrap();
2097 let cur = Cursor::new(buf);
2098
2099 #[allow(deprecated)]
2100 let sig_ = match &sig {
2101 Signature::RSA { .. } =>
2102 Signature::parse(RSAEncryptSign, cur).unwrap(),
2103 Signature::DSA { .. } =>
2104 Signature::parse(DSA, cur).unwrap(),
2105 Signature::ElGamal { .. } =>
2106 Signature::parse(ElGamalEncryptSign, cur).unwrap(),
2107 Signature::EdDSA { .. } =>
2108 Signature::parse(EdDSA, cur).unwrap(),
2109 Signature::ECDSA { .. } =>
2110 Signature::parse(ECDSA, cur).unwrap(),
2111 Signature::Ed25519 { .. } =>
2112 Signature::parse(Ed25519, cur).unwrap(),
2113 Signature::Ed448 { .. } =>
2114 Signature::parse(Ed448, cur).unwrap(),
2115
2116 Signature::MLDSA65_Ed25519 { .. } =>
2117 Signature::parse(MLDSA65_Ed25519, cur).unwrap(),
2118 Signature::MLDSA87_Ed448 { .. } =>
2119 Signature::parse(MLDSA87_Ed448, cur).unwrap(),
2120
2121 Signature::SLHDSA128s { .. } =>
2122 Signature::parse(SLHDSA128s, cur).unwrap(),
2123 Signature::SLHDSA128f { .. } =>
2124 Signature::parse(SLHDSA128f, cur).unwrap(),
2125 Signature::SLHDSA256s { .. } =>
2126 Signature::parse(SLHDSA256s, cur).unwrap(),
2127
2128 Signature::Unknown { .. } => unreachable!(),
2129 };
2130
2131 sig == sig_
2132 }
2133 }
2134}