1use std::fmt;
19use std::cmp::Ordering;
20use std::io::Write;
21use std::borrow::Cow;
22
23#[cfg(test)]
24use quickcheck::{Arbitrary, Gen};
25
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 Unknown(_) if ! curve.is_brainpoolp384() =>
220 Err(Error::UnsupportedEllipticCurve(curve.clone()).into()),
221
222 NistP256
223 | NistP384
224 | NistP521
225 | BrainpoolP256
226 | Unknown(_)
227 | BrainpoolP512
228 =>
229 {
230 let coordinate_length = curve.field_size()?;
232
233 let expected_length =
235 1 + (2 * coordinate_length);
238
239 if value.len() != expected_length {
240 return Err(Error::MalformedMPI(
241 format!("Invalid length of MPI: {} (expected {})",
242 value.len(), expected_length)).into());
243 }
244
245 if value.get(0).map(|&b| b != 0x04).unwrap_or(true) {
246 return Err(Error::MalformedMPI(
247 format!("Bad prefix: {:?} (expected Some(0x04))",
248 value.get(0))).into());
249 }
250
251 Ok((&value[1..1 + coordinate_length],
252 &value[1 + coordinate_length..]))
253 },
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 dyn hash::Digest) {
286 let len = self.bits() as u16;
287
288 hash.update(&len.to_be_bytes());
289 hash.update(&self.value);
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 From<MPI> for ProtectedMPI {
386 fn from(m: MPI) -> Self {
387 ProtectedMPI {
388 value: m.value.into(),
389 }
390 }
391}
392
393impl PartialOrd for ProtectedMPI {
394 fn partial_cmp(&self, other: &ProtectedMPI) -> Option<Ordering> {
395 Some(self.cmp(other))
396 }
397}
398
399impl Ord for ProtectedMPI {
400 fn cmp(&self, other: &ProtectedMPI) -> Ordering {
401 self.secure_memcmp(other)
402 }
403}
404
405impl PartialEq for ProtectedMPI {
406 fn eq(&self, other: &ProtectedMPI) -> bool {
407 self.cmp(other) == Ordering::Equal
408 }
409}
410
411impl Eq for ProtectedMPI {}
412
413impl std::hash::Hash for ProtectedMPI {
414 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
415 self.value.hash(state);
416 }
417}
418
419impl ProtectedMPI {
420 pub fn new_point(x: &[u8], y: &[u8], field_bits: usize) -> Self {
429 MPI::new_point_common(x, y, field_bits).into()
430 }
431
432 pub fn new_compressed_point(x: &[u8]) -> Self {
442 MPI::new_compressed_point_common(x).into()
443 }
444
445 pub fn bits(&self) -> usize {
449 self.value.len() * 8
450 - self.value.get(0).map(|&b| b.leading_zeros() as usize)
451 .unwrap_or(0)
452 }
453
454 pub fn value(&self) -> &[u8] {
459 &self.value
460 }
461
462 pub fn value_padded(&self, to: usize) -> Protected {
469 let missing = to.saturating_sub(self.value.len());
470 let limit = self.value.len().min(to);
471 let mut v: Protected = vec![0; to].into();
472 v[missing..].copy_from_slice(&self.value()[..limit]);
473 v
474 }
475
476 pub fn decode_point(&self, curve: &Curve) -> Result<(&[u8], &[u8])> {
493 MPI::decode_point_common(self.value(), curve)
494 }
495
496 fn secure_memcmp(&self, other: &Self) -> Ordering {
498 (self.value.len() as i32).cmp(&(other.value.len() as i32))
499 .then(
500 self.value.cmp(&other.value))
502 }
503}
504
505impl fmt::Debug for ProtectedMPI {
506 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
507 if cfg!(debug_assertions) {
508 f.write_fmt(format_args!(
509 "{} bits: {}", self.bits(),
510 crate::fmt::to_hex(&*self.value, true)))
511 } else {
512 f.write_str("<Redacted>")
513 }
514 }
515}
516
517#[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 Unknown {
589 mpis: Box<[MPI]>,
591 rest: Box<[u8]>,
593 },
594}
595assert_send_and_sync!(PublicKey);
596
597impl PublicKey {
598 pub fn bits(&self) -> Option<usize> {
609 use self::PublicKey::*;
610 match self {
611 RSA { ref n,.. } => Some(n.bits()),
612 DSA { ref p,.. } => Some(p.bits()),
613 ElGamal { ref p,.. } => Some(p.bits()),
614 EdDSA { ref curve,.. } => curve.bits(),
615 ECDSA { ref curve,.. } => curve.bits(),
616 ECDH { ref curve,.. } => curve.bits(),
617 Unknown { .. } => None,
618 }
619 }
620
621 pub fn algo(&self) -> Option<PublicKeyAlgorithm> {
624 use self::PublicKey::*;
625 match self {
626 RSA { .. } => Some(PublicKeyAlgorithm::RSAEncryptSign),
627 DSA { .. } => Some(PublicKeyAlgorithm::DSA),
628 ElGamal { .. } => Some(PublicKeyAlgorithm::ElGamalEncrypt),
629 EdDSA { .. } => Some(PublicKeyAlgorithm::EdDSA),
630 ECDSA { .. } => Some(PublicKeyAlgorithm::ECDSA),
631 ECDH { .. } => Some(PublicKeyAlgorithm::ECDH),
632 Unknown { .. } => None,
633 }
634 }
635}
636
637impl Hash for PublicKey {
638 fn hash(&self, mut hash: &mut dyn hash::Digest) {
639 self.serialize(&mut hash as &mut dyn Write)
640 .expect("hashing does not fail")
641 }
642}
643
644#[cfg(test)]
645impl Arbitrary for PublicKey {
646 fn arbitrary(g: &mut Gen) -> Self {
647 use self::PublicKey::*;
648 use crate::arbitrary_helper::gen_arbitrary_from_range;
649
650 match gen_arbitrary_from_range(0..6, g) {
651 0 => RSA {
652 e: MPI::arbitrary(g),
653 n: MPI::arbitrary(g),
654 },
655
656 1 => DSA {
657 p: MPI::arbitrary(g),
658 q: MPI::arbitrary(g),
659 g: MPI::arbitrary(g),
660 y: MPI::arbitrary(g),
661 },
662
663 2 => ElGamal {
664 p: MPI::arbitrary(g),
665 g: MPI::arbitrary(g),
666 y: MPI::arbitrary(g),
667 },
668
669 3 => EdDSA {
670 curve: Curve::arbitrary(g),
671 q: MPI::arbitrary(g),
672 },
673
674 4 => ECDSA {
675 curve: Curve::arbitrary(g),
676 q: MPI::arbitrary(g),
677 },
678
679 5 => ECDH {
680 curve: Curve::arbitrary(g),
681 q: MPI::arbitrary(g),
682 hash: HashAlgorithm::arbitrary(g),
683 sym: SymmetricAlgorithm::arbitrary(g),
684 },
685
686 _ => unreachable!(),
687 }
688 }
689}
690
691#[non_exhaustive]
704#[allow(clippy::derived_hash_with_manual_eq)]
705#[derive(Clone, Hash)]
706pub enum SecretKeyMaterial {
707 RSA {
709 d: ProtectedMPI,
711 p: ProtectedMPI,
713 q: ProtectedMPI,
715 u: ProtectedMPI,
717 },
718
719 DSA {
721 x: ProtectedMPI,
723 },
724
725 ElGamal {
727 x: ProtectedMPI,
729 },
730
731 EdDSA {
733 scalar: ProtectedMPI,
735 },
736
737 ECDSA {
739 scalar: ProtectedMPI,
741 },
742
743 ECDH {
745 scalar: ProtectedMPI,
747 },
748
749 Unknown {
751 mpis: Box<[ProtectedMPI]>,
753 rest: Protected,
755 },
756}
757assert_send_and_sync!(SecretKeyMaterial);
758
759impl fmt::Debug for SecretKeyMaterial {
760 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
761 if cfg!(debug_assertions) {
762 match self {
763 SecretKeyMaterial::RSA{ ref d, ref p, ref q, ref u } =>
764 write!(f, "RSA {{ d: {:?}, p: {:?}, q: {:?}, u: {:?} }}", d, p, q, u),
765 SecretKeyMaterial::DSA{ ref x } =>
766 write!(f, "DSA {{ x: {:?} }}", x),
767 SecretKeyMaterial::ElGamal{ ref x } =>
768 write!(f, "ElGamal {{ x: {:?} }}", x),
769 SecretKeyMaterial::EdDSA{ ref scalar } =>
770 write!(f, "EdDSA {{ scalar: {:?} }}", scalar),
771 SecretKeyMaterial::ECDSA{ ref scalar } =>
772 write!(f, "ECDSA {{ scalar: {:?} }}", scalar),
773 SecretKeyMaterial::ECDH{ ref scalar } =>
774 write!(f, "ECDH {{ scalar: {:?} }}", scalar),
775 SecretKeyMaterial::Unknown{ ref mpis, ref rest } =>
776 write!(f, "Unknown {{ mips: {:?}, rest: {:?} }}", mpis, rest),
777 }
778 } else {
779 match self {
780 SecretKeyMaterial::RSA{ .. } =>
781 f.write_str("RSA { <Redacted> }"),
782 SecretKeyMaterial::DSA{ .. } =>
783 f.write_str("DSA { <Redacted> }"),
784 SecretKeyMaterial::ElGamal{ .. } =>
785 f.write_str("ElGamal { <Redacted> }"),
786 SecretKeyMaterial::EdDSA{ .. } =>
787 f.write_str("EdDSA { <Redacted> }"),
788 SecretKeyMaterial::ECDSA{ .. } =>
789 f.write_str("ECDSA { <Redacted> }"),
790 SecretKeyMaterial::ECDH{ .. } =>
791 f.write_str("ECDH { <Redacted> }"),
792 SecretKeyMaterial::Unknown{ .. } =>
793 f.write_str("Unknown { <Redacted> }"),
794 }
795 }
796 }
797}
798
799impl PartialOrd for SecretKeyMaterial {
800 fn partial_cmp(&self, other: &SecretKeyMaterial) -> Option<Ordering> {
801 Some(self.cmp(other))
802 }
803}
804
805impl Ord for SecretKeyMaterial {
806 fn cmp(&self, other: &Self) -> Ordering {
807 use std::iter;
808
809 fn discriminant(sk: &SecretKeyMaterial) -> usize {
810 match sk {
811 SecretKeyMaterial::RSA{ .. } => 0,
812 SecretKeyMaterial::DSA{ .. } => 1,
813 SecretKeyMaterial::ElGamal{ .. } => 2,
814 SecretKeyMaterial::EdDSA{ .. } => 3,
815 SecretKeyMaterial::ECDSA{ .. } => 4,
816 SecretKeyMaterial::ECDH{ .. } => 5,
817 SecretKeyMaterial::Unknown{ .. } => 6,
818 }
819 }
820
821 let ret = match (self, other) {
822 (&SecretKeyMaterial::RSA{ d: ref d1, p: ref p1, q: ref q1, u: ref u1 }
823 ,&SecretKeyMaterial::RSA{ d: ref d2, p: ref p2, q: ref q2, u: ref u2 }) => {
824 let o1 = d1.cmp(d2);
825 let o2 = p1.cmp(p2);
826 let o3 = q1.cmp(q2);
827 let o4 = u1.cmp(u2);
828
829 if o1 != Ordering::Equal { return o1; }
830 if o2 != Ordering::Equal { return o2; }
831 if o3 != Ordering::Equal { return o3; }
832 o4
833 }
834 (&SecretKeyMaterial::DSA{ x: ref x1 }
835 ,&SecretKeyMaterial::DSA{ x: ref x2 }) => {
836 x1.cmp(x2)
837 }
838 (&SecretKeyMaterial::ElGamal{ x: ref x1 }
839 ,&SecretKeyMaterial::ElGamal{ x: ref x2 }) => {
840 x1.cmp(x2)
841 }
842 (&SecretKeyMaterial::EdDSA{ scalar: ref scalar1 }
843 ,&SecretKeyMaterial::EdDSA{ scalar: ref scalar2 }) => {
844 scalar1.cmp(scalar2)
845 }
846 (&SecretKeyMaterial::ECDSA{ scalar: ref scalar1 }
847 ,&SecretKeyMaterial::ECDSA{ scalar: ref scalar2 }) => {
848 scalar1.cmp(scalar2)
849 }
850 (&SecretKeyMaterial::ECDH{ scalar: ref scalar1 }
851 ,&SecretKeyMaterial::ECDH{ scalar: ref scalar2 }) => {
852 scalar1.cmp(scalar2)
853 }
854 (&SecretKeyMaterial::Unknown{ mpis: ref mpis1, rest: ref rest1 }
855 ,&SecretKeyMaterial::Unknown{ mpis: ref mpis2, rest: ref rest2 }) => {
856 let o1 = secure_cmp(rest1, rest2);
857 let o2 = mpis1.len().cmp(&mpis2.len());
858 let on = mpis1.iter().zip(mpis2.iter()).map(|(a,b)| {
859 a.cmp(b)
860 }).collect::<Vec<_>>();
861
862 iter::once(o1)
863 .chain(iter::once(o2))
864 .chain(on.iter().cloned())
865 .fold(Ordering::Equal, |acc, x| acc.then(x))
866 }
867
868 (a, b) => {
869 let ret = discriminant(a).cmp(&discriminant(b));
870
871 assert!(ret != Ordering::Equal);
872 ret
873 }
874 };
875
876 ret
877 }
878}
879
880impl PartialEq for SecretKeyMaterial {
881 fn eq(&self, other: &Self) -> bool { self.cmp(other) == Ordering::Equal }
882}
883
884impl Eq for SecretKeyMaterial {}
885
886impl SecretKeyMaterial {
887 pub fn algo(&self) -> Option<PublicKeyAlgorithm> {
890 use self::SecretKeyMaterial::*;
891 match self {
892 RSA { .. } => Some(PublicKeyAlgorithm::RSAEncryptSign),
893 DSA { .. } => Some(PublicKeyAlgorithm::DSA),
894 ElGamal { .. } => Some(PublicKeyAlgorithm::ElGamalEncrypt),
895 EdDSA { .. } => Some(PublicKeyAlgorithm::EdDSA),
896 ECDSA { .. } => Some(PublicKeyAlgorithm::ECDSA),
897 ECDH { .. } => Some(PublicKeyAlgorithm::ECDH),
898 Unknown { .. } => None,
899 }
900 }
901}
902
903impl Hash for SecretKeyMaterial {
904 fn hash(&self, mut hash: &mut dyn hash::Digest) {
905 self.serialize(&mut hash as &mut dyn Write)
906 .expect("hashing does not fail")
907 }
908}
909
910#[cfg(test)]
911impl SecretKeyMaterial {
912 pub(crate) fn arbitrary_for(g: &mut Gen, pk: PublicKeyAlgorithm) -> Result<Self> {
913 use self::PublicKeyAlgorithm::*;
914 #[allow(deprecated)]
915 match pk {
916 RSAEncryptSign | RSASign | RSAEncrypt => Ok(SecretKeyMaterial::RSA {
917 d: MPI::arbitrary(g).into(),
918 p: MPI::arbitrary(g).into(),
919 q: MPI::arbitrary(g).into(),
920 u: MPI::arbitrary(g).into(),
921 }),
922
923 DSA => Ok(SecretKeyMaterial::DSA {
924 x: MPI::arbitrary(g).into(),
925 }),
926
927 ElGamalEncryptSign | ElGamalEncrypt => Ok(SecretKeyMaterial::ElGamal {
928 x: MPI::arbitrary(g).into(),
929 }),
930
931 EdDSA => Ok(SecretKeyMaterial::EdDSA {
932 scalar: MPI::arbitrary(g).into(),
933 }),
934
935 ECDSA => Ok(SecretKeyMaterial::ECDSA {
936 scalar: MPI::arbitrary(g).into(),
937 }),
938
939 ECDH => Ok(SecretKeyMaterial::ECDH {
940 scalar: MPI::arbitrary(g).into(),
941 }),
942
943 Private(_) | Unknown(_) =>
944 Err(Error::UnsupportedPublicKeyAlgorithm(pk).into()),
945 }
946 }
947}
948#[cfg(test)]
949impl Arbitrary for SecretKeyMaterial {
950 fn arbitrary(g: &mut Gen) -> Self {
951 let pk = *g.choose(&crate::types::PUBLIC_KEY_ALGORITHM_VARIANTS)
952 .expect("not empty");
953 Self::arbitrary_for(g, pk).expect("only known variants")
954 }
955}
956
957#[derive(PartialEq, Eq, Hash, Clone, Copy, Debug)]
964pub enum SecretKeyChecksum {
965 SHA1,
967
968 Sum16,
970}
971assert_send_and_sync!(SecretKeyChecksum);
972
973impl Default for SecretKeyChecksum {
974 fn default() -> Self {
975 SecretKeyChecksum::SHA1
976 }
977}
978
979impl SecretKeyChecksum {
980 pub(crate) fn len(&self) -> usize {
982 match self {
983 SecretKeyChecksum::SHA1 => 20,
984 SecretKeyChecksum::Sum16 => 2,
985 }
986 }
987}
988
989#[non_exhaustive]
999#[derive(Clone, PartialEq, Eq, Hash, Debug, PartialOrd, Ord)]
1000pub enum Ciphertext {
1001 RSA {
1003 c: MPI,
1005 },
1006
1007 ElGamal {
1009 e: MPI,
1011 c: MPI,
1013 },
1014
1015 ECDH {
1017 e: MPI,
1019 key: Box<[u8]>,
1021 },
1022
1023 Unknown {
1025 mpis: Box<[MPI]>,
1027 rest: Box<[u8]>,
1029 },
1030}
1031assert_send_and_sync!(Ciphertext);
1032
1033impl Ciphertext {
1034 pub fn pk_algo(&self) -> Option<PublicKeyAlgorithm> {
1037 use self::Ciphertext::*;
1038
1039 match self {
1043 RSA { .. } => Some(PublicKeyAlgorithm::RSAEncryptSign),
1044 ElGamal { .. } => Some(PublicKeyAlgorithm::ElGamalEncrypt),
1045 ECDH { .. } => Some(PublicKeyAlgorithm::ECDH),
1046 Unknown { .. } => None,
1047 }
1048 }
1049}
1050
1051impl Hash for Ciphertext {
1052 fn hash(&self, mut hash: &mut dyn hash::Digest) {
1053 self.serialize(&mut hash as &mut dyn Write)
1054 .expect("hashing does not fail")
1055 }
1056}
1057
1058#[cfg(test)]
1059impl Arbitrary for Ciphertext {
1060 fn arbitrary(g: &mut Gen) -> Self {
1061 use crate::arbitrary_helper::gen_arbitrary_from_range;
1062
1063 match gen_arbitrary_from_range(0..3, g) {
1064 0 => Ciphertext::RSA {
1065 c: MPI::arbitrary(g),
1066 },
1067
1068 1 => Ciphertext::ElGamal {
1069 e: MPI::arbitrary(g),
1070 c: MPI::arbitrary(g)
1071 },
1072
1073 2 => Ciphertext::ECDH {
1074 e: MPI::arbitrary(g),
1075 key: {
1076 let mut k = <Vec<u8>>::arbitrary(g);
1077 k.truncate(255);
1078 k.into_boxed_slice()
1079 },
1080 },
1081 _ => unreachable!(),
1082 }
1083 }
1084}
1085
1086#[non_exhaustive]
1096#[derive(Clone, PartialEq, Eq, Hash, Debug, PartialOrd, Ord)]
1097pub enum Signature {
1098 RSA {
1100 s: MPI,
1102 },
1103
1104 DSA {
1106 r: MPI,
1108 s: MPI,
1110 },
1111
1112 ElGamal {
1114 r: MPI,
1116 s: MPI,
1118 },
1119
1120 EdDSA {
1122 r: MPI,
1124 s: MPI,
1126 },
1127
1128 ECDSA {
1130 r: MPI,
1132 s: MPI,
1134 },
1135
1136 Unknown {
1138 mpis: Box<[MPI]>,
1140 rest: Box<[u8]>,
1142 },
1143}
1144assert_send_and_sync!(Signature);
1145
1146impl Hash for Signature {
1147 fn hash(&self, mut hash: &mut dyn hash::Digest) {
1148 self.serialize(&mut hash as &mut dyn Write)
1149 .expect("hashing does not fail")
1150 }
1151}
1152
1153#[cfg(test)]
1154impl Arbitrary for Signature {
1155 fn arbitrary(g: &mut Gen) -> Self {
1156 use crate::arbitrary_helper::gen_arbitrary_from_range;
1157
1158 match gen_arbitrary_from_range(0..4, g) {
1159 0 => Signature::RSA {
1160 s: MPI::arbitrary(g),
1161 },
1162
1163 1 => Signature::DSA {
1164 r: MPI::arbitrary(g),
1165 s: MPI::arbitrary(g),
1166 },
1167
1168 2 => Signature::EdDSA {
1169 r: MPI::arbitrary(g),
1170 s: MPI::arbitrary(g),
1171 },
1172
1173 3 => Signature::ECDSA {
1174 r: MPI::arbitrary(g),
1175 s: MPI::arbitrary(g),
1176 },
1177
1178 _ => unreachable!(),
1179 }
1180 }
1181}
1182
1183#[cfg(test)]
1184mod tests {
1185 use super::*;
1186 use crate::parse::Parse;
1187
1188 quickcheck! {
1189 fn mpi_roundtrip(mpi: MPI) -> bool {
1190 let mut buf = Vec::new();
1191 mpi.serialize(&mut buf).unwrap();
1192 MPI::from_bytes(&buf).unwrap() == mpi
1193 }
1194 }
1195
1196 quickcheck! {
1197 fn pk_roundtrip(pk: PublicKey) -> bool {
1198 use std::io::Cursor;
1199 use crate::PublicKeyAlgorithm::*;
1200
1201 let mut buf = Vec::new();
1202 pk.serialize(&mut buf).unwrap();
1203 let cur = Cursor::new(buf);
1204
1205 #[allow(deprecated)]
1206 let pk_ = match &pk {
1207 PublicKey::RSA { .. } =>
1208 PublicKey::parse(RSAEncryptSign, cur).unwrap(),
1209 PublicKey::DSA { .. } =>
1210 PublicKey::parse(DSA, cur).unwrap(),
1211 PublicKey::ElGamal { .. } =>
1212 PublicKey::parse(ElGamalEncrypt, cur).unwrap(),
1213 PublicKey::EdDSA { .. } =>
1214 PublicKey::parse(EdDSA, cur).unwrap(),
1215 PublicKey::ECDSA { .. } =>
1216 PublicKey::parse(ECDSA, cur).unwrap(),
1217 PublicKey::ECDH { .. } =>
1218 PublicKey::parse(ECDH, cur).unwrap(),
1219
1220 PublicKey::Unknown { .. } => unreachable!(),
1221 };
1222
1223 pk == pk_
1224 }
1225 }
1226
1227 #[test]
1228 fn pk_bits() {
1229 for (name, key_no, bits) in &[
1230 ("testy.pgp", 0, 2048),
1231 ("testy-new.pgp", 1, 256),
1232 ("dennis-simon-anton.pgp", 0, 2048),
1233 ("dsa2048-elgamal3072.pgp", 1, 3072),
1234 ("emmelie-dorothea-dina-samantha-awina-ed25519.pgp", 0, 256),
1235 ("erika-corinna-daniela-simone-antonia-nistp256.pgp", 0, 256),
1236 ("erika-corinna-daniela-simone-antonia-nistp384.pgp", 0, 384),
1237 ("erika-corinna-daniela-simone-antonia-nistp521.pgp", 0, 521),
1238 ] {
1239 let cert = crate::Cert::from_bytes(crate::tests::key(name)).unwrap();
1240 let ka = cert.keys().nth(*key_no).unwrap();
1241 assert_eq!(ka.key().mpis().bits().unwrap(), *bits,
1242 "Cert {}, key no {}", name, *key_no);
1243 }
1244 }
1245
1246 quickcheck! {
1247 fn sk_roundtrip(sk: SecretKeyMaterial) -> bool {
1248 use std::io::Cursor;
1249 use crate::PublicKeyAlgorithm::*;
1250
1251 let mut buf = Vec::new();
1252 sk.serialize(&mut buf).unwrap();
1253 let cur = Cursor::new(buf);
1254
1255 #[allow(deprecated)]
1256 let sk_ = match &sk {
1257 SecretKeyMaterial::RSA { .. } =>
1258 SecretKeyMaterial::parse(RSAEncryptSign, cur).unwrap(),
1259 SecretKeyMaterial::DSA { .. } =>
1260 SecretKeyMaterial::parse(DSA, cur).unwrap(),
1261 SecretKeyMaterial::EdDSA { .. } =>
1262 SecretKeyMaterial::parse(EdDSA, cur).unwrap(),
1263 SecretKeyMaterial::ECDSA { .. } =>
1264 SecretKeyMaterial::parse(ECDSA, cur).unwrap(),
1265 SecretKeyMaterial::ECDH { .. } =>
1266 SecretKeyMaterial::parse(ECDH, cur).unwrap(),
1267 SecretKeyMaterial::ElGamal { .. } =>
1268 SecretKeyMaterial::parse(ElGamalEncrypt, cur).unwrap(),
1269
1270 SecretKeyMaterial::Unknown { .. } => unreachable!(),
1271 };
1272
1273 sk == sk_
1274 }
1275 }
1276
1277 quickcheck! {
1278 fn ct_roundtrip(ct: Ciphertext) -> bool {
1279 use std::io::Cursor;
1280 use crate::PublicKeyAlgorithm::*;
1281
1282 let mut buf = Vec::new();
1283 ct.serialize(&mut buf).unwrap();
1284 let cur = Cursor::new(buf);
1285
1286 #[allow(deprecated)]
1287 let ct_ = match &ct {
1288 Ciphertext::RSA { .. } =>
1289 Ciphertext::parse(RSAEncryptSign, cur).unwrap(),
1290 Ciphertext::ElGamal { .. } =>
1291 Ciphertext::parse(ElGamalEncrypt, cur).unwrap(),
1292 Ciphertext::ECDH { .. } =>
1293 Ciphertext::parse(ECDH, cur).unwrap(),
1294
1295 Ciphertext::Unknown { .. } => unreachable!(),
1296 };
1297
1298 ct == ct_
1299 }
1300 }
1301
1302 quickcheck! {
1303 fn signature_roundtrip(sig: Signature) -> bool {
1304 use std::io::Cursor;
1305 use crate::PublicKeyAlgorithm::*;
1306
1307 let mut buf = Vec::new();
1308 sig.serialize(&mut buf).unwrap();
1309 let cur = Cursor::new(buf);
1310
1311 #[allow(deprecated)]
1312 let sig_ = match &sig {
1313 Signature::RSA { .. } =>
1314 Signature::parse(RSAEncryptSign, cur).unwrap(),
1315 Signature::DSA { .. } =>
1316 Signature::parse(DSA, cur).unwrap(),
1317 Signature::ElGamal { .. } =>
1318 Signature::parse(ElGamalEncryptSign, cur).unwrap(),
1319 Signature::EdDSA { .. } =>
1320 Signature::parse(EdDSA, cur).unwrap(),
1321 Signature::ECDSA { .. } =>
1322 Signature::parse(ECDSA, cur).unwrap(),
1323
1324 Signature::Unknown { .. } => unreachable!(),
1325 };
1326
1327 sig == sig_
1328 }
1329 }
1330}