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::types::{
26 Curve,
27 HashAlgorithm,
28 PublicKeyAlgorithm,
29 SymmetricAlgorithm,
30};
31use crate::crypto::hash::{self, Hash};
32use crate::crypto::mem::{secure_cmp, Protected};
33use crate::serialize::Marshal;
34
35use crate::Error;
36use crate::Result;
37
38#[derive(Clone)]
40pub struct MPI {
41 value: Box<[u8]>,
43}
44assert_send_and_sync!(MPI);
45
46impl From<Vec<u8>> for MPI {
47 fn from(v: Vec<u8>) -> Self {
48 Self::new(&v)
55 }
56}
57
58impl From<Box<[u8]>> for MPI {
59 fn from(v: Box<[u8]>) -> Self {
60 Self::new(&v)
67 }
68}
69
70impl MPI {
71 fn trim_leading_zeros(v: &[u8]) -> &[u8] {
73 let offset = v.iter().take_while(|&&o| o == 0).count();
74 &v[offset..]
75 }
76
77 pub fn new(value: &[u8]) -> Self {
81 let value = Self::trim_leading_zeros(value).to_vec().into_boxed_slice();
82
83 MPI {
84 value,
85 }
86 }
87
88 pub fn new_point(x: &[u8], y: &[u8], field_bits: usize) -> Self {
97 Self::new_point_common(x, y, field_bits).into()
98 }
99
100 fn new_point_common(x: &[u8], y: &[u8], field_bits: usize) -> Vec<u8> {
102 let field_sz = if field_bits % 8 > 0 { 1 } else { 0 } + field_bits / 8;
103 let mut val = vec![0x0u8; 1 + 2 * field_sz];
104 let x_missing = field_sz - x.len();
105 let y_missing = field_sz - y.len();
106
107 val[0] = 0x4;
108 val[1 + x_missing..1 + field_sz].copy_from_slice(x);
109 val[1 + field_sz + y_missing..].copy_from_slice(y);
110 val
111 }
112
113 pub fn new_compressed_point(x: &[u8]) -> Self {
123 Self::new_compressed_point_common(x).into()
124 }
125
126 fn new_compressed_point_common(x: &[u8]) -> Vec<u8> {
128 let mut val = vec![0; 1 + x.len()];
129 val[0] = 0x40;
130 val[1..].copy_from_slice(x);
131 val
132 }
133
134 pub fn zero() -> Self {
136 Self::new(&[])
137 }
138
139 pub fn is_zero(&self) -> bool {
141 self.value().is_empty()
142 }
143
144 pub fn bits(&self) -> usize {
148 self.value.len() * 8
149 - self.value.get(0).map(|&b| b.leading_zeros() as usize)
150 .unwrap_or(0)
151 }
152
153 pub fn value(&self) -> &[u8] {
158 &self.value
159 }
160
161 pub fn value_padded(&self, to: usize) -> Result<Cow<[u8]>> {
167 crate::crypto::pad(self.value(), to)
168 }
169
170 pub fn decode_point(&self, curve: &Curve) -> Result<(&[u8], &[u8])> {
187 Self::decode_point_common(self.value(), curve)
188 }
189
190 fn decode_point_common<'a>(value: &'a [u8], curve: &Curve)
192 -> Result<(&'a [u8], &'a [u8])> {
193 const ED25519_KEY_SIZE: usize = 32;
194 const CURVE25519_SIZE: usize = 32;
195 use self::Curve::*;
196 match &curve {
197 Ed25519 | Cv25519 => {
198 assert_eq!(CURVE25519_SIZE, ED25519_KEY_SIZE);
199 if value.len() != 1 + CURVE25519_SIZE {
202 return Err(Error::MalformedMPI(
203 format!("Bad size of Curve25519 key: {} expected: {}",
204 value.len(),
205 1 + CURVE25519_SIZE
206 )
207 ).into());
208 }
209
210 if value.get(0).map(|&b| b != 0x40).unwrap_or(true) {
211 return Err(Error::MalformedMPI(
212 "Bad encoding of Curve25519 key".into()).into());
213 }
214
215 Ok((&value[1..], &[]))
216 },
217
218 NistP256
219 | NistP384
220 | NistP521
221 | BrainpoolP256
222 | BrainpoolP384
223 | BrainpoolP512
224 =>
225 {
226 let coordinate_length = curve.field_size()?;
228
229 let expected_length =
231 1 + (2 * coordinate_length);
234
235 if value.len() != expected_length {
236 return Err(Error::MalformedMPI(
237 format!("Invalid length of MPI: {} (expected {})",
238 value.len(), expected_length)).into());
239 }
240
241 if value.get(0).map(|&b| b != 0x04).unwrap_or(true) {
242 return Err(Error::MalformedMPI(
243 format!("Bad prefix: {:?} (expected Some(0x04))",
244 value.get(0))).into());
245 }
246
247 Ok((&value[1..1 + coordinate_length],
248 &value[1 + coordinate_length..]))
249 },
250
251 Unknown(_) =>
252 Err(Error::UnsupportedEllipticCurve(curve.clone()).into()),
253 }
254 }
255
256 fn secure_memcmp(&self, other: &Self) -> Ordering {
258 let cmp = unsafe {
259 if self.value.len() == other.value.len() {
260 ::memsec::memcmp(self.value.as_ptr(), other.value.as_ptr(),
261 other.value.len())
262 } else {
263 self.value.len() as i32 - other.value.len() as i32
264 }
265 };
266
267 match cmp {
268 0 => Ordering::Equal,
269 x if x < 0 => Ordering::Less,
270 _ => Ordering::Greater,
271 }
272 }
273}
274
275impl fmt::Debug for MPI {
276 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
277 f.write_fmt(format_args!(
278 "{} bits: {}", self.bits(),
279 crate::fmt::to_hex(&*self.value, true)))
280 }
281}
282
283impl Hash for MPI {
284 fn hash(&self, hash: &mut hash::Context) -> Result<()> {
285 let len = self.bits() as u16;
286
287 hash.update(&len.to_be_bytes());
288 hash.update(&self.value);
289 Ok(())
290 }
291}
292
293#[cfg(test)]
294impl Arbitrary for MPI {
295 fn arbitrary(g: &mut Gen) -> Self {
296 loop {
297 let buf = <Vec<u8>>::arbitrary(g);
298
299 if !buf.is_empty() && buf[0] != 0 {
300 break MPI::new(&buf);
301 }
302 }
303 }
304}
305
306impl PartialOrd for MPI {
307 fn partial_cmp(&self, other: &MPI) -> Option<Ordering> {
308 Some(self.cmp(other))
309 }
310}
311
312impl Ord for MPI {
313 fn cmp(&self, other: &MPI) -> Ordering {
314 self.secure_memcmp(other)
315 }
316}
317
318impl PartialEq for MPI {
319 fn eq(&self, other: &MPI) -> bool {
320 self.cmp(other) == Ordering::Equal
321 }
322}
323
324impl Eq for MPI {}
325
326impl std::hash::Hash for MPI {
327 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
328 self.value.hash(state);
329 }
330}
331
332#[derive(Clone)]
338pub struct ProtectedMPI {
339 value: Protected,
341}
342assert_send_and_sync!(ProtectedMPI);
343
344impl From<&[u8]> for ProtectedMPI {
345 fn from(m: &[u8]) -> Self {
346 let value = Protected::from(MPI::trim_leading_zeros(m));
347 ProtectedMPI {
348 value,
349 }
350 }
351}
352
353impl From<Vec<u8>> for ProtectedMPI {
354 fn from(m: Vec<u8>) -> Self {
355 let value = Protected::from(MPI::trim_leading_zeros(&m));
356 drop(Protected::from(m)); ProtectedMPI {
358 value,
359 }
360 }
361}
362
363impl From<Box<[u8]>> for ProtectedMPI {
364 fn from(m: Box<[u8]>) -> Self {
365 let value = Protected::from(MPI::trim_leading_zeros(&m));
366 drop(Protected::from(m)); ProtectedMPI {
368 value,
369 }
370 }
371}
372
373impl From<Protected> for ProtectedMPI {
374 fn from(m: Protected) -> Self {
375 let value = Protected::from(MPI::trim_leading_zeros(&m));
376 drop(m); ProtectedMPI {
378 value,
379 }
380 }
381}
382
383impl PartialOrd for ProtectedMPI {
384 fn partial_cmp(&self, other: &ProtectedMPI) -> Option<Ordering> {
385 Some(self.cmp(other))
386 }
387}
388
389impl Ord for ProtectedMPI {
390 fn cmp(&self, other: &ProtectedMPI) -> Ordering {
391 self.secure_memcmp(other)
392 }
393}
394
395impl PartialEq for ProtectedMPI {
396 fn eq(&self, other: &ProtectedMPI) -> bool {
397 self.cmp(other) == Ordering::Equal
398 }
399}
400
401impl Eq for ProtectedMPI {}
402
403impl std::hash::Hash for ProtectedMPI {
404 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
405 self.value.hash(state);
406 }
407}
408
409#[cfg(test)]
410impl Arbitrary for ProtectedMPI {
411 fn arbitrary(g: &mut Gen) -> Self {
412 loop {
413 let buf = <Vec<u8>>::arbitrary(g);
414
415 if ! buf.is_empty() && buf[0] != 0 {
416 break ProtectedMPI::from(buf);
417 }
418 }
419 }
420}
421
422impl ProtectedMPI {
423 pub fn new_point(x: &[u8], y: &[u8], field_bits: usize) -> Self {
432 MPI::new_point_common(x, y, field_bits).into()
433 }
434
435 pub fn new_compressed_point(x: &[u8]) -> Self {
445 MPI::new_compressed_point_common(x).into()
446 }
447
448 pub fn bits(&self) -> usize {
452 self.value.len() * 8
453 - self.value.get(0).map(|&b| b.leading_zeros() as usize)
454 .unwrap_or(0)
455 }
456
457 pub fn value(&self) -> &[u8] {
462 &self.value
463 }
464
465 pub fn value_padded(&self, to: usize) -> Protected {
472 let missing = to.saturating_sub(self.value.len());
473 let limit = self.value.len().min(to);
474 let mut v: Protected = vec![0; to].into();
475 v[missing..].copy_from_slice(&self.value()[..limit]);
476 v
477 }
478
479 pub fn decode_point(&self, curve: &Curve) -> Result<(&[u8], &[u8])> {
496 MPI::decode_point_common(self.value(), curve)
497 }
498
499 fn secure_memcmp(&self, other: &Self) -> Ordering {
501 (self.value.len() as i32).cmp(&(other.value.len() as i32))
502 .then(
503 self.value.cmp(&other.value))
505 }
506}
507
508impl fmt::Debug for ProtectedMPI {
509 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
510 if cfg!(debug_assertions) {
511 f.write_fmt(format_args!(
512 "{} bits: {}", self.bits(),
513 crate::fmt::to_hex(&*self.value, true)))
514 } else {
515 f.write_str("<Redacted>")
516 }
517 }
518}
519
520#[non_exhaustive]
527#[derive(Clone, PartialEq, Eq, Hash, Debug, PartialOrd, Ord)]
528pub enum PublicKey {
529 RSA {
531 e: MPI,
533 n: MPI,
535 },
536
537 DSA {
539 p: MPI,
541 q: MPI,
543 g: MPI,
545 y: MPI,
547 },
548
549 ElGamal {
551 p: MPI,
553 g: MPI,
555 y: MPI,
557 },
558
559 EdDSA {
561 curve: Curve,
563 q: MPI,
565 },
566
567 ECDSA {
569 curve: Curve,
571 q: MPI,
573 },
574
575 ECDH {
577 curve: Curve,
579 q: MPI,
581 hash: HashAlgorithm,
583 sym: SymmetricAlgorithm,
585 },
586
587 X25519 {
589 u: [u8; 32],
591 },
592
593 X448 {
595 u: Box<[u8; 56]>,
597 },
598
599 Ed25519 {
601 a: [u8; 32],
603 },
604
605 Ed448 {
607 a: Box<[u8; 57]>,
609 },
610
611 Unknown {
613 mpis: Box<[MPI]>,
615 rest: Box<[u8]>,
617 },
618}
619assert_send_and_sync!(PublicKey);
620
621impl PublicKey {
622 pub fn bits(&self) -> Option<usize> {
633 use self::PublicKey::*;
634 match self {
635 RSA { ref n,.. } => Some(n.bits()),
636 DSA { ref p,.. } => Some(p.bits()),
637 ElGamal { ref p,.. } => Some(p.bits()),
638 EdDSA { ref curve,.. } => curve.bits().ok(),
639 ECDSA { ref curve,.. } => curve.bits().ok(),
640 ECDH { ref curve,.. } => curve.bits().ok(),
641 X25519 { .. } => Some(256),
642 X448 { .. } => Some(448),
643 Ed25519 { .. } => Some(256),
644 Ed448 { .. } => Some(456),
645 Unknown { .. } => None,
646 }
647 }
648
649 pub fn algo(&self) -> Option<PublicKeyAlgorithm> {
652 use self::PublicKey::*;
653 #[allow(deprecated)]
654 match self {
655 RSA { .. } => Some(PublicKeyAlgorithm::RSAEncryptSign),
656 DSA { .. } => Some(PublicKeyAlgorithm::DSA),
657 ElGamal { .. } => Some(PublicKeyAlgorithm::ElGamalEncrypt),
658 EdDSA { .. } => Some(PublicKeyAlgorithm::EdDSA),
659 ECDSA { .. } => Some(PublicKeyAlgorithm::ECDSA),
660 ECDH { .. } => Some(PublicKeyAlgorithm::ECDH),
661 X25519 { .. } => Some(PublicKeyAlgorithm::X25519),
662 X448 { .. } => Some(PublicKeyAlgorithm::X448),
663 Ed25519 { .. } => Some(PublicKeyAlgorithm::Ed25519),
664 Ed448 { .. } => Some(PublicKeyAlgorithm::Ed448),
665 Unknown { .. } => None,
666 }
667 }
668}
669
670impl Hash for PublicKey {
671 fn hash(&self, mut hash: &mut hash::Context) -> Result<()> {
672 self.serialize(&mut hash as &mut dyn Write)
673 }
674}
675
676#[cfg(test)]
677impl Arbitrary for PublicKey {
678 fn arbitrary(g: &mut Gen) -> Self {
679 use self::PublicKey::*;
680 use crate::arbitrary_helper::gen_arbitrary_from_range;
681
682 match gen_arbitrary_from_range(0..10, g) {
683 0 => RSA {
684 e: MPI::arbitrary(g),
685 n: MPI::arbitrary(g),
686 },
687
688 1 => DSA {
689 p: MPI::arbitrary(g),
690 q: MPI::arbitrary(g),
691 g: MPI::arbitrary(g),
692 y: MPI::arbitrary(g),
693 },
694
695 2 => ElGamal {
696 p: MPI::arbitrary(g),
697 g: MPI::arbitrary(g),
698 y: MPI::arbitrary(g),
699 },
700
701 3 => EdDSA {
702 curve: Curve::arbitrary(g),
703 q: MPI::arbitrary(g),
704 },
705
706 4 => ECDSA {
707 curve: Curve::arbitrary(g),
708 q: MPI::arbitrary(g),
709 },
710
711 5 => ECDH {
712 curve: Curve::arbitrary(g),
713 q: MPI::arbitrary(g),
714 hash: HashAlgorithm::arbitrary(g),
715 sym: SymmetricAlgorithm::arbitrary(g),
716 },
717
718 6 => X25519 { u: arbitrary(g) },
719 7 => X448 { u: Box::new(arbitrarize(g, [0; 56])) },
720 8 => Ed25519 { a: arbitrary(g) },
721 9 => Ed448 { a: Box::new(arbitrarize(g, [0; 57])) },
722
723 _ => unreachable!(),
724 }
725 }
726}
727
728#[cfg(test)]
729pub(crate) fn arbitrarize<T: AsMut<[u8]>>(g: &mut Gen, mut a: T) -> T
730{
731 a.as_mut().iter_mut().for_each(|p| *p = Arbitrary::arbitrary(g));
732 a
733}
734
735#[cfg(test)]
736pub(crate) fn arbitrary<T: Default + AsMut<[u8]>>(g: &mut Gen) -> T
737{
738 arbitrarize(g, Default::default())
739}
740
741
742#[non_exhaustive]
752#[allow(clippy::derived_hash_with_manual_eq)]
753#[derive(Clone, Hash)]
754pub enum SecretKeyMaterial {
755 RSA {
757 d: ProtectedMPI,
759 p: ProtectedMPI,
761 q: ProtectedMPI,
763 u: ProtectedMPI,
765 },
766
767 DSA {
769 x: ProtectedMPI,
771 },
772
773 ElGamal {
775 x: ProtectedMPI,
777 },
778
779 EdDSA {
781 scalar: ProtectedMPI,
783 },
784
785 ECDSA {
787 scalar: ProtectedMPI,
789 },
790
791 ECDH {
793 scalar: ProtectedMPI,
795 },
796
797 X25519 {
799 x: Protected,
801 },
802
803 X448 {
805 x: Protected,
807 },
808
809 Ed25519 {
811 x: Protected,
813 },
814
815 Ed448 {
817 x: Protected,
819 },
820
821 Unknown {
823 mpis: Box<[ProtectedMPI]>,
825 rest: Protected,
827 },
828}
829assert_send_and_sync!(SecretKeyMaterial);
830
831impl fmt::Debug for SecretKeyMaterial {
832 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
833 if cfg!(debug_assertions) {
834 match self {
835 SecretKeyMaterial::RSA{ ref d, ref p, ref q, ref u } =>
836 write!(f, "RSA {{ d: {:?}, p: {:?}, q: {:?}, u: {:?} }}", d, p, q, u),
837 SecretKeyMaterial::DSA{ ref x } =>
838 write!(f, "DSA {{ x: {:?} }}", x),
839 SecretKeyMaterial::ElGamal{ ref x } =>
840 write!(f, "ElGamal {{ x: {:?} }}", x),
841 SecretKeyMaterial::EdDSA{ ref scalar } =>
842 write!(f, "EdDSA {{ scalar: {:?} }}", scalar),
843 SecretKeyMaterial::ECDSA{ ref scalar } =>
844 write!(f, "ECDSA {{ scalar: {:?} }}", scalar),
845 SecretKeyMaterial::ECDH{ ref scalar } =>
846 write!(f, "ECDH {{ scalar: {:?} }}", scalar),
847 SecretKeyMaterial::X25519 { x } =>
848 write!(f, "X25519 {{ x: {:?} }}", x),
849 SecretKeyMaterial::X448 { x } =>
850 write!(f, "X448 {{ x: {:?} }}", x),
851 SecretKeyMaterial::Ed25519 { x } =>
852 write!(f, "Ed25519 {{ x: {:?} }}", x),
853 SecretKeyMaterial::Ed448 { x } =>
854 write!(f, "Ed448 {{ x: {:?} }}", x),
855 SecretKeyMaterial::Unknown{ ref mpis, ref rest } =>
856 write!(f, "Unknown {{ mips: {:?}, rest: {:?} }}", mpis, rest),
857 }
858 } else {
859 match self {
860 SecretKeyMaterial::RSA{ .. } =>
861 f.write_str("RSA { <Redacted> }"),
862 SecretKeyMaterial::DSA{ .. } =>
863 f.write_str("DSA { <Redacted> }"),
864 SecretKeyMaterial::ElGamal{ .. } =>
865 f.write_str("ElGamal { <Redacted> }"),
866 SecretKeyMaterial::EdDSA{ .. } =>
867 f.write_str("EdDSA { <Redacted> }"),
868 SecretKeyMaterial::ECDSA{ .. } =>
869 f.write_str("ECDSA { <Redacted> }"),
870 SecretKeyMaterial::ECDH{ .. } =>
871 f.write_str("ECDH { <Redacted> }"),
872 SecretKeyMaterial::X25519 { .. } =>
873 f.write_str("X25519 { <Redacted> }"),
874 SecretKeyMaterial::X448 { .. } =>
875 f.write_str("X448 { <Redacted> }"),
876 SecretKeyMaterial::Ed25519 { .. } =>
877 f.write_str("Ed25519 { <Redacted> }"),
878 SecretKeyMaterial::Ed448 { .. } =>
879 f.write_str("Ed448 { <Redacted> }"),
880 SecretKeyMaterial::Unknown{ .. } =>
881 f.write_str("Unknown { <Redacted> }"),
882 }
883 }
884 }
885}
886
887impl PartialOrd for SecretKeyMaterial {
888 fn partial_cmp(&self, other: &SecretKeyMaterial) -> Option<Ordering> {
889 Some(self.cmp(other))
890 }
891}
892
893impl Ord for SecretKeyMaterial {
894 fn cmp(&self, other: &Self) -> Ordering {
895 use std::iter;
896
897 fn discriminant(sk: &SecretKeyMaterial) -> usize {
898 match sk {
899 SecretKeyMaterial::RSA{ .. } => 0,
900 SecretKeyMaterial::DSA{ .. } => 1,
901 SecretKeyMaterial::ElGamal{ .. } => 2,
902 SecretKeyMaterial::EdDSA{ .. } => 3,
903 SecretKeyMaterial::ECDSA{ .. } => 4,
904 SecretKeyMaterial::ECDH{ .. } => 5,
905 SecretKeyMaterial::X25519 { .. } => 6,
906 SecretKeyMaterial::X448 { .. } => 7,
907 SecretKeyMaterial::Ed25519 { .. } => 8,
908 SecretKeyMaterial::Ed448 { .. } => 9,
909 SecretKeyMaterial::Unknown { .. } => 10,
910 }
911 }
912
913 let ret = match (self, other) {
914 (&SecretKeyMaterial::RSA{ d: ref d1, p: ref p1, q: ref q1, u: ref u1 }
915 ,&SecretKeyMaterial::RSA{ d: ref d2, p: ref p2, q: ref q2, u: ref u2 }) => {
916 let o1 = d1.cmp(d2);
917 let o2 = p1.cmp(p2);
918 let o3 = q1.cmp(q2);
919 let o4 = u1.cmp(u2);
920
921 if o1 != Ordering::Equal { return o1; }
922 if o2 != Ordering::Equal { return o2; }
923 if o3 != Ordering::Equal { return o3; }
924 o4
925 }
926 (&SecretKeyMaterial::DSA{ x: ref x1 }
927 ,&SecretKeyMaterial::DSA{ x: ref x2 }) => {
928 x1.cmp(x2)
929 }
930 (&SecretKeyMaterial::ElGamal{ x: ref x1 }
931 ,&SecretKeyMaterial::ElGamal{ x: ref x2 }) => {
932 x1.cmp(x2)
933 }
934 (&SecretKeyMaterial::EdDSA{ scalar: ref scalar1 }
935 ,&SecretKeyMaterial::EdDSA{ scalar: ref scalar2 }) => {
936 scalar1.cmp(scalar2)
937 }
938 (&SecretKeyMaterial::ECDSA{ scalar: ref scalar1 }
939 ,&SecretKeyMaterial::ECDSA{ scalar: ref scalar2 }) => {
940 scalar1.cmp(scalar2)
941 }
942 (&SecretKeyMaterial::ECDH{ scalar: ref scalar1 }
943 ,&SecretKeyMaterial::ECDH{ scalar: ref scalar2 }) => {
944 scalar1.cmp(scalar2)
945 }
946 (SecretKeyMaterial::X25519 { x: x0 },
947 SecretKeyMaterial::X25519 { x: x1 }) => x0.cmp(x1),
948 (SecretKeyMaterial::X448 { x: x0 },
949 SecretKeyMaterial::X448 { x: x1 }) => x0.cmp(x1),
950 (SecretKeyMaterial::Ed25519 { x: x0 },
951 SecretKeyMaterial::Ed25519 { x: x1 }) => x0.cmp(x1),
952 (SecretKeyMaterial::Ed448 { x: x0 },
953 SecretKeyMaterial::Ed448 { x: x1 }) => x0.cmp(x1),
954
955 (&SecretKeyMaterial::Unknown{ mpis: ref mpis1, rest: ref rest1 }
956 ,&SecretKeyMaterial::Unknown{ mpis: ref mpis2, rest: ref rest2 }) => {
957 let o1 = secure_cmp(rest1, rest2);
958 let o2 = mpis1.len().cmp(&mpis2.len());
959 let on = mpis1.iter().zip(mpis2.iter()).map(|(a,b)| {
960 a.cmp(b)
961 }).collect::<Vec<_>>();
962
963 iter::once(o1)
964 .chain(iter::once(o2))
965 .chain(on.iter().cloned())
966 .fold(Ordering::Equal, |acc, x| acc.then(x))
967 }
968
969 (a, b) => {
970 let ret = discriminant(a).cmp(&discriminant(b));
971
972 assert!(ret != Ordering::Equal);
973 ret
974 }
975 };
976
977 ret
978 }
979}
980
981impl PartialEq for SecretKeyMaterial {
982 fn eq(&self, other: &Self) -> bool { self.cmp(other) == Ordering::Equal }
983}
984
985impl Eq for SecretKeyMaterial {}
986
987impl SecretKeyMaterial {
988 pub fn algo(&self) -> Option<PublicKeyAlgorithm> {
991 use self::SecretKeyMaterial::*;
992 #[allow(deprecated)]
993 match self {
994 RSA { .. } => Some(PublicKeyAlgorithm::RSAEncryptSign),
995 DSA { .. } => Some(PublicKeyAlgorithm::DSA),
996 ElGamal { .. } => Some(PublicKeyAlgorithm::ElGamalEncrypt),
997 EdDSA { .. } => Some(PublicKeyAlgorithm::EdDSA),
998 ECDSA { .. } => Some(PublicKeyAlgorithm::ECDSA),
999 ECDH { .. } => Some(PublicKeyAlgorithm::ECDH),
1000 X25519 { .. } => Some(PublicKeyAlgorithm::X25519),
1001 X448 { .. } => Some(PublicKeyAlgorithm::X448),
1002 Ed25519 { .. } => Some(PublicKeyAlgorithm::Ed25519),
1003 Ed448 { .. } => Some(PublicKeyAlgorithm::Ed448),
1004 Unknown { .. } => None,
1005 }
1006 }
1007}
1008
1009impl Hash for SecretKeyMaterial {
1010 fn hash(&self, mut hash: &mut hash::Context) -> Result<()> {
1011 self.serialize(&mut hash as &mut dyn Write)
1012 }
1013}
1014
1015#[cfg(test)]
1016impl SecretKeyMaterial {
1017 pub(crate) fn arbitrary_for(g: &mut Gen, pk: PublicKeyAlgorithm) -> Result<Self> {
1018 use self::PublicKeyAlgorithm::*;
1019 #[allow(deprecated)]
1020 match pk {
1021 RSAEncryptSign | RSASign | RSAEncrypt => Ok(SecretKeyMaterial::RSA {
1022 d: ProtectedMPI::arbitrary(g),
1023 p: ProtectedMPI::arbitrary(g),
1024 q: ProtectedMPI::arbitrary(g),
1025 u: ProtectedMPI::arbitrary(g),
1026 }),
1027
1028 DSA => Ok(SecretKeyMaterial::DSA {
1029 x: ProtectedMPI::arbitrary(g),
1030 }),
1031
1032 ElGamalEncryptSign | ElGamalEncrypt => Ok(SecretKeyMaterial::ElGamal {
1033 x: ProtectedMPI::arbitrary(g),
1034 }),
1035
1036 EdDSA => Ok(SecretKeyMaterial::EdDSA {
1037 scalar: ProtectedMPI::arbitrary(g),
1038 }),
1039
1040 ECDSA => Ok(SecretKeyMaterial::ECDSA {
1041 scalar: ProtectedMPI::arbitrary(g),
1042 }),
1043
1044 ECDH => Ok(SecretKeyMaterial::ECDH {
1045 scalar: ProtectedMPI::arbitrary(g),
1046 }),
1047
1048 X25519 => Ok(SecretKeyMaterial::X25519 {
1049 x: arbitrarize(g, vec![0; 32]).into(),
1050 }),
1051 X448 => Ok(SecretKeyMaterial::X448 {
1052 x: arbitrarize(g, vec![0; 56]).into(),
1053 }),
1054 Ed25519 => Ok(SecretKeyMaterial::Ed25519 {
1055 x: arbitrarize(g, vec![0; 32]).into(),
1056 }),
1057 Ed448 => Ok(SecretKeyMaterial::Ed448 {
1058 x: arbitrarize(g, vec![0; 57]).into(),
1059 }),
1060
1061 Private(_) | Unknown(_) =>
1062 Err(Error::UnsupportedPublicKeyAlgorithm(pk).into()),
1063 }
1064 }
1065}
1066#[cfg(test)]
1067impl Arbitrary for SecretKeyMaterial {
1068 fn arbitrary(g: &mut Gen) -> Self {
1069 let pk = *g.choose(
1070 &crate::crypto::types::public_key_algorithm::PUBLIC_KEY_ALGORITHM_VARIANTS)
1071 .expect("not empty");
1072 Self::arbitrary_for(g, pk).expect("only known variants")
1073 }
1074}
1075
1076#[derive(PartialEq, Eq, Hash, Clone, Copy, Debug)]
1083pub enum SecretKeyChecksum {
1084 SHA1,
1086
1087 Sum16,
1089}
1090assert_send_and_sync!(SecretKeyChecksum);
1091
1092impl Default for SecretKeyChecksum {
1093 fn default() -> Self {
1094 SecretKeyChecksum::SHA1
1095 }
1096}
1097
1098impl SecretKeyChecksum {
1099 pub(crate) fn len(&self) -> usize {
1101 match self {
1102 SecretKeyChecksum::SHA1 => 20,
1103 SecretKeyChecksum::Sum16 => 2,
1104 }
1105 }
1106}
1107
1108#[non_exhaustive]
1115#[derive(Clone, PartialEq, Eq, Hash, Debug, PartialOrd, Ord)]
1116pub enum Ciphertext {
1117 RSA {
1119 c: MPI,
1121 },
1122
1123 ElGamal {
1125 e: MPI,
1127 c: MPI,
1129 },
1130
1131 ECDH {
1133 e: MPI,
1135 key: Box<[u8]>,
1137 },
1138
1139 X25519 {
1141 e: Box<[u8; 32]>,
1143 key: Box<[u8]>,
1145 },
1146
1147 X448 {
1149 e: Box<[u8; 56]>,
1151 key: Box<[u8]>,
1153 },
1154
1155 Unknown {
1157 mpis: Box<[MPI]>,
1159 rest: Box<[u8]>,
1161 },
1162}
1163assert_send_and_sync!(Ciphertext);
1164
1165impl Ciphertext {
1166 pub fn pk_algo(&self) -> Option<PublicKeyAlgorithm> {
1169 use self::Ciphertext::*;
1170
1171 #[allow(deprecated)]
1175 match self {
1176 RSA { .. } => Some(PublicKeyAlgorithm::RSAEncryptSign),
1177 ElGamal { .. } => Some(PublicKeyAlgorithm::ElGamalEncrypt),
1178 ECDH { .. } => Some(PublicKeyAlgorithm::ECDH),
1179 X25519 { .. } => Some(PublicKeyAlgorithm::X25519),
1180 X448 { .. } => Some(PublicKeyAlgorithm::X448),
1181 Unknown { .. } => None,
1182 }
1183 }
1184}
1185
1186impl Hash for Ciphertext {
1187 fn hash(&self, mut hash: &mut hash::Context) -> Result<()> {
1188 self.serialize(&mut hash as &mut dyn Write)
1189 }
1190}
1191
1192#[cfg(test)]
1193impl Arbitrary for Ciphertext {
1194 fn arbitrary(g: &mut Gen) -> Self {
1195 use crate::arbitrary_helper::gen_arbitrary_from_range;
1196
1197 match gen_arbitrary_from_range(0..5, g) {
1198 0 => Ciphertext::RSA {
1199 c: MPI::arbitrary(g),
1200 },
1201
1202 1 => Ciphertext::ElGamal {
1203 e: MPI::arbitrary(g),
1204 c: MPI::arbitrary(g)
1205 },
1206
1207 2 => Ciphertext::ECDH {
1208 e: MPI::arbitrary(g),
1209 key: {
1210 let mut k = <Vec<u8>>::arbitrary(g);
1211 k.truncate(255);
1212 k.into_boxed_slice()
1213 },
1214 },
1215
1216 3 => Ciphertext::X25519 {
1217 e: Box::new(arbitrary(g)),
1218 key: {
1219 let mut k = <Vec<u8>>::arbitrary(g);
1220 k.truncate(255);
1221 k.into_boxed_slice()
1222 },
1223 },
1224
1225 4 => Ciphertext::X448 {
1226 e: Box::new(arbitrarize(g, [0; 56])),
1227 key: {
1228 let mut k = <Vec<u8>>::arbitrary(g);
1229 k.truncate(255);
1230 k.into_boxed_slice()
1231 },
1232 },
1233 _ => unreachable!(),
1234 }
1235 }
1236}
1237
1238#[non_exhaustive]
1245#[derive(Clone, PartialEq, Eq, Hash, Debug, PartialOrd, Ord)]
1246pub enum Signature {
1247 RSA {
1249 s: MPI,
1251 },
1252
1253 DSA {
1255 r: MPI,
1257 s: MPI,
1259 },
1260
1261 ElGamal {
1263 r: MPI,
1265 s: MPI,
1267 },
1268
1269 EdDSA {
1271 r: MPI,
1273 s: MPI,
1275 },
1276
1277 ECDSA {
1279 r: MPI,
1281 s: MPI,
1283 },
1284
1285 Ed25519 {
1287 s: Box<[u8; 64]>,
1289 },
1290
1291 Ed448 {
1293 s: Box<[u8; 114]>,
1295 },
1296
1297 Unknown {
1299 mpis: Box<[MPI]>,
1301 rest: Box<[u8]>,
1303 },
1304}
1305assert_send_and_sync!(Signature);
1306
1307impl Hash for Signature {
1308 fn hash(&self, mut hash: &mut hash::Context) -> Result<()> {
1309 self.serialize(&mut hash as &mut dyn Write)
1310 }
1311}
1312
1313#[cfg(test)]
1314impl Arbitrary for Signature {
1315 fn arbitrary(g: &mut Gen) -> Self {
1316 use crate::arbitrary_helper::gen_arbitrary_from_range;
1317
1318 match gen_arbitrary_from_range(0..6, g) {
1319 0 => Signature::RSA {
1320 s: MPI::arbitrary(g),
1321 },
1322
1323 1 => Signature::DSA {
1324 r: MPI::arbitrary(g),
1325 s: MPI::arbitrary(g),
1326 },
1327
1328 2 => Signature::EdDSA {
1329 r: MPI::arbitrary(g),
1330 s: MPI::arbitrary(g),
1331 },
1332
1333 3 => Signature::ECDSA {
1334 r: MPI::arbitrary(g),
1335 s: MPI::arbitrary(g),
1336 },
1337
1338 4 => Signature::Ed25519 {
1339 s: Box::new(arbitrarize(g, [0; 64])),
1340 },
1341
1342 5 => Signature::Ed448 {
1343 s: Box::new(arbitrarize(g, [0; 114])),
1344 },
1345
1346 _ => unreachable!(),
1347 }
1348 }
1349}
1350
1351#[cfg(test)]
1352mod tests {
1353 use super::*;
1354 use crate::parse::Parse;
1355
1356 quickcheck! {
1357 fn mpi_roundtrip(mpi: MPI) -> bool {
1358 let mut buf = Vec::new();
1359 mpi.serialize(&mut buf).unwrap();
1360 MPI::from_bytes(&buf).unwrap() == mpi
1361 }
1362 }
1363
1364 quickcheck! {
1365 fn pk_roundtrip(pk: PublicKey) -> bool {
1366 use std::io::Cursor;
1367 use crate::PublicKeyAlgorithm::*;
1368
1369 let mut buf = Vec::new();
1370 pk.serialize(&mut buf).unwrap();
1371 let cur = Cursor::new(buf);
1372
1373 #[allow(deprecated)]
1374 let pk_ = match &pk {
1375 PublicKey::RSA { .. } =>
1376 PublicKey::parse(RSAEncryptSign, cur).unwrap(),
1377 PublicKey::DSA { .. } =>
1378 PublicKey::parse(DSA, cur).unwrap(),
1379 PublicKey::ElGamal { .. } =>
1380 PublicKey::parse(ElGamalEncrypt, cur).unwrap(),
1381 PublicKey::EdDSA { .. } =>
1382 PublicKey::parse(EdDSA, cur).unwrap(),
1383 PublicKey::ECDSA { .. } =>
1384 PublicKey::parse(ECDSA, cur).unwrap(),
1385 PublicKey::ECDH { .. } =>
1386 PublicKey::parse(ECDH, cur).unwrap(),
1387 PublicKey::X25519 { .. } =>
1388 PublicKey::parse(X25519, cur).unwrap(),
1389 PublicKey::X448 { .. } =>
1390 PublicKey::parse(X448, cur).unwrap(),
1391 PublicKey::Ed25519 { .. } =>
1392 PublicKey::parse(Ed25519, cur).unwrap(),
1393 PublicKey::Ed448 { .. } =>
1394 PublicKey::parse(Ed448, cur).unwrap(),
1395
1396 PublicKey::Unknown { .. } => unreachable!(),
1397 };
1398
1399 pk == pk_
1400 }
1401 }
1402
1403 #[test]
1404 fn pk_bits() {
1405 for (name, key_no, bits) in &[
1406 ("testy.pgp", 0, 2048),
1407 ("testy-new.pgp", 1, 256),
1408 ("dennis-simon-anton.pgp", 0, 2048),
1409 ("dsa2048-elgamal3072.pgp", 1, 3072),
1410 ("emmelie-dorothea-dina-samantha-awina-ed25519.pgp", 0, 256),
1411 ("erika-corinna-daniela-simone-antonia-nistp256.pgp", 0, 256),
1412 ("erika-corinna-daniela-simone-antonia-nistp384.pgp", 0, 384),
1413 ("erika-corinna-daniela-simone-antonia-nistp521.pgp", 0, 521),
1414 ] {
1415 let cert = crate::Cert::from_bytes(crate::tests::key(name)).unwrap();
1416 let ka = cert.keys().nth(*key_no).unwrap();
1417 assert_eq!(ka.key().mpis().bits().unwrap(), *bits,
1418 "Cert {}, key no {}", name, *key_no);
1419 }
1420 }
1421
1422 quickcheck! {
1423 fn sk_roundtrip(sk: SecretKeyMaterial) -> bool {
1424 use std::io::Cursor;
1425 use crate::PublicKeyAlgorithm::*;
1426
1427 let mut buf = Vec::new();
1428 sk.serialize(&mut buf).unwrap();
1429 let cur = Cursor::new(buf);
1430
1431 #[allow(deprecated)]
1432 let sk_ = match &sk {
1433 SecretKeyMaterial::RSA { .. } =>
1434 SecretKeyMaterial::parse(RSAEncryptSign, cur).unwrap(),
1435 SecretKeyMaterial::DSA { .. } =>
1436 SecretKeyMaterial::parse(DSA, cur).unwrap(),
1437 SecretKeyMaterial::EdDSA { .. } =>
1438 SecretKeyMaterial::parse(EdDSA, cur).unwrap(),
1439 SecretKeyMaterial::ECDSA { .. } =>
1440 SecretKeyMaterial::parse(ECDSA, cur).unwrap(),
1441 SecretKeyMaterial::ECDH { .. } =>
1442 SecretKeyMaterial::parse(ECDH, cur).unwrap(),
1443 SecretKeyMaterial::ElGamal { .. } =>
1444 SecretKeyMaterial::parse(ElGamalEncrypt, cur).unwrap(),
1445 SecretKeyMaterial::X25519 { .. } =>
1446 SecretKeyMaterial::parse(X25519, cur).unwrap(),
1447 SecretKeyMaterial::X448 { .. } =>
1448 SecretKeyMaterial::parse(X448, cur).unwrap(),
1449 SecretKeyMaterial::Ed25519 { .. } =>
1450 SecretKeyMaterial::parse(Ed25519, cur).unwrap(),
1451 SecretKeyMaterial::Ed448 { .. } =>
1452 SecretKeyMaterial::parse(Ed448, cur).unwrap(),
1453
1454 SecretKeyMaterial::Unknown { .. } => unreachable!(),
1455 };
1456
1457 sk == sk_
1458 }
1459 }
1460
1461 quickcheck! {
1462 fn ct_roundtrip(ct: Ciphertext) -> bool {
1463 use std::io::Cursor;
1464 use crate::PublicKeyAlgorithm::*;
1465
1466 let mut buf = Vec::new();
1467 ct.serialize(&mut buf).unwrap();
1468 let cur = Cursor::new(buf);
1469
1470 #[allow(deprecated)]
1471 let ct_ = match &ct {
1472 Ciphertext::RSA { .. } =>
1473 Ciphertext::parse(RSAEncryptSign, cur).unwrap(),
1474 Ciphertext::ElGamal { .. } =>
1475 Ciphertext::parse(ElGamalEncrypt, cur).unwrap(),
1476 Ciphertext::ECDH { .. } =>
1477 Ciphertext::parse(ECDH, cur).unwrap(),
1478 Ciphertext::X25519 { .. } =>
1479 Ciphertext::parse(X25519, cur).unwrap(),
1480 Ciphertext::X448 { .. } =>
1481 Ciphertext::parse(X448, cur).unwrap(),
1482
1483 Ciphertext::Unknown { .. } => unreachable!(),
1484 };
1485
1486 ct == ct_
1487 }
1488 }
1489
1490 quickcheck! {
1491 fn signature_roundtrip(sig: Signature) -> bool {
1492 use std::io::Cursor;
1493 use crate::PublicKeyAlgorithm::*;
1494
1495 let mut buf = Vec::new();
1496 sig.serialize(&mut buf).unwrap();
1497 let cur = Cursor::new(buf);
1498
1499 #[allow(deprecated)]
1500 let sig_ = match &sig {
1501 Signature::RSA { .. } =>
1502 Signature::parse(RSAEncryptSign, cur).unwrap(),
1503 Signature::DSA { .. } =>
1504 Signature::parse(DSA, cur).unwrap(),
1505 Signature::ElGamal { .. } =>
1506 Signature::parse(ElGamalEncryptSign, cur).unwrap(),
1507 Signature::EdDSA { .. } =>
1508 Signature::parse(EdDSA, cur).unwrap(),
1509 Signature::ECDSA { .. } =>
1510 Signature::parse(ECDSA, cur).unwrap(),
1511 Signature::Ed25519 { .. } =>
1512 Signature::parse(Ed25519, cur).unwrap(),
1513 Signature::Ed448 { .. } =>
1514 Signature::parse(Ed448, cur).unwrap(),
1515
1516 Signature::Unknown { .. } => unreachable!(),
1517 };
1518
1519 sig == sig_
1520 }
1521 }
1522}