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 {
637 public: [u8; 32],
639 },
640
641 SLHDSA128f {
647 public: [u8; 32],
649 },
650
651 SLHDSA256s {
657 public: Box<[u8; 64]>,
659 },
660
661 MLKEM768_X25519 {
663 ecdh: Box<[u8; 32]>,
665
666 mlkem: Box<[u8; 1184]>,
668 },
669
670 MLKEM1024_X448 {
672 ecdh: Box<[u8; 56]>,
674
675 mlkem: Box<[u8; 1568]>,
677 },
678
679 Unknown {
681 mpis: Box<[MPI]>,
683 rest: Box<[u8]>,
685 },
686}
687assert_send_and_sync!(PublicKey);
688
689impl fmt::Debug for PublicKey {
690 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
691 match self {
692 PublicKey::RSA { e, n } =>
693 f.debug_struct("RSA")
694 .field("e", e)
695 .field("n", n)
696 .finish(),
697
698 PublicKey::DSA { p, q, g, y } =>
699 f.debug_struct("DSA")
700 .field("p", p)
701 .field("q", q)
702 .field("g", g)
703 .field("y", y)
704 .finish(),
705
706 PublicKey::ElGamal { p, g, y } =>
707 f.debug_struct("ElGamal")
708 .field("p", p)
709 .field("g", g)
710 .field("y", y)
711 .finish(),
712
713 PublicKey::EdDSA { curve, q } =>
714 f.debug_struct("EdDSA")
715 .field("curve", curve)
716 .field("q", q)
717 .finish(),
718
719 PublicKey::ECDSA { curve, q } =>
720 f.debug_struct("ECDSA")
721 .field("curve", curve)
722 .field("q", q)
723 .finish(),
724
725 PublicKey::ECDH { curve, q, hash, sym } =>
726 f.debug_struct("ECDH")
727 .field("curve", curve)
728 .field("q", q)
729 .field("hash", hash)
730 .field("sym", sym)
731 .finish(),
732
733 PublicKey::X25519 { u } =>
734 f.debug_struct("X25519")
735 .field("u", &hex::encode(u))
736 .finish(),
737
738 PublicKey::X448 { u } =>
739 f.debug_struct("X448")
740 .field("u", &hex::encode(u.as_ref()))
741 .finish(),
742
743 PublicKey::Ed25519 { a } =>
744 f.debug_struct("Ed25519")
745 .field("a", &hex::encode(a))
746 .finish(),
747
748 PublicKey::Ed448 { a } =>
749 f.debug_struct("Ed448")
750 .field("a", &hex::encode(a.as_ref()))
751 .finish(),
752
753 PublicKey::MLDSA65_Ed25519 { eddsa, mldsa } =>
754 f.debug_struct("MLDSA65_Ed25519")
755 .field("eddsa", &hex::encode(eddsa.as_ref()))
756 .field("mldsa", &hex::encode(mldsa.as_ref()))
757 .finish(),
758
759 PublicKey::MLDSA87_Ed448 { eddsa, mldsa } =>
760 f.debug_struct("MLDSA87_Ed448")
761 .field("eddsa", &hex::encode(eddsa.as_ref()))
762 .field("mldsa", &hex::encode(mldsa.as_ref()))
763 .finish(),
764
765 PublicKey::SLHDSA128s { public } =>
766 f.debug_struct("SLHDSA128s")
767 .field("public", &hex::encode(public))
768 .finish(),
769
770 PublicKey::SLHDSA128f { public } =>
771 f.debug_struct("SLHDSA128f")
772 .field("public", &hex::encode(public))
773 .finish(),
774
775 PublicKey::SLHDSA256s { public } =>
776 f.debug_struct("SLHDSA256s")
777 .field("public", &hex::encode(public.as_ref()))
778 .finish(),
779
780 PublicKey::MLKEM768_X25519 { ecdh, mlkem } =>
781 f.debug_struct("MLKEM768_X25519")
782 .field("ecdh", &hex::encode(ecdh.as_ref()))
783 .field("mlkem", &hex::encode(mlkem.as_ref()))
784 .finish(),
785
786 PublicKey::MLKEM1024_X448 { ecdh, mlkem } =>
787 f.debug_struct("MLKEM1024_X448")
788 .field("ecdh", &hex::encode(ecdh.as_ref()))
789 .field("mlkem", &hex::encode(mlkem.as_ref()))
790 .finish(),
791
792 PublicKey::Unknown { mpis, rest } =>
793 f.debug_struct("Unknown")
794 .field("mpis", mpis)
795 .field("rest", &hex::encode(rest))
796 .finish(),
797 }
798 }
799}
800
801impl PublicKey {
802 pub fn bits(&self) -> Option<usize> {
813 use self::PublicKey::*;
814 match self {
815 RSA { ref n,.. } => Some(n.bits()),
816 DSA { ref p,.. } => Some(p.bits()),
817 ElGamal { ref p,.. } => Some(p.bits()),
818 EdDSA { ref curve,.. } => curve.bits().ok(),
819 ECDSA { ref curve,.. } => curve.bits().ok(),
820 ECDH { ref curve,.. } => curve.bits().ok(),
821 X25519 { .. } => Some(256),
822 X448 { .. } => Some(448),
823 Ed25519 { .. } => Some(256),
824 Ed448 { .. } => Some(456),
825 MLDSA65_Ed25519 { .. } => None,
826 MLDSA87_Ed448 { .. } => None,
827 SLHDSA128s { .. } => None,
828 SLHDSA128f { .. } => None,
829 SLHDSA256s { .. } => None,
830 MLKEM768_X25519 { .. } => None,
831 MLKEM1024_X448 { .. } => None,
832 Unknown { .. } => None,
833 }
834 }
835
836 pub fn algo(&self) -> Option<PublicKeyAlgorithm> {
839 use self::PublicKey::*;
840 #[allow(deprecated)]
841 match self {
842 RSA { .. } => Some(PublicKeyAlgorithm::RSAEncryptSign),
843 DSA { .. } => Some(PublicKeyAlgorithm::DSA),
844 ElGamal { .. } => Some(PublicKeyAlgorithm::ElGamalEncrypt),
845 EdDSA { .. } => Some(PublicKeyAlgorithm::EdDSA),
846 ECDSA { .. } => Some(PublicKeyAlgorithm::ECDSA),
847 ECDH { .. } => Some(PublicKeyAlgorithm::ECDH),
848 X25519 { .. } => Some(PublicKeyAlgorithm::X25519),
849 X448 { .. } => Some(PublicKeyAlgorithm::X448),
850 Ed25519 { .. } => Some(PublicKeyAlgorithm::Ed25519),
851 Ed448 { .. } => Some(PublicKeyAlgorithm::Ed448),
852 MLDSA65_Ed25519 { .. } =>
853 Some(PublicKeyAlgorithm::MLDSA65_Ed25519),
854 MLDSA87_Ed448 { .. } =>
855 Some(PublicKeyAlgorithm::MLDSA87_Ed448),
856 SLHDSA128s { .. } => Some(PublicKeyAlgorithm::SLHDSA128s),
857 SLHDSA128f { .. } => Some(PublicKeyAlgorithm::SLHDSA128f),
858 SLHDSA256s { .. } => Some(PublicKeyAlgorithm::SLHDSA256s),
859 MLKEM768_X25519 { .. } =>
860 Some(PublicKeyAlgorithm::MLKEM768_X25519),
861 MLKEM1024_X448 { .. } =>
862 Some(PublicKeyAlgorithm::MLKEM1024_X448),
863 Unknown { .. } => None,
864 }
865 }
866}
867
868impl Hash for PublicKey {
869 fn hash(&self, mut hash: &mut hash::Context) -> Result<()> {
870 self.serialize(&mut hash as &mut dyn Write)
871 }
872}
873
874#[cfg(test)]
875impl Arbitrary for PublicKey {
876 fn arbitrary(g: &mut Gen) -> Self {
877 use self::PublicKey::*;
878 use crate::arbitrary_helper::gen_arbitrary_from_range;
879
880 match gen_arbitrary_from_range(0..17, g) {
881 0 => RSA {
882 e: MPI::arbitrary(g),
883 n: MPI::arbitrary(g),
884 },
885
886 1 => DSA {
887 p: MPI::arbitrary(g),
888 q: MPI::arbitrary(g),
889 g: MPI::arbitrary(g),
890 y: MPI::arbitrary(g),
891 },
892
893 2 => ElGamal {
894 p: MPI::arbitrary(g),
895 g: MPI::arbitrary(g),
896 y: MPI::arbitrary(g),
897 },
898
899 3 => EdDSA {
900 curve: Curve::arbitrary(g),
901 q: MPI::arbitrary(g),
902 },
903
904 4 => ECDSA {
905 curve: Curve::arbitrary(g),
906 q: MPI::arbitrary(g),
907 },
908
909 5 => ECDH {
910 curve: Curve::arbitrary(g),
911 q: MPI::arbitrary(g),
912 hash: HashAlgorithm::arbitrary(g),
913 sym: SymmetricAlgorithm::arbitrary(g),
914 },
915
916 6 => X25519 { u: arbitrary(g) },
917 7 => X448 { u: Box::new(arbitrarize(g, [0; 56])) },
918 8 => Ed25519 { a: arbitrary(g) },
919 9 => Ed448 { a: Box::new(arbitrarize(g, [0; 57])) },
920
921 10 => MLDSA65_Ed25519 {
922 eddsa: Box::new(arbitrarize(g, [0; 32])),
923 mldsa: Box::new(arbitrarize(g, [0; 1952])),
924 },
925
926 11 => MLDSA87_Ed448 {
927 eddsa: Box::new(arbitrarize(g, [0; 57])),
928 mldsa: Box::new(arbitrarize(g, [0; 2592])),
929 },
930
931 12 => SLHDSA128s {
932 public: arbitrary(g),
933 },
934
935 13 => SLHDSA128f {
936 public: arbitrary(g),
937 },
938
939 14 => SLHDSA256s {
940 public: Box::new(arbitrarize(g, [0; 64])),
941 },
942
943 15 => MLKEM768_X25519 {
944 ecdh: Box::new(arbitrarize(g, [0; 32])),
945 mlkem: Box::new(arbitrarize(g, [0; 1184])),
946 },
947
948 16 => MLKEM1024_X448 {
949 ecdh: Box::new(arbitrarize(g, [0; 56])),
950 mlkem: Box::new(arbitrarize(g, [0; 1568])),
951 },
952
953 _ => unreachable!(),
954 }
955 }
956}
957
958#[cfg(test)]
959pub(crate) fn arbitrarize<T: AsMut<[u8]>>(g: &mut Gen, mut a: T) -> T
960{
961 a.as_mut().iter_mut().for_each(|p| *p = Arbitrary::arbitrary(g));
962 a
963}
964
965#[cfg(test)]
966pub(crate) fn arbitrary<T: Default + AsMut<[u8]>>(g: &mut Gen) -> T
967{
968 arbitrarize(g, Default::default())
969}
970
971
972#[non_exhaustive]
982#[allow(non_camel_case_types)]
983#[allow(clippy::derived_hash_with_manual_eq)]
984#[derive(Clone, Hash)]
985pub enum SecretKeyMaterial {
986 RSA {
988 d: ProtectedMPI,
990 p: ProtectedMPI,
992 q: ProtectedMPI,
994 u: ProtectedMPI,
996 },
997
998 DSA {
1000 x: ProtectedMPI,
1002 },
1003
1004 ElGamal {
1006 x: ProtectedMPI,
1008 },
1009
1010 EdDSA {
1012 scalar: ProtectedMPI,
1014 },
1015
1016 ECDSA {
1018 scalar: ProtectedMPI,
1020 },
1021
1022 ECDH {
1024 scalar: ProtectedMPI,
1026 },
1027
1028 X25519 {
1030 x: Protected,
1032 },
1033
1034 X448 {
1036 x: Protected,
1038 },
1039
1040 Ed25519 {
1042 x: Protected,
1044 },
1045
1046 Ed448 {
1048 x: Protected,
1050 },
1051
1052 MLDSA65_Ed25519 {
1054 eddsa: Protected,
1056
1057 mldsa: Protected,
1059 },
1060
1061 MLDSA87_Ed448 {
1063 eddsa: Protected,
1065
1066 mldsa: Protected,
1068 },
1069
1070 SLHDSA128s {
1072 secret: Protected,
1074 },
1075
1076 SLHDSA128f {
1078 secret: Protected,
1080 },
1081
1082 SLHDSA256s {
1084 secret: Protected,
1086 },
1087
1088 MLKEM768_X25519 {
1090 ecdh: Protected,
1092
1093 mlkem: Protected,
1095 },
1096
1097 MLKEM1024_X448 {
1099 ecdh: Protected,
1101
1102 mlkem: Protected,
1104 },
1105
1106 Unknown {
1108 mpis: Box<[ProtectedMPI]>,
1110 rest: Protected,
1112 },
1113}
1114assert_send_and_sync!(SecretKeyMaterial);
1115
1116impl fmt::Debug for SecretKeyMaterial {
1117 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1118 if cfg!(debug_assertions) {
1119 match self {
1120 SecretKeyMaterial::RSA { d, p, q, u } =>
1121 f.debug_struct("RSA")
1122 .field("d", d)
1123 .field("p", p)
1124 .field("q", q)
1125 .field("u", u)
1126 .finish(),
1127
1128 SecretKeyMaterial::DSA { x } =>
1129 f.debug_struct("DSA")
1130 .field("x", x)
1131 .finish(),
1132
1133 SecretKeyMaterial::ElGamal { x } =>
1134 f.debug_struct("ElGamal")
1135 .field("x", x)
1136 .finish(),
1137
1138 SecretKeyMaterial::EdDSA { scalar } =>
1139 f.debug_struct("EdDSA")
1140 .field("scalar", scalar)
1141 .finish(),
1142
1143 SecretKeyMaterial::ECDSA { scalar } =>
1144 f.debug_struct("ECDSA")
1145 .field("scalar", scalar)
1146 .finish(),
1147
1148 SecretKeyMaterial::ECDH { scalar } =>
1149 f.debug_struct("ECDH")
1150 .field("scalar", scalar)
1151 .finish(),
1152
1153 SecretKeyMaterial::X25519 { x } =>
1154 f.debug_struct("X25519")
1155 .field("x", &hex::encode(x))
1156 .finish(),
1157
1158 SecretKeyMaterial::X448 { x } =>
1159 f.debug_struct("X448")
1160 .field("x", &hex::encode(x))
1161 .finish(),
1162
1163 SecretKeyMaterial::Ed25519 { x } =>
1164 f.debug_struct("Ed25519")
1165 .field("x", &hex::encode(x))
1166 .finish(),
1167
1168 SecretKeyMaterial::Ed448 { x } =>
1169 f.debug_struct("Ed448")
1170 .field("x", &hex::encode(x))
1171 .finish(),
1172
1173 SecretKeyMaterial::MLDSA65_Ed25519 { eddsa, mldsa } =>
1174 f.debug_struct("MLDSA65_Ed25519")
1175 .field("eddsa", &hex::encode(eddsa))
1176 .field("mldsa", &hex::encode(mldsa))
1177 .finish(),
1178
1179 SecretKeyMaterial::MLDSA87_Ed448 { eddsa, mldsa } =>
1180 f.debug_struct("MLDSA87_Ed448")
1181 .field("eddsa", &hex::encode(eddsa))
1182 .field("mldsa", &hex::encode(mldsa))
1183 .finish(),
1184
1185 SecretKeyMaterial::SLHDSA128s { secret } =>
1186 f.debug_struct("SLHDSA128s")
1187 .field("secret", &hex::encode(secret.as_ref()))
1188 .finish(),
1189
1190 SecretKeyMaterial::SLHDSA128f { secret } =>
1191 f.debug_struct("SLHDSA128f")
1192 .field("secret", &hex::encode(secret.as_ref()))
1193 .finish(),
1194
1195 SecretKeyMaterial::SLHDSA256s { secret } =>
1196 f.debug_struct("SLHDSA256s")
1197 .field("secret", &hex::encode(secret.as_ref()))
1198 .finish(),
1199
1200 SecretKeyMaterial::MLKEM768_X25519 { ecdh, mlkem } =>
1201 f.debug_struct("MLKEM768_X25519")
1202 .field("ecdh", &hex::encode(ecdh))
1203 .field("mlkem", &hex::encode(mlkem))
1204 .finish(),
1205
1206 SecretKeyMaterial::MLKEM1024_X448 { ecdh, mlkem } =>
1207 f.debug_struct("MLKEM1024_X448")
1208 .field("ecdh", &hex::encode(ecdh))
1209 .field("mlkem", &hex::encode(mlkem))
1210 .finish(),
1211
1212 SecretKeyMaterial::Unknown{ mpis, rest } =>
1213 f.debug_struct("Unknown")
1214 .field("mpis", mpis)
1215 .field("rest", &hex::encode(rest))
1216 .finish(),
1217 }
1218 } else {
1219 match self {
1220 SecretKeyMaterial::RSA{ .. } =>
1221 f.write_str("RSA { <Redacted> }"),
1222 SecretKeyMaterial::DSA{ .. } =>
1223 f.write_str("DSA { <Redacted> }"),
1224 SecretKeyMaterial::ElGamal{ .. } =>
1225 f.write_str("ElGamal { <Redacted> }"),
1226 SecretKeyMaterial::EdDSA{ .. } =>
1227 f.write_str("EdDSA { <Redacted> }"),
1228 SecretKeyMaterial::ECDSA{ .. } =>
1229 f.write_str("ECDSA { <Redacted> }"),
1230 SecretKeyMaterial::ECDH{ .. } =>
1231 f.write_str("ECDH { <Redacted> }"),
1232 SecretKeyMaterial::X25519 { .. } =>
1233 f.write_str("X25519 { <Redacted> }"),
1234 SecretKeyMaterial::X448 { .. } =>
1235 f.write_str("X448 { <Redacted> }"),
1236 SecretKeyMaterial::Ed25519 { .. } =>
1237 f.write_str("Ed25519 { <Redacted> }"),
1238 SecretKeyMaterial::Ed448 { .. } =>
1239 f.write_str("Ed448 { <Redacted> }"),
1240 SecretKeyMaterial::MLDSA65_Ed25519 { .. } =>
1241 f.write_str("MLDSA65_Ed25519 { <Redacted> }"),
1242 SecretKeyMaterial::MLDSA87_Ed448 { .. } =>
1243 f.write_str("MLDSA87_Ed448 { <Redacted> }"),
1244 SecretKeyMaterial::SLHDSA128s { .. } =>
1245 f.write_str("SLHDSA128s { <Redacted> }"),
1246 SecretKeyMaterial::SLHDSA128f { .. } =>
1247 f.write_str("SLHDSA128f { <Redacted> }"),
1248 SecretKeyMaterial::SLHDSA256s { .. } =>
1249 f.write_str("SLHDSA256s { <Redacted> }"),
1250 SecretKeyMaterial::MLKEM768_X25519 { .. } =>
1251 f.write_str("MLKEM768_X25519 { <Redacted> }"),
1252 SecretKeyMaterial::MLKEM1024_X448 { .. } =>
1253 f.write_str("MLKEM1024_X448 { <Redacted> }"),
1254 SecretKeyMaterial::Unknown{ .. } =>
1255 f.write_str("Unknown { <Redacted> }"),
1256 }
1257 }
1258 }
1259}
1260
1261impl PartialOrd for SecretKeyMaterial {
1262 fn partial_cmp(&self, other: &SecretKeyMaterial) -> Option<Ordering> {
1263 Some(self.cmp(other))
1264 }
1265}
1266
1267impl Ord for SecretKeyMaterial {
1268 fn cmp(&self, other: &Self) -> Ordering {
1269 use std::iter;
1270
1271 fn discriminant(sk: &SecretKeyMaterial) -> usize {
1272 match sk {
1273 SecretKeyMaterial::RSA{ .. } => 0,
1274 SecretKeyMaterial::DSA{ .. } => 1,
1275 SecretKeyMaterial::ElGamal{ .. } => 2,
1276 SecretKeyMaterial::EdDSA{ .. } => 3,
1277 SecretKeyMaterial::ECDSA{ .. } => 4,
1278 SecretKeyMaterial::ECDH{ .. } => 5,
1279 SecretKeyMaterial::X25519 { .. } => 6,
1280 SecretKeyMaterial::X448 { .. } => 7,
1281 SecretKeyMaterial::Ed25519 { .. } => 8,
1282 SecretKeyMaterial::Ed448 { .. } => 9,
1283 SecretKeyMaterial::Unknown { .. } => 10,
1284 SecretKeyMaterial::MLDSA65_Ed25519 { .. } => 11,
1285 SecretKeyMaterial::MLDSA87_Ed448 { .. } => 12,
1286 SecretKeyMaterial::SLHDSA128s { .. } => 13,
1287 SecretKeyMaterial::SLHDSA128f { .. } => 14,
1288 SecretKeyMaterial::SLHDSA256s { .. } => 15,
1289 SecretKeyMaterial::MLKEM768_X25519 { .. } => 16,
1290 SecretKeyMaterial::MLKEM1024_X448 { .. } => 17,
1291 }
1292 }
1293
1294 let ret = match (self, other) {
1295 (&SecretKeyMaterial::RSA{ d: ref d1, p: ref p1, q: ref q1, u: ref u1 }
1296 ,&SecretKeyMaterial::RSA{ d: ref d2, p: ref p2, q: ref q2, u: ref u2 }) => {
1297 let o1 = d1.cmp(d2);
1298 let o2 = p1.cmp(p2);
1299 let o3 = q1.cmp(q2);
1300 let o4 = u1.cmp(u2);
1301
1302 if o1 != Ordering::Equal { return o1; }
1303 if o2 != Ordering::Equal { return o2; }
1304 if o3 != Ordering::Equal { return o3; }
1305 o4
1306 }
1307 (&SecretKeyMaterial::DSA{ x: ref x1 }
1308 ,&SecretKeyMaterial::DSA{ x: ref x2 }) => {
1309 x1.cmp(x2)
1310 }
1311 (&SecretKeyMaterial::ElGamal{ x: ref x1 }
1312 ,&SecretKeyMaterial::ElGamal{ x: ref x2 }) => {
1313 x1.cmp(x2)
1314 }
1315 (&SecretKeyMaterial::EdDSA{ scalar: ref scalar1 }
1316 ,&SecretKeyMaterial::EdDSA{ scalar: ref scalar2 }) => {
1317 scalar1.cmp(scalar2)
1318 }
1319 (&SecretKeyMaterial::ECDSA{ scalar: ref scalar1 }
1320 ,&SecretKeyMaterial::ECDSA{ scalar: ref scalar2 }) => {
1321 scalar1.cmp(scalar2)
1322 }
1323 (&SecretKeyMaterial::ECDH{ scalar: ref scalar1 }
1324 ,&SecretKeyMaterial::ECDH{ scalar: ref scalar2 }) => {
1325 scalar1.cmp(scalar2)
1326 }
1327 (SecretKeyMaterial::X25519 { x: x0 },
1328 SecretKeyMaterial::X25519 { x: x1 }) => x0.cmp(x1),
1329 (SecretKeyMaterial::X448 { x: x0 },
1330 SecretKeyMaterial::X448 { x: x1 }) => x0.cmp(x1),
1331 (SecretKeyMaterial::Ed25519 { x: x0 },
1332 SecretKeyMaterial::Ed25519 { x: x1 }) => x0.cmp(x1),
1333 (SecretKeyMaterial::Ed448 { x: x0 },
1334 SecretKeyMaterial::Ed448 { x: x1 }) => x0.cmp(x1),
1335
1336 (SecretKeyMaterial::MLDSA65_Ed25519 { eddsa: e0, mldsa: m0 },
1337 SecretKeyMaterial::MLDSA65_Ed25519 { eddsa: e1, mldsa: m1 }) =>
1338 iter::once(e0.cmp(e1))
1339 .chain(iter::once(m0.cmp(m1)))
1340 .fold(Ordering::Equal, |acc, x| acc.then(x)),
1341
1342 (SecretKeyMaterial::MLDSA87_Ed448 { eddsa: e0, mldsa: m0 },
1343 SecretKeyMaterial::MLDSA87_Ed448 { eddsa: e1, mldsa: m1 }) =>
1344 iter::once(e0.cmp(e1))
1345 .chain(iter::once(m0.cmp(m1)))
1346 .fold(Ordering::Equal, |acc, x| acc.then(x)),
1347
1348 (SecretKeyMaterial::SLHDSA128s { secret: s0 },
1349 SecretKeyMaterial::SLHDSA128s { secret: s1 }) => s0.cmp(s1),
1350
1351 (SecretKeyMaterial::SLHDSA128f { secret: s0 },
1352 SecretKeyMaterial::SLHDSA128f { secret: s1 }) => s0.cmp(s1),
1353
1354 (SecretKeyMaterial::SLHDSA256s { secret: s0 },
1355 SecretKeyMaterial::SLHDSA256s { secret: s1 }) => s0.cmp(s1),
1356
1357 (SecretKeyMaterial::MLKEM768_X25519 { ecdh: e0, mlkem: m0 },
1358 SecretKeyMaterial::MLKEM768_X25519 { ecdh: e1, mlkem: m1 }) =>
1359 iter::once(e0.cmp(e1))
1360 .chain(iter::once(m0.cmp(m1)))
1361 .fold(Ordering::Equal, |acc, x| acc.then(x)),
1362
1363 (SecretKeyMaterial::MLKEM1024_X448 { ecdh: e0, mlkem: m0 },
1364 SecretKeyMaterial::MLKEM1024_X448 { ecdh: e1, mlkem: m1 }) =>
1365 iter::once(e0.cmp(e1))
1366 .chain(iter::once(m0.cmp(m1)))
1367 .fold(Ordering::Equal, |acc, x| acc.then(x)),
1368
1369 (&SecretKeyMaterial::Unknown{ mpis: ref mpis1, rest: ref rest1 }
1370 ,&SecretKeyMaterial::Unknown{ mpis: ref mpis2, rest: ref rest2 }) => {
1371 let o1 = secure_cmp(rest1, rest2);
1372 let o2 = mpis1.len().cmp(&mpis2.len());
1373 let on = mpis1.iter().zip(mpis2.iter()).map(|(a,b)| {
1374 a.cmp(b)
1375 }).collect::<Vec<_>>();
1376
1377 iter::once(o1)
1378 .chain(iter::once(o2))
1379 .chain(on.iter().cloned())
1380 .fold(Ordering::Equal, |acc, x| acc.then(x))
1381 }
1382
1383 (a, b) => {
1384 let ret = discriminant(a).cmp(&discriminant(b));
1385
1386 assert!(ret != Ordering::Equal);
1387 ret
1388 }
1389 };
1390
1391 ret
1392 }
1393}
1394
1395impl PartialEq for SecretKeyMaterial {
1396 fn eq(&self, other: &Self) -> bool { self.cmp(other) == Ordering::Equal }
1397}
1398
1399impl Eq for SecretKeyMaterial {}
1400
1401impl SecretKeyMaterial {
1402 pub fn algo(&self) -> Option<PublicKeyAlgorithm> {
1405 use self::SecretKeyMaterial::*;
1406 #[allow(deprecated)]
1407 match self {
1408 RSA { .. } => Some(PublicKeyAlgorithm::RSAEncryptSign),
1409 DSA { .. } => Some(PublicKeyAlgorithm::DSA),
1410 ElGamal { .. } => Some(PublicKeyAlgorithm::ElGamalEncrypt),
1411 EdDSA { .. } => Some(PublicKeyAlgorithm::EdDSA),
1412 ECDSA { .. } => Some(PublicKeyAlgorithm::ECDSA),
1413 ECDH { .. } => Some(PublicKeyAlgorithm::ECDH),
1414 X25519 { .. } => Some(PublicKeyAlgorithm::X25519),
1415 X448 { .. } => Some(PublicKeyAlgorithm::X448),
1416 Ed25519 { .. } => Some(PublicKeyAlgorithm::Ed25519),
1417 Ed448 { .. } => Some(PublicKeyAlgorithm::Ed448),
1418 MLDSA65_Ed25519 { .. } => Some(PublicKeyAlgorithm::MLDSA65_Ed25519),
1419 MLDSA87_Ed448 { .. } => Some(PublicKeyAlgorithm::MLDSA87_Ed448),
1420 SLHDSA128s { .. } => Some(PublicKeyAlgorithm::SLHDSA128s),
1421 SLHDSA128f { .. } => Some(PublicKeyAlgorithm::SLHDSA128f),
1422 SLHDSA256s { .. } => Some(PublicKeyAlgorithm::SLHDSA256s),
1423 MLKEM768_X25519 { .. } => Some(PublicKeyAlgorithm::MLKEM768_X25519),
1424 MLKEM1024_X448 { .. } => Some(PublicKeyAlgorithm::MLKEM1024_X448),
1425 Unknown { .. } => None,
1426 }
1427 }
1428}
1429
1430impl Hash for SecretKeyMaterial {
1431 fn hash(&self, mut hash: &mut hash::Context) -> Result<()> {
1432 self.serialize(&mut hash as &mut dyn Write)
1433 }
1434}
1435
1436#[cfg(test)]
1437impl SecretKeyMaterial {
1438 pub(crate) fn arbitrary_for(g: &mut Gen, pk: PublicKeyAlgorithm) -> Result<Self> {
1439 use self::PublicKeyAlgorithm::*;
1440 #[allow(deprecated)]
1441 match pk {
1442 RSAEncryptSign | RSASign | RSAEncrypt => Ok(SecretKeyMaterial::RSA {
1443 d: ProtectedMPI::arbitrary(g),
1444 p: ProtectedMPI::arbitrary(g),
1445 q: ProtectedMPI::arbitrary(g),
1446 u: ProtectedMPI::arbitrary(g),
1447 }),
1448
1449 DSA => Ok(SecretKeyMaterial::DSA {
1450 x: ProtectedMPI::arbitrary(g),
1451 }),
1452
1453 ElGamalEncryptSign | ElGamalEncrypt => Ok(SecretKeyMaterial::ElGamal {
1454 x: ProtectedMPI::arbitrary(g),
1455 }),
1456
1457 EdDSA => Ok(SecretKeyMaterial::EdDSA {
1458 scalar: ProtectedMPI::arbitrary(g),
1459 }),
1460
1461 ECDSA => Ok(SecretKeyMaterial::ECDSA {
1462 scalar: ProtectedMPI::arbitrary(g),
1463 }),
1464
1465 ECDH => Ok(SecretKeyMaterial::ECDH {
1466 scalar: ProtectedMPI::arbitrary(g),
1467 }),
1468
1469 X25519 => Ok(SecretKeyMaterial::X25519 {
1470 x: arbitrarize(g, vec![0; 32]).into(),
1471 }),
1472 X448 => Ok(SecretKeyMaterial::X448 {
1473 x: arbitrarize(g, vec![0; 56]).into(),
1474 }),
1475 Ed25519 => Ok(SecretKeyMaterial::Ed25519 {
1476 x: arbitrarize(g, vec![0; 32]).into(),
1477 }),
1478 Ed448 => Ok(SecretKeyMaterial::Ed448 {
1479 x: arbitrarize(g, vec![0; 57]).into(),
1480 }),
1481
1482 MLDSA65_Ed25519 => Ok(SecretKeyMaterial::MLDSA65_Ed25519 {
1483 eddsa: arbitrarize(g, vec![0; 32]).into(),
1484 mldsa: arbitrarize(g, vec![0; 32]).into(),
1485 }),
1486
1487 MLDSA87_Ed448 => Ok(SecretKeyMaterial::MLDSA87_Ed448 {
1488 eddsa: arbitrarize(g, vec![0; 57]).into(),
1489 mldsa: arbitrarize(g, vec![0; 32]).into(),
1490 }),
1491
1492 SLHDSA128s => Ok(SecretKeyMaterial::SLHDSA128s {
1493 secret: arbitrarize(g, [0; 64]).into(),
1494 }),
1495
1496 SLHDSA128f => Ok(SecretKeyMaterial::SLHDSA128f {
1497 secret: arbitrarize(g, [0; 64]).into(),
1498 }),
1499
1500 SLHDSA256s => Ok(SecretKeyMaterial::SLHDSA256s {
1501 secret: arbitrarize(g, [0; 128]).into(),
1502 }),
1503
1504 MLKEM768_X25519 => Ok(SecretKeyMaterial::MLKEM768_X25519 {
1505 ecdh: arbitrarize(g, vec![0; 32]).into(),
1506 mlkem: arbitrarize(g, vec![0; 64]).into(),
1507 }),
1508
1509 MLKEM1024_X448 => Ok(SecretKeyMaterial::MLKEM1024_X448 {
1510 ecdh: arbitrarize(g, vec![0; 56]).into(),
1511 mlkem: arbitrarize(g, vec![0; 64]).into(),
1512 }),
1513
1514 Private(_) | Unknown(_) =>
1515 Err(Error::UnsupportedPublicKeyAlgorithm(pk).into()),
1516 }
1517 }
1518}
1519#[cfg(test)]
1520impl Arbitrary for SecretKeyMaterial {
1521 fn arbitrary(g: &mut Gen) -> Self {
1522 let pk = *g.choose(
1523 &crate::crypto::types::public_key_algorithm::PUBLIC_KEY_ALGORITHM_VARIANTS)
1524 .expect("not empty");
1525 Self::arbitrary_for(g, pk).expect("only known variants")
1526 }
1527}
1528
1529#[derive(PartialEq, Eq, Hash, Clone, Copy, Debug)]
1536pub enum SecretKeyChecksum {
1537 SHA1,
1539
1540 Sum16,
1542}
1543assert_send_and_sync!(SecretKeyChecksum);
1544
1545impl Default for SecretKeyChecksum {
1546 fn default() -> Self {
1547 SecretKeyChecksum::SHA1
1548 }
1549}
1550
1551impl SecretKeyChecksum {
1552 pub(crate) fn len(&self) -> usize {
1554 match self {
1555 SecretKeyChecksum::SHA1 => 20,
1556 SecretKeyChecksum::Sum16 => 2,
1557 }
1558 }
1559}
1560
1561#[non_exhaustive]
1568#[allow(non_camel_case_types)]
1569#[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
1570pub enum Ciphertext {
1571 RSA {
1573 c: MPI,
1575 },
1576
1577 ElGamal {
1579 e: MPI,
1581 c: MPI,
1583 },
1584
1585 ECDH {
1587 e: MPI,
1589 key: Box<[u8]>,
1591 },
1592
1593 X25519 {
1595 e: Box<[u8; 32]>,
1597 key: Box<[u8]>,
1599 },
1600
1601 X448 {
1603 e: Box<[u8; 56]>,
1605 key: Box<[u8]>,
1607 },
1608
1609 MLKEM768_X25519 {
1611 ecdh: Box<[u8; 32]>,
1613
1614 mlkem: Box<[u8; 1088]>,
1616
1617 esk: Box<[u8]>,
1619 },
1620
1621 MLKEM1024_X448 {
1623 ecdh: Box<[u8; 56]>,
1625
1626 mlkem: Box<[u8; 1568]>,
1628
1629 esk: Box<[u8]>,
1631 },
1632
1633 Unknown {
1635 mpis: Box<[MPI]>,
1637 rest: Box<[u8]>,
1639 },
1640}
1641assert_send_and_sync!(Ciphertext);
1642
1643impl fmt::Debug for Ciphertext {
1644 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1645 match self {
1646 Ciphertext::RSA { c } =>
1647 f.debug_struct("RSA")
1648 .field("c", c)
1649 .finish(),
1650
1651 Ciphertext::ElGamal { e, c } =>
1652 f.debug_struct("ElGamal")
1653 .field("e", e)
1654 .field("c", c)
1655 .finish(),
1656
1657 Ciphertext::ECDH { e, key } =>
1658 f.debug_struct("ECDH")
1659 .field("e", e)
1660 .field("key", &hex::encode(key))
1661 .finish(),
1662
1663 Ciphertext::X25519 { e, key } =>
1664 f.debug_struct("X25519")
1665 .field("e", &hex::encode(&e[..]))
1666 .field("key", &hex::encode(key))
1667 .finish(),
1668
1669 Ciphertext::X448 { e, key } =>
1670 f.debug_struct("X448")
1671 .field("e", &hex::encode(&e[..]))
1672 .field("key", &hex::encode(key))
1673 .finish(),
1674
1675 Ciphertext::MLKEM768_X25519 { ecdh, mlkem, esk } =>
1676 f.debug_struct("MLKEM768_X25519")
1677 .field("ecdh", &hex::encode(&ecdh[..]))
1678 .field("mlkem", &hex::encode(&mlkem[..]))
1679 .field("esk", &hex::encode(esk))
1680 .finish(),
1681
1682 Ciphertext::MLKEM1024_X448 { ecdh, mlkem, esk } =>
1683 f.debug_struct("MLKEM1024_X448")
1684 .field("ecdh", &hex::encode(&ecdh[..]))
1685 .field("mlkem", &hex::encode(&mlkem[..]))
1686 .field("esk", &hex::encode(esk))
1687 .finish(),
1688
1689 Ciphertext::Unknown { mpis, rest } =>
1690 f.debug_struct("Unknown")
1691 .field("mpis", mpis)
1692 .field("rest", &hex::encode(rest))
1693 .finish(),
1694 }
1695 }
1696}
1697
1698impl Ciphertext {
1699 pub fn pk_algo(&self) -> Option<PublicKeyAlgorithm> {
1702 use self::Ciphertext::*;
1703
1704 #[allow(deprecated)]
1708 match self {
1709 RSA { .. } => Some(PublicKeyAlgorithm::RSAEncryptSign),
1710 ElGamal { .. } => Some(PublicKeyAlgorithm::ElGamalEncrypt),
1711 ECDH { .. } => Some(PublicKeyAlgorithm::ECDH),
1712 X25519 { .. } => Some(PublicKeyAlgorithm::X25519),
1713 X448 { .. } => Some(PublicKeyAlgorithm::X448),
1714 MLKEM768_X25519 { .. } => Some(PublicKeyAlgorithm::MLKEM768_X25519),
1715 MLKEM1024_X448 { .. } => Some(PublicKeyAlgorithm::MLKEM1024_X448),
1716 Unknown { .. } => None,
1717 }
1718 }
1719}
1720
1721impl Hash for Ciphertext {
1722 fn hash(&self, mut hash: &mut hash::Context) -> Result<()> {
1723 self.serialize(&mut hash as &mut dyn Write)
1724 }
1725}
1726
1727#[cfg(test)]
1728impl Arbitrary for Ciphertext {
1729 fn arbitrary(g: &mut Gen) -> Self {
1730 use crate::arbitrary_helper::gen_arbitrary_from_range;
1731
1732 match gen_arbitrary_from_range(0..7, g) {
1733 0 => Ciphertext::RSA {
1734 c: MPI::arbitrary(g),
1735 },
1736
1737 1 => Ciphertext::ElGamal {
1738 e: MPI::arbitrary(g),
1739 c: MPI::arbitrary(g)
1740 },
1741
1742 2 => Ciphertext::ECDH {
1743 e: MPI::arbitrary(g),
1744 key: {
1745 let mut k = <Vec<u8>>::arbitrary(g);
1746 k.truncate(255);
1747 k.into_boxed_slice()
1748 },
1749 },
1750
1751 3 => Ciphertext::X25519 {
1752 e: Box::new(arbitrary(g)),
1753 key: {
1754 let mut k = <Vec<u8>>::arbitrary(g);
1755 k.truncate(255);
1756 k.into_boxed_slice()
1757 },
1758 },
1759
1760 4 => Ciphertext::X448 {
1761 e: Box::new(arbitrarize(g, [0; 56])),
1762 key: {
1763 let mut k = <Vec<u8>>::arbitrary(g);
1764 k.truncate(255);
1765 k.into_boxed_slice()
1766 },
1767 },
1768
1769 5 => Ciphertext::MLKEM768_X25519 {
1770 ecdh: Box::new(arbitrarize(g, [0; 32])),
1771 mlkem: Box::new(arbitrarize(g, [0; 1088])),
1772 esk: {
1773 let mut k = <Vec<u8>>::arbitrary(g);
1774 k.truncate(255);
1775 k.into_boxed_slice()
1776 },
1777 },
1778
1779 6 => Ciphertext::MLKEM1024_X448 {
1780 ecdh: Box::new(arbitrarize(g, [0; 56])),
1781 mlkem: Box::new(arbitrarize(g, [0; 1568])),
1782 esk: {
1783 let mut k = <Vec<u8>>::arbitrary(g);
1784 k.truncate(255);
1785 k.into_boxed_slice()
1786 },
1787 },
1788
1789 _ => unreachable!(),
1790 }
1791 }
1792}
1793
1794#[non_exhaustive]
1801#[allow(non_camel_case_types)]
1802#[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
1803pub enum Signature {
1804 RSA {
1806 s: MPI,
1808 },
1809
1810 DSA {
1812 r: MPI,
1814 s: MPI,
1816 },
1817
1818 ElGamal {
1820 r: MPI,
1822 s: MPI,
1824 },
1825
1826 EdDSA {
1828 r: MPI,
1830 s: MPI,
1832 },
1833
1834 ECDSA {
1836 r: MPI,
1838 s: MPI,
1840 },
1841
1842 Ed25519 {
1844 s: Box<[u8; 64]>,
1846 },
1847
1848 Ed448 {
1850 s: Box<[u8; 114]>,
1852 },
1853
1854 MLDSA65_Ed25519 {
1856 eddsa: Box<[u8; 64]>,
1858
1859 mldsa: Box<[u8; 3309]>,
1861 },
1862
1863 MLDSA87_Ed448 {
1865 eddsa: Box<[u8; 114]>,
1867
1868 mldsa: Box<[u8; 4627]>,
1870 },
1871
1872 SLHDSA128s {
1878 sig: Box<[u8; 7856]>,
1880 },
1881
1882 SLHDSA128f {
1888 sig: Box<[u8; 17088]>,
1890 },
1891
1892 SLHDSA256s {
1898 sig: Box<[u8; 29792]>,
1900 },
1901
1902 Unknown {
1904 mpis: Box<[MPI]>,
1906 rest: Box<[u8]>,
1908 },
1909}
1910assert_send_and_sync!(Signature);
1911
1912impl fmt::Debug for Signature {
1913 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1914 match self {
1915 Signature::RSA { s } =>
1916 f.debug_struct("RSA")
1917 .field("s", s)
1918 .finish(),
1919
1920 Signature::DSA { r, s } =>
1921 f.debug_struct("DSA")
1922 .field("r", r)
1923 .field("s", s)
1924 .finish(),
1925
1926 Signature::ElGamal { r, s } =>
1927 f.debug_struct("ElGamal")
1928 .field("r", r)
1929 .field("s", s)
1930 .finish(),
1931
1932 Signature::EdDSA { r, s } =>
1933 f.debug_struct("EdDSA")
1934 .field("r", r)
1935 .field("s", s)
1936 .finish(),
1937
1938 Signature::ECDSA { r, s } =>
1939 f.debug_struct("ECDSA")
1940 .field("r", r)
1941 .field("s", s)
1942 .finish(),
1943
1944 Signature::Ed25519 { s } =>
1945 f.debug_struct("Ed25519")
1946 .field("s", &hex::encode(&s[..]))
1947 .finish(),
1948
1949 Signature::Ed448 { s } =>
1950 f.debug_struct("Ed448")
1951 .field("s", &hex::encode(&s[..]))
1952 .finish(),
1953
1954 Signature::MLDSA65_Ed25519 { eddsa, mldsa } =>
1955 f.debug_struct("MLDSA65_Ed25519")
1956 .field("eddsa", &hex::encode(&eddsa[..]))
1957 .field("mldsa", &hex::encode(&mldsa[..]))
1958 .finish(),
1959
1960 Signature::MLDSA87_Ed448 { eddsa, mldsa } =>
1961 f.debug_struct("MLDSA87_Ed448")
1962 .field("eddsa", &hex::encode(&eddsa[..]))
1963 .field("mldsa", &hex::encode(&mldsa[..]))
1964 .finish(),
1965
1966 Signature::SLHDSA128s { sig } =>
1967 f.debug_struct("SLHDSA128s")
1968 .field("sig", &hex::encode(sig.as_ref()))
1969 .finish(),
1970
1971 Signature::SLHDSA128f { sig } =>
1972 f.debug_struct("SLHDSA128f")
1973 .field("sig", &hex::encode(sig.as_ref()))
1974 .finish(),
1975
1976 Signature::SLHDSA256s { sig } =>
1977 f.debug_struct("SLHDSA256s")
1978 .field("sig", &hex::encode(sig.as_ref()))
1979 .finish(),
1980
1981 Signature::Unknown { mpis, rest } =>
1982 f.debug_struct("Unknown")
1983 .field("mpis", mpis)
1984 .field("rest", &hex::encode(rest))
1985 .finish(),
1986 }
1987 }
1988}
1989
1990impl Hash for Signature {
1991 fn hash(&self, mut hash: &mut hash::Context) -> Result<()> {
1992 self.serialize(&mut hash as &mut dyn Write)
1993 }
1994}
1995
1996#[cfg(test)]
1997impl Arbitrary for Signature {
1998 fn arbitrary(g: &mut Gen) -> Self {
1999 use crate::arbitrary_helper::gen_arbitrary_from_range;
2000
2001 match gen_arbitrary_from_range(0..8, g) {
2002 0 => Signature::RSA {
2003 s: MPI::arbitrary(g),
2004 },
2005
2006 1 => Signature::DSA {
2007 r: MPI::arbitrary(g),
2008 s: MPI::arbitrary(g),
2009 },
2010
2011 2 => Signature::EdDSA {
2012 r: MPI::arbitrary(g),
2013 s: MPI::arbitrary(g),
2014 },
2015
2016 3 => Signature::ECDSA {
2017 r: MPI::arbitrary(g),
2018 s: MPI::arbitrary(g),
2019 },
2020
2021 4 => Signature::Ed25519 {
2022 s: Box::new(arbitrarize(g, [0; 64])),
2023 },
2024
2025 5 => Signature::Ed448 {
2026 s: Box::new(arbitrarize(g, [0; 114])),
2027 },
2028
2029 6 => Signature::MLDSA65_Ed25519 {
2030 eddsa: Box::new(arbitrarize(g, [0; 64])),
2031 mldsa: Box::new(arbitrarize(g, [0; 3309])),
2032 },
2033
2034 7 => Signature::MLDSA87_Ed448 {
2035 eddsa: Box::new(arbitrarize(g, [0; 114])),
2036 mldsa: Box::new(arbitrarize(g, [0; 4627])),
2037 },
2038
2039 _ => unreachable!(),
2040 }
2041 }
2042}
2043
2044#[cfg(test)]
2045mod tests {
2046 use super::*;
2047 use crate::parse::Parse;
2048
2049 quickcheck! {
2050 fn mpi_roundtrip(mpi: MPI) -> bool {
2051 let mut buf = Vec::new();
2052 mpi.serialize(&mut buf).unwrap();
2053 MPI::from_bytes(&buf).unwrap() == mpi
2054 }
2055 }
2056
2057 quickcheck! {
2058 fn pk_roundtrip(pk: PublicKey) -> bool {
2059 use std::io::Cursor;
2060
2061 let mut buf = Vec::new();
2062 pk.serialize(&mut buf).unwrap();
2063 let cur = Cursor::new(buf);
2064 let pk_ = PublicKey::parse(pk.algo().unwrap(), cur).unwrap();
2065
2066 pk == pk_
2067 }
2068 }
2069
2070 #[test]
2071 fn pk_bits() {
2072 for (name, key_no, bits) in &[
2073 ("testy.pgp", 0, 2048),
2074 ("testy-new.pgp", 1, 256),
2075 ("dennis-simon-anton.pgp", 0, 2048),
2076 ("dsa2048-elgamal3072.pgp", 1, 3072),
2077 ("emmelie-dorothea-dina-samantha-awina-ed25519.pgp", 0, 256),
2078 ("erika-corinna-daniela-simone-antonia-nistp256.pgp", 0, 256),
2079 ("erika-corinna-daniela-simone-antonia-nistp384.pgp", 0, 384),
2080 ("erika-corinna-daniela-simone-antonia-nistp521.pgp", 0, 521),
2081 ] {
2082 let cert = crate::Cert::from_bytes(crate::tests::key(name)).unwrap();
2083 let ka = cert.keys().nth(*key_no).unwrap();
2084 assert_eq!(ka.key().mpis().bits().unwrap(), *bits,
2085 "Cert {}, key no {}", name, *key_no);
2086 }
2087 }
2088
2089 quickcheck! {
2090 fn sk_roundtrip(sk: SecretKeyMaterial) -> bool {
2091 let mut buf = Vec::new();
2092 sk.serialize(&mut buf).unwrap();
2093 let sk_ =
2094 SecretKeyMaterial::from_bytes(sk.algo().unwrap(),
2095 &buf).unwrap();
2096
2097 sk == sk_
2098 }
2099 }
2100
2101 quickcheck! {
2102 fn ct_roundtrip(ct: Ciphertext) -> bool {
2103 use std::io::Cursor;
2104
2105 let mut buf = Vec::new();
2106 ct.serialize(&mut buf).unwrap();
2107 let cur = Cursor::new(buf);
2108 let ct_ = Ciphertext::parse(ct.pk_algo().unwrap(), cur).unwrap();
2109
2110 ct == ct_
2111 }
2112 }
2113
2114 quickcheck! {
2115 fn signature_roundtrip(sig: Signature) -> bool {
2116 use std::io::Cursor;
2117 use crate::PublicKeyAlgorithm::*;
2118
2119 let mut buf = Vec::new();
2120 sig.serialize(&mut buf).unwrap();
2121 let cur = Cursor::new(buf);
2122
2123 #[allow(deprecated)]
2124 let sig_ = match &sig {
2125 Signature::RSA { .. } =>
2126 Signature::parse(RSAEncryptSign, cur).unwrap(),
2127 Signature::DSA { .. } =>
2128 Signature::parse(DSA, cur).unwrap(),
2129 Signature::ElGamal { .. } =>
2130 Signature::parse(ElGamalEncryptSign, cur).unwrap(),
2131 Signature::EdDSA { .. } =>
2132 Signature::parse(EdDSA, cur).unwrap(),
2133 Signature::ECDSA { .. } =>
2134 Signature::parse(ECDSA, cur).unwrap(),
2135 Signature::Ed25519 { .. } =>
2136 Signature::parse(Ed25519, cur).unwrap(),
2137 Signature::Ed448 { .. } =>
2138 Signature::parse(Ed448, cur).unwrap(),
2139
2140 Signature::MLDSA65_Ed25519 { .. } =>
2141 Signature::parse(MLDSA65_Ed25519, cur).unwrap(),
2142 Signature::MLDSA87_Ed448 { .. } =>
2143 Signature::parse(MLDSA87_Ed448, cur).unwrap(),
2144
2145 Signature::SLHDSA128s { .. } =>
2146 Signature::parse(SLHDSA128s, cur).unwrap(),
2147 Signature::SLHDSA128f { .. } =>
2148 Signature::parse(SLHDSA128f, cur).unwrap(),
2149 Signature::SLHDSA256s { .. } =>
2150 Signature::parse(SLHDSA256s, cur).unwrap(),
2151
2152 Signature::Unknown { .. } => unreachable!(),
2153 };
2154
2155 sig == sig_
2156 }
2157 }
2158}