sequoia_openpgp/crypto/
mpi.rs

1//! Multiprecision Integers.
2//!
3//! Cryptographic objects like [public keys], [secret keys],
4//! [ciphertexts], and [signatures] are scalar numbers of arbitrary
5//! precision.  OpenPGP specifies that these are stored encoded as
6//! big-endian integers with leading zeros stripped (See [Section 3.2
7//! of RFC 9580]).  Multiprecision integers in OpenPGP are extended by
8//! [Section 3.2.1 of RFC 9580] to store curves and coordinates used
9//! in elliptic curve cryptography (ECC).
10//!
11//!   [public keys]: PublicKey
12//!   [secret keys]: SecretKeyMaterial
13//!   [ciphertexts]: Ciphertext
14//!   [signatures]: Signature
15//!   [Section 3.2 of RFC 9580]: https://www.rfc-editor.org/rfc/rfc9580.html#section-3.2
16//!   [Section 3.2.1 of RFC 9580]: https://www.rfc-editor.org/rfc/rfc9580.html#section-3.2.1
17use 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/// A Multiprecision Integer.
40#[derive(Clone)]
41pub struct MPI {
42    /// Integer value as big-endian with leading zeros stripped.
43    value: Box<[u8]>,
44}
45assert_send_and_sync!(MPI);
46
47impl From<Vec<u8>> for MPI {
48    fn from(v: Vec<u8>) -> Self {
49        // XXX: This will leak secrets in v into the heap.  But,
50        // eagerly clearing the memory may have a very high overhead,
51        // after all, most MPIs that we encounter will not contain
52        // secrets.  I think it is better to avoid creating MPIs that
53        // contain secrets in the first place.  In 2.0, we can remove
54        // the impl From<MPI> for ProtectedMPI.
55        Self::new(&v)
56    }
57}
58
59impl From<Box<[u8]>> for MPI {
60    fn from(v: Box<[u8]>) -> Self {
61        // XXX: This will leak secrets in v into the heap.  But,
62        // eagerly clearing the memory may have a very high overhead,
63        // after all, most MPIs that we encounter will not contain
64        // secrets.  I think it is better to avoid creating MPIs that
65        // contain secrets in the first place.  In 2.0, we can remove
66        // the impl From<MPI> for ProtectedMPI.
67        Self::new(&v)
68    }
69}
70
71impl MPI {
72    /// Trims leading zero octets.
73    fn trim_leading_zeros(v: &[u8]) -> &[u8] {
74        let offset = v.iter().take_while(|&&o| o == 0).count();
75        &v[offset..]
76    }
77
78    /// Creates a new MPI.
79    ///
80    /// This function takes care of removing leading zeros.
81    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    /// Creates new MPI encoding an uncompressed EC point.
90    ///
91    /// Encodes the given point on an elliptic curve (see [Section 6 of
92    /// RFC 6637] for details).  This is used to encode public keys
93    /// and ciphertexts for the NIST curves (`NistP256`, `NistP384`,
94    /// and `NistP521`).
95    ///
96    ///   [Section 6 of RFC 6637]: https://tools.ietf.org/html/rfc6637#section-6
97    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    /// Common implementation shared between MPI and ProtectedMPI.
102    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    /// Creates new MPI encoding a compressed EC point using native
115    /// encoding.
116    ///
117    /// Encodes the given point on an elliptic curve (see [Section 13.2
118    /// of RFC4880bis] for details).  This is used to encode public
119    /// keys and ciphertexts for the Bernstein curves (currently
120    /// `X25519`).
121    ///
122    ///   [Section 13.2 of RFC4880bis]: https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-09#section-13.2
123    pub fn new_compressed_point(x: &[u8]) -> Self {
124        Self::new_compressed_point_common(x).into()
125    }
126
127    /// Common implementation shared between MPI and ProtectedMPI.
128    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    /// Creates a new MPI representing zero.
136    pub fn zero() -> Self {
137        Self::new(&[])
138    }
139
140    /// Tests whether the MPI represents zero.
141    pub fn is_zero(&self) -> bool {
142        self.value().is_empty()
143    }
144
145    /// Returns the length of the MPI in bits.
146    ///
147    /// Leading zero-bits are not included in the returned size.
148    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    /// Returns the value of this MPI.
155    ///
156    /// Note that due to stripping of zero-bytes, the returned value
157    /// may be shorter than expected.
158    pub fn value(&self) -> &[u8] {
159        &self.value
160    }
161
162    /// Returns the value of this MPI zero-padded to the given length.
163    ///
164    /// MPI-encoding strips leading zero-bytes.  This function adds
165    /// them back, if necessary.  If the size exceeds `to`, an error
166    /// is returned.
167    pub fn value_padded(&self, to: usize) -> Result<Cow<[u8]>> {
168        crate::crypto::pad(self.value(), to)
169    }
170
171    /// Decodes an EC point encoded as MPI.
172    ///
173    /// Decodes the MPI into a point on an elliptic curve (see
174    /// [Section 6 of RFC 6637] and [Section 13.2 of RFC4880bis] for
175    /// details).  If the point is not compressed, the function
176    /// returns `(x, y)`.  If it is compressed, `y` will be empty.
177    ///
178    ///   [Section 6 of RFC 6637]: https://tools.ietf.org/html/rfc6637#section-6
179    ///   [Section 13.2 of RFC4880bis]: https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-09#section-13.2
180    ///
181    /// # Errors
182    ///
183    /// Returns `Error::UnsupportedEllipticCurve` if the curve is not
184    /// supported, `Error::MalformedMPI` if the point is formatted
185    /// incorrectly, `Error::InvalidOperation` if the given curve is
186    /// operating on native octet strings.
187    pub fn decode_point(&self, curve: &Curve) -> Result<(&[u8], &[u8])> {
188        Self::decode_point_common(self.value(), curve)
189    }
190
191    /// Common implementation shared between MPI and ProtectedMPI.
192    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                // This curve uses a custom compression format which
201                // only contains the X coordinate.
202                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                // Length of one coordinate in bytes, rounded up.
228                let coordinate_length = curve.field_size()?;
229
230                // Check length of Q.
231                let expected_length =
232                    1 // 0x04.
233                    + (2 // (x, y)
234                       * 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    /// Securely compares two MPIs in constant time.
258    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/// Holds a single MPI containing secrets.
334///
335/// The memory will be cleared when the object is dropped.  Used by
336/// [`SecretKeyMaterial`] to protect secret keys.
337///
338#[derive(Clone)]
339pub struct ProtectedMPI {
340    /// Integer value as big-endian.
341    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)); // Erase source.
358        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)); // Erase source.
368        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); // Erase source.
378        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    /// Creates new MPI encoding an uncompressed EC point.
425    ///
426    /// Encodes the given point on an elliptic curve (see [Section 6 of
427    /// RFC 6637] for details).  This is used to encode public keys
428    /// and ciphertexts for the NIST curves (`NistP256`, `NistP384`,
429    /// and `NistP521`).
430    ///
431    ///   [Section 6 of RFC 6637]: https://tools.ietf.org/html/rfc6637#section-6
432    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    /// Creates new MPI encoding a compressed EC point using native
437    /// encoding.
438    ///
439    /// Encodes the given point on an elliptic curve (see [Section 13.2
440    /// of RFC4880bis] for details).  This is used to encode public
441    /// keys and ciphertexts for the Bernstein curves (currently
442    /// `X25519`).
443    ///
444    ///   [Section 13.2 of RFC4880bis]: https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-09#section-13.2
445    pub fn new_compressed_point(x: &[u8]) -> Self {
446        MPI::new_compressed_point_common(x).into()
447    }
448
449    /// Returns the length of the MPI in bits.
450    ///
451    /// Leading zero-bits are not included in the returned size.
452    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    /// Returns the value of this MPI.
459    ///
460    /// Note that due to stripping of zero-bytes, the returned value
461    /// may be shorter than expected.
462    pub fn value(&self) -> &[u8] {
463        &self.value
464    }
465
466    /// Returns the value of this MPI zero-padded to the given length.
467    ///
468    /// MPI-encoding strips leading zero-bytes.  This function adds
469    /// them back.  This operation is done unconditionally to avoid
470    /// timing differences.  If the size exceeds `to`, the result is
471    /// silently truncated to avoid timing differences.
472    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    /// Decodes an EC point encoded as MPI.
481    ///
482    /// Decodes the MPI into a point on an elliptic curve (see
483    /// [Section 6 of RFC 6637] and [Section 13.2 of RFC4880bis] for
484    /// details).  If the point is not compressed, the function
485    /// returns `(x, y)`.  If it is compressed, `y` will be empty.
486    ///
487    ///   [Section 6 of RFC 6637]: https://tools.ietf.org/html/rfc6637#section-6
488    ///   [Section 13.2 of RFC4880bis]: https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-09#section-13.2
489    ///
490    /// # Errors
491    ///
492    /// Returns `Error::UnsupportedEllipticCurve` if the curve is not
493    /// supported, `Error::MalformedMPI` if the point is formatted
494    /// incorrectly, `Error::InvalidOperation` if the given curve is
495    /// operating on native octet strings.
496    pub fn decode_point(&self, curve: &Curve) -> Result<(&[u8], &[u8])> {
497        MPI::decode_point_common(self.value(), curve)
498    }
499
500    /// Securely compares two MPIs in constant time.
501    fn secure_memcmp(&self, other: &Self) -> Ordering {
502        (self.value.len() as i32).cmp(&(other.value.len() as i32))
503            .then(
504                // Protected compares in constant time.
505                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/// A public key.
522///
523/// Provides a typed and structured way of storing multiple MPIs (and
524/// the occasional elliptic curve) in [`Key`] packets.
525///
526///   [`Key`]: crate::packet::Key
527#[non_exhaustive]
528#[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
529pub enum PublicKey {
530    /// RSA public key.
531    RSA {
532        /// Public exponent
533        e: MPI,
534        /// Public modulo N = pq.
535        n: MPI,
536    },
537
538    /// NIST DSA public key.
539    DSA {
540        /// Prime of the ring Zp.
541        p: MPI,
542        /// Order of `g` in Zp.
543        q: MPI,
544        /// Public generator of Zp.
545        g: MPI,
546        /// Public key g^x mod p.
547        y: MPI,
548    },
549
550    /// ElGamal public key.
551    ElGamal {
552        /// Prime of the ring Zp.
553        p: MPI,
554        /// Generator of Zp.
555        g: MPI,
556        /// Public key g^x mod p.
557        y: MPI,
558    },
559
560    /// DJB's "Twisted" Edwards curve DSA public key.
561    EdDSA {
562        /// Curve we're using. Must be curve 25519.
563        curve: Curve,
564        /// Public point.
565        q: MPI,
566    },
567
568    /// NIST's Elliptic Curve DSA public key.
569    ECDSA {
570        /// Curve we're using.
571        curve: Curve,
572        /// Public point.
573        q: MPI,
574    },
575
576    /// Elliptic Curve Diffie-Hellman public key.
577    ECDH {
578        /// Curve we're using.
579        curve: Curve,
580        /// Public point.
581        q: MPI,
582        /// Algorithm used to derive the Key Encapsulation Key.
583        hash: HashAlgorithm,
584        /// Algorithm used to encapsulate the session key.
585        sym: SymmetricAlgorithm,
586    },
587
588    /// X25519 public key.
589    X25519 {
590        /// The public key, an opaque string.
591        u: [u8; 32],
592    },
593
594    /// X448 public key.
595    X448 {
596        /// The public key, an opaque string.
597        u: Box<[u8; 56]>,
598    },
599
600    /// Ed25519 public key.
601    Ed25519 {
602        /// The public key, an opaque string.
603        a: [u8; 32],
604    },
605
606    /// Ed448 public key.
607    Ed448 {
608        /// The public key, an opaque string.
609        a: Box<[u8; 57]>,
610    },
611
612    /// Unknown number of MPIs for an unknown algorithm.
613    Unknown {
614        /// The successfully parsed MPIs.
615        mpis: Box<[MPI]>,
616        /// Any data that failed to parse.
617        rest: Box<[u8]>,
618    },
619}
620assert_send_and_sync!(PublicKey);
621
622impl fmt::Debug for PublicKey {
623    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
624        match self {
625            PublicKey::RSA { e, n } =>
626                f.debug_struct("RSA")
627                .field("e", e)
628                .field("n", n)
629                .finish(),
630
631            PublicKey::DSA { p, q, g, y } =>
632                f.debug_struct("DSA")
633                .field("p", p)
634                .field("q", q)
635                .field("g", g)
636                .field("y", y)
637                .finish(),
638
639            PublicKey::ElGamal { p, g, y } =>
640                f.debug_struct("ElGamal")
641                .field("p", p)
642                .field("g", g)
643                .field("y", y)
644                .finish(),
645
646            PublicKey::EdDSA { curve, q } =>
647                f.debug_struct("EdDSA")
648                .field("curve", curve)
649                .field("q", q)
650                .finish(),
651
652            PublicKey::ECDSA { curve, q } =>
653                f.debug_struct("ECDSA")
654                .field("curve", curve)
655                .field("q", q)
656                .finish(),
657
658            PublicKey::ECDH { curve, q, hash, sym } =>
659                f.debug_struct("ECDH")
660                .field("curve", curve)
661                .field("q", q)
662                .field("hash", hash)
663                .field("sym", sym)
664                .finish(),
665
666            PublicKey::X25519 { u } =>
667                f.debug_struct("X25519")
668                .field("u", &hex::encode(u))
669                .finish(),
670
671            PublicKey::X448 { u } =>
672                f.debug_struct("X448")
673                .field("u", &hex::encode(u.as_ref()))
674                .finish(),
675
676            PublicKey::Ed25519 { a } =>
677                f.debug_struct("Ed25519")
678                .field("a", &hex::encode(a))
679                .finish(),
680
681            PublicKey::Ed448 { a } =>
682                f.debug_struct("Ed448")
683                .field("a", &hex::encode(a.as_ref()))
684                .finish(),
685
686            PublicKey::Unknown { mpis, rest } =>
687                f.debug_struct("Unknown")
688                .field("mpis", mpis)
689                .field("rest", &hex::encode(rest))
690                .finish(),
691        }
692    }
693}
694
695impl PublicKey {
696    /// Returns the length of the public key in bits.
697    ///
698    /// For finite field crypto this returns the size of the field we
699    /// operate in, for ECC it returns `Curve::bits()`.
700    ///
701    /// Note: This information is useless and should not be used to
702    /// gauge the security of a particular key. This function exists
703    /// only because some legacy PGP application like HKP need it.
704    ///
705    /// Returns `None` for unknown keys and curves.
706    pub fn bits(&self) -> Option<usize> {
707        use self::PublicKey::*;
708        match self {
709            RSA { ref n,.. } => Some(n.bits()),
710            DSA { ref p,.. } => Some(p.bits()),
711            ElGamal { ref p,.. } => Some(p.bits()),
712            EdDSA { ref curve,.. } => curve.bits().ok(),
713            ECDSA { ref curve,.. } => curve.bits().ok(),
714            ECDH { ref curve,.. } => curve.bits().ok(),
715            X25519 { .. } => Some(256),
716            X448 { .. } => Some(448),
717            Ed25519 { .. } => Some(256),
718            Ed448 { .. } => Some(456),
719            Unknown { .. } => None,
720        }
721    }
722
723    /// Returns, if known, the public-key algorithm for this public
724    /// key.
725    pub fn algo(&self) -> Option<PublicKeyAlgorithm> {
726        use self::PublicKey::*;
727        #[allow(deprecated)]
728        match self {
729            RSA { .. } => Some(PublicKeyAlgorithm::RSAEncryptSign),
730            DSA { .. } => Some(PublicKeyAlgorithm::DSA),
731            ElGamal { .. } => Some(PublicKeyAlgorithm::ElGamalEncrypt),
732            EdDSA { .. } => Some(PublicKeyAlgorithm::EdDSA),
733            ECDSA { .. } => Some(PublicKeyAlgorithm::ECDSA),
734            ECDH { .. } => Some(PublicKeyAlgorithm::ECDH),
735            X25519 { .. } => Some(PublicKeyAlgorithm::X25519),
736            X448 { .. } => Some(PublicKeyAlgorithm::X448),
737            Ed25519 { .. } => Some(PublicKeyAlgorithm::Ed25519),
738            Ed448 { .. } => Some(PublicKeyAlgorithm::Ed448),
739            Unknown { .. } => None,
740        }
741    }
742}
743
744impl Hash for PublicKey {
745    fn hash(&self, mut hash: &mut hash::Context) -> Result<()> {
746        self.serialize(&mut hash as &mut dyn Write)
747    }
748}
749
750#[cfg(test)]
751impl Arbitrary for PublicKey {
752    fn arbitrary(g: &mut Gen) -> Self {
753        use self::PublicKey::*;
754        use crate::arbitrary_helper::gen_arbitrary_from_range;
755
756        match gen_arbitrary_from_range(0..10, g) {
757            0 => RSA {
758                e: MPI::arbitrary(g),
759                n: MPI::arbitrary(g),
760            },
761
762            1 => DSA {
763                p: MPI::arbitrary(g),
764                q: MPI::arbitrary(g),
765                g: MPI::arbitrary(g),
766                y: MPI::arbitrary(g),
767            },
768
769            2 => ElGamal {
770                p: MPI::arbitrary(g),
771                g: MPI::arbitrary(g),
772                y: MPI::arbitrary(g),
773            },
774
775            3 => EdDSA {
776                curve: Curve::arbitrary(g),
777                q: MPI::arbitrary(g),
778            },
779
780            4 => ECDSA {
781                curve: Curve::arbitrary(g),
782                q: MPI::arbitrary(g),
783            },
784
785            5 => ECDH {
786                curve: Curve::arbitrary(g),
787                q: MPI::arbitrary(g),
788                hash: HashAlgorithm::arbitrary(g),
789                sym: SymmetricAlgorithm::arbitrary(g),
790            },
791
792            6 => X25519 { u: arbitrary(g) },
793            7 => X448 { u: Box::new(arbitrarize(g, [0; 56])) },
794            8 => Ed25519 { a: arbitrary(g) },
795            9 => Ed448 { a: Box::new(arbitrarize(g, [0; 57])) },
796
797            _ => unreachable!(),
798        }
799    }
800}
801
802#[cfg(test)]
803pub(crate) fn arbitrarize<T: AsMut<[u8]>>(g: &mut Gen, mut a: T) -> T
804{
805    a.as_mut().iter_mut().for_each(|p| *p = Arbitrary::arbitrary(g));
806    a
807}
808
809#[cfg(test)]
810pub(crate) fn arbitrary<T: Default + AsMut<[u8]>>(g: &mut Gen) -> T
811{
812    arbitrarize(g, Default::default())
813}
814
815
816/// A secret key.
817///
818/// Provides a typed and structured way of storing multiple MPIs in
819/// [`Key`] packets.  Secret key components are protected by storing
820/// them using [`ProtectedMPI`].
821///
822///   [`Key`]: crate::packet::Key
823// Deriving Hash here is okay: PartialEq is manually implemented to
824// ensure that secrets are compared in constant-time.
825#[non_exhaustive]
826#[allow(clippy::derived_hash_with_manual_eq)]
827#[derive(Clone, Hash)]
828pub enum SecretKeyMaterial {
829    /// RSA secret key.
830    RSA {
831        /// Secret exponent, inverse of e in Phi(N).
832        d: ProtectedMPI,
833        /// Smaller secret prime.
834        p: ProtectedMPI,
835        /// Larger secret prime.
836        q: ProtectedMPI,
837        /// Inverse of p mod q.
838        u: ProtectedMPI,
839    },
840
841    /// NIST DSA secret key.
842    DSA {
843        /// Secret key log_g(y) in Zp.
844        x: ProtectedMPI,
845    },
846
847    /// ElGamal secret key.
848    ElGamal {
849        /// Secret key log_g(y) in Zp.
850        x: ProtectedMPI,
851    },
852
853    /// DJB's "Twisted" Edwards curve DSA secret key.
854    EdDSA {
855        /// Secret scalar.
856        scalar: ProtectedMPI,
857    },
858
859    /// NIST's Elliptic Curve DSA secret key.
860    ECDSA {
861        /// Secret scalar.
862        scalar: ProtectedMPI,
863    },
864
865    /// Elliptic Curve Diffie-Hellman secret key.
866    ECDH {
867        /// Secret scalar.
868        scalar: ProtectedMPI,
869    },
870
871    /// X25519 secret key.
872    X25519 {
873        /// The secret key, an opaque string.
874        x: Protected,
875    },
876
877    /// X448 secret key.
878    X448 {
879        /// The secret key, an opaque string.
880        x: Protected,
881    },
882
883    /// Ed25519 secret key.
884    Ed25519 {
885        /// The secret key, an opaque string.
886        x: Protected,
887    },
888
889    /// Ed448 secret key.
890    Ed448 {
891        /// The secret key, an opaque string.
892        x: Protected,
893    },
894
895    /// Unknown number of MPIs for an unknown algorithm.
896    Unknown {
897        /// The successfully parsed MPIs.
898        mpis: Box<[ProtectedMPI]>,
899        /// Any data that failed to parse.
900        rest: Protected,
901    },
902}
903assert_send_and_sync!(SecretKeyMaterial);
904
905impl fmt::Debug for SecretKeyMaterial {
906    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
907        if cfg!(debug_assertions) {
908            match self {
909                SecretKeyMaterial::RSA { d, p, q, u } =>
910                    f.debug_struct("RSA")
911                    .field("d", d)
912                    .field("p", p)
913                    .field("q", q)
914                    .field("u", u)
915                    .finish(),
916
917                SecretKeyMaterial::DSA { x } =>
918                    f.debug_struct("DSA")
919                    .field("x", x)
920                    .finish(),
921
922                SecretKeyMaterial::ElGamal { x } =>
923                    f.debug_struct("ElGamal")
924                    .field("x", x)
925                    .finish(),
926
927                SecretKeyMaterial::EdDSA { scalar } =>
928                    f.debug_struct("EdDSA")
929                    .field("scalar", scalar)
930                    .finish(),
931
932                SecretKeyMaterial::ECDSA { scalar } =>
933                    f.debug_struct("ECDSA")
934                    .field("scalar", scalar)
935                    .finish(),
936
937                SecretKeyMaterial::ECDH { scalar } =>
938                    f.debug_struct("ECDH")
939                    .field("scalar", scalar)
940                    .finish(),
941
942                SecretKeyMaterial::X25519 { x } =>
943                    f.debug_struct("X25519")
944                    .field("x", &hex::encode(x))
945                    .finish(),
946
947                SecretKeyMaterial::X448 { x } =>
948                    f.debug_struct("X448")
949                    .field("x", &hex::encode(x))
950                    .finish(),
951
952                SecretKeyMaterial::Ed25519 { x } =>
953                    f.debug_struct("Ed25519")
954                    .field("x", &hex::encode(x))
955                    .finish(),
956
957                SecretKeyMaterial::Ed448 { x } =>
958                    f.debug_struct("Ed448")
959                    .field("x", &hex::encode(x))
960                    .finish(),
961
962                SecretKeyMaterial::Unknown{ mpis, rest } =>
963                    f.debug_struct("Unknown")
964                    .field("mpis", mpis)
965                    .field("rest", &hex::encode(rest))
966                    .finish(),
967            }
968        } else {
969            match self {
970                SecretKeyMaterial::RSA{ .. } =>
971                    f.write_str("RSA { <Redacted> }"),
972                SecretKeyMaterial::DSA{ .. } =>
973                    f.write_str("DSA { <Redacted> }"),
974                SecretKeyMaterial::ElGamal{ .. } =>
975                    f.write_str("ElGamal { <Redacted> }"),
976                SecretKeyMaterial::EdDSA{ .. } =>
977                    f.write_str("EdDSA { <Redacted> }"),
978                SecretKeyMaterial::ECDSA{ .. } =>
979                    f.write_str("ECDSA { <Redacted> }"),
980                SecretKeyMaterial::ECDH{ .. } =>
981                    f.write_str("ECDH { <Redacted> }"),
982                SecretKeyMaterial::X25519 { .. } =>
983                    f.write_str("X25519 { <Redacted> }"),
984                SecretKeyMaterial::X448 { .. } =>
985                    f.write_str("X448 { <Redacted> }"),
986                SecretKeyMaterial::Ed25519 { .. } =>
987                    f.write_str("Ed25519 { <Redacted> }"),
988                SecretKeyMaterial::Ed448 { .. } =>
989                    f.write_str("Ed448 { <Redacted> }"),
990                SecretKeyMaterial::Unknown{ .. } =>
991                    f.write_str("Unknown { <Redacted> }"),
992            }
993        }
994    }
995}
996
997impl PartialOrd for SecretKeyMaterial {
998    fn partial_cmp(&self, other: &SecretKeyMaterial) -> Option<Ordering> {
999        Some(self.cmp(other))
1000    }
1001}
1002
1003impl Ord for SecretKeyMaterial {
1004    fn cmp(&self, other: &Self) -> Ordering {
1005        use std::iter;
1006
1007        fn discriminant(sk: &SecretKeyMaterial) -> usize {
1008            match sk {
1009                SecretKeyMaterial::RSA{ .. } => 0,
1010                SecretKeyMaterial::DSA{ .. } => 1,
1011                SecretKeyMaterial::ElGamal{ .. } => 2,
1012                SecretKeyMaterial::EdDSA{ .. } => 3,
1013                SecretKeyMaterial::ECDSA{ .. } => 4,
1014                SecretKeyMaterial::ECDH{ .. } => 5,
1015                SecretKeyMaterial::X25519 { .. } => 6,
1016                SecretKeyMaterial::X448 { .. } => 7,
1017                SecretKeyMaterial::Ed25519 { .. } => 8,
1018                SecretKeyMaterial::Ed448 { .. } => 9,
1019                SecretKeyMaterial::Unknown { .. } => 10,
1020            }
1021        }
1022
1023        let ret = match (self, other) {
1024            (&SecretKeyMaterial::RSA{ d: ref d1, p: ref p1, q: ref q1, u: ref u1 }
1025            ,&SecretKeyMaterial::RSA{ d: ref d2, p: ref p2, q: ref q2, u: ref u2 }) => {
1026                let o1 = d1.cmp(d2);
1027                let o2 = p1.cmp(p2);
1028                let o3 = q1.cmp(q2);
1029                let o4 = u1.cmp(u2);
1030
1031                if o1 != Ordering::Equal { return o1; }
1032                if o2 != Ordering::Equal { return o2; }
1033                if o3 != Ordering::Equal { return o3; }
1034                o4
1035            }
1036            (&SecretKeyMaterial::DSA{ x: ref x1 }
1037            ,&SecretKeyMaterial::DSA{ x: ref x2 }) => {
1038                x1.cmp(x2)
1039            }
1040            (&SecretKeyMaterial::ElGamal{ x: ref x1 }
1041            ,&SecretKeyMaterial::ElGamal{ x: ref x2 }) => {
1042                x1.cmp(x2)
1043            }
1044            (&SecretKeyMaterial::EdDSA{ scalar: ref scalar1 }
1045            ,&SecretKeyMaterial::EdDSA{ scalar: ref scalar2 }) => {
1046                scalar1.cmp(scalar2)
1047            }
1048            (&SecretKeyMaterial::ECDSA{ scalar: ref scalar1 }
1049            ,&SecretKeyMaterial::ECDSA{ scalar: ref scalar2 }) => {
1050                scalar1.cmp(scalar2)
1051            }
1052            (&SecretKeyMaterial::ECDH{ scalar: ref scalar1 }
1053            ,&SecretKeyMaterial::ECDH{ scalar: ref scalar2 }) => {
1054                scalar1.cmp(scalar2)
1055            }
1056            (SecretKeyMaterial::X25519 { x: x0 },
1057             SecretKeyMaterial::X25519 { x: x1 }) => x0.cmp(x1),
1058            (SecretKeyMaterial::X448 { x: x0 },
1059             SecretKeyMaterial::X448 { x: x1 }) => x0.cmp(x1),
1060            (SecretKeyMaterial::Ed25519 { x: x0 },
1061             SecretKeyMaterial::Ed25519 { x: x1 }) => x0.cmp(x1),
1062            (SecretKeyMaterial::Ed448 { x: x0 },
1063             SecretKeyMaterial::Ed448 { x: x1 }) => x0.cmp(x1),
1064
1065            (&SecretKeyMaterial::Unknown{ mpis: ref mpis1, rest: ref rest1 }
1066            ,&SecretKeyMaterial::Unknown{ mpis: ref mpis2, rest: ref rest2 }) => {
1067                let o1 = secure_cmp(rest1, rest2);
1068                let o2 = mpis1.len().cmp(&mpis2.len());
1069                let on = mpis1.iter().zip(mpis2.iter()).map(|(a,b)| {
1070                    a.cmp(b)
1071                }).collect::<Vec<_>>();
1072
1073                iter::once(o1)
1074                    .chain(iter::once(o2))
1075                    .chain(on.iter().cloned())
1076                    .fold(Ordering::Equal, |acc, x| acc.then(x))
1077            }
1078
1079            (a, b) => {
1080                let ret = discriminant(a).cmp(&discriminant(b));
1081
1082                assert!(ret != Ordering::Equal);
1083                ret
1084            }
1085        };
1086
1087        ret
1088    }
1089}
1090
1091impl PartialEq for SecretKeyMaterial {
1092    fn eq(&self, other: &Self) -> bool { self.cmp(other) == Ordering::Equal }
1093}
1094
1095impl Eq for SecretKeyMaterial {}
1096
1097impl SecretKeyMaterial {
1098    /// Returns, if known, the public-key algorithm for this secret
1099    /// key.
1100    pub fn algo(&self) -> Option<PublicKeyAlgorithm> {
1101        use self::SecretKeyMaterial::*;
1102        #[allow(deprecated)]
1103        match self {
1104            RSA { .. } => Some(PublicKeyAlgorithm::RSAEncryptSign),
1105            DSA { .. } => Some(PublicKeyAlgorithm::DSA),
1106            ElGamal { .. } => Some(PublicKeyAlgorithm::ElGamalEncrypt),
1107            EdDSA { .. } => Some(PublicKeyAlgorithm::EdDSA),
1108            ECDSA { .. } => Some(PublicKeyAlgorithm::ECDSA),
1109            ECDH { .. } => Some(PublicKeyAlgorithm::ECDH),
1110            X25519 { .. } => Some(PublicKeyAlgorithm::X25519),
1111            X448 { .. } => Some(PublicKeyAlgorithm::X448),
1112            Ed25519 { .. } => Some(PublicKeyAlgorithm::Ed25519),
1113            Ed448 { .. } => Some(PublicKeyAlgorithm::Ed448),
1114            Unknown { .. } => None,
1115        }
1116    }
1117}
1118
1119impl Hash for SecretKeyMaterial {
1120    fn hash(&self, mut hash: &mut hash::Context) -> Result<()> {
1121        self.serialize(&mut hash as &mut dyn Write)
1122    }
1123}
1124
1125#[cfg(test)]
1126impl SecretKeyMaterial {
1127    pub(crate) fn arbitrary_for(g: &mut Gen, pk: PublicKeyAlgorithm) -> Result<Self> {
1128        use self::PublicKeyAlgorithm::*;
1129        #[allow(deprecated)]
1130        match pk {
1131            RSAEncryptSign | RSASign | RSAEncrypt => Ok(SecretKeyMaterial::RSA {
1132                d: ProtectedMPI::arbitrary(g),
1133                p: ProtectedMPI::arbitrary(g),
1134                q: ProtectedMPI::arbitrary(g),
1135                u: ProtectedMPI::arbitrary(g),
1136            }),
1137
1138            DSA => Ok(SecretKeyMaterial::DSA {
1139                x: ProtectedMPI::arbitrary(g),
1140            }),
1141
1142            ElGamalEncryptSign | ElGamalEncrypt => Ok(SecretKeyMaterial::ElGamal {
1143                x: ProtectedMPI::arbitrary(g),
1144            }),
1145
1146            EdDSA => Ok(SecretKeyMaterial::EdDSA {
1147                scalar: ProtectedMPI::arbitrary(g),
1148            }),
1149
1150            ECDSA => Ok(SecretKeyMaterial::ECDSA {
1151                scalar: ProtectedMPI::arbitrary(g),
1152            }),
1153
1154            ECDH => Ok(SecretKeyMaterial::ECDH {
1155                scalar: ProtectedMPI::arbitrary(g),
1156            }),
1157
1158            X25519 => Ok(SecretKeyMaterial::X25519 {
1159                x: arbitrarize(g, vec![0; 32]).into(),
1160            }),
1161            X448 => Ok(SecretKeyMaterial::X448 {
1162                x: arbitrarize(g, vec![0; 56]).into(),
1163            }),
1164            Ed25519 => Ok(SecretKeyMaterial::Ed25519 {
1165                x: arbitrarize(g, vec![0; 32]).into(),
1166            }),
1167            Ed448 => Ok(SecretKeyMaterial::Ed448 {
1168                x: arbitrarize(g, vec![0; 57]).into(),
1169            }),
1170
1171            Private(_) | Unknown(_) =>
1172                Err(Error::UnsupportedPublicKeyAlgorithm(pk).into()),
1173        }
1174    }
1175}
1176#[cfg(test)]
1177impl Arbitrary for SecretKeyMaterial {
1178    fn arbitrary(g: &mut Gen) -> Self {
1179        let pk = *g.choose(
1180            &crate::crypto::types::public_key_algorithm::PUBLIC_KEY_ALGORITHM_VARIANTS)
1181            .expect("not empty");
1182        Self::arbitrary_for(g, pk).expect("only known variants")
1183    }
1184}
1185
1186/// Checksum method for secret key material.
1187///
1188/// Secret key material may be protected by a checksum.  See [Section
1189/// 5.5.3 of RFC 9580] for details.
1190///
1191///   [Section 5.5.3 of RFC 9580]: https://www.rfc-editor.org/rfc/rfc9580.html#section-5.5.3
1192#[derive(PartialEq, Eq, Hash, Clone, Copy, Debug)]
1193pub enum SecretKeyChecksum {
1194    /// SHA1 over the decrypted secret key.
1195    SHA1,
1196
1197    /// Sum of the decrypted secret key octets modulo 65536.
1198    Sum16,
1199}
1200assert_send_and_sync!(SecretKeyChecksum);
1201
1202impl Default for SecretKeyChecksum {
1203    fn default() -> Self {
1204        SecretKeyChecksum::SHA1
1205    }
1206}
1207
1208impl SecretKeyChecksum {
1209    /// Returns the on-wire length of the checksum.
1210    pub(crate) fn len(&self) -> usize {
1211        match self {
1212            SecretKeyChecksum::SHA1 => 20,
1213            SecretKeyChecksum::Sum16 => 2,
1214        }
1215    }
1216}
1217
1218/// An encrypted session key.
1219///
1220/// Provides a typed and structured way of storing multiple MPIs in
1221/// [`PKESK`] packets.
1222///
1223///   [`PKESK`]: crate::packet::PKESK
1224#[non_exhaustive]
1225#[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
1226pub enum Ciphertext {
1227    /// RSA ciphertext.
1228    RSA {
1229        ///  m^e mod N.
1230        c: MPI,
1231    },
1232
1233    /// ElGamal ciphertext.
1234    ElGamal {
1235        /// Ephemeral key.
1236        e: MPI,
1237        /// Ciphertext.
1238        c: MPI,
1239    },
1240
1241    /// Elliptic curve ElGamal public key.
1242    ECDH {
1243        /// Ephemeral key.
1244        e: MPI,
1245        /// Symmetrically encrypted session key.
1246        key: Box<[u8]>,
1247    },
1248
1249    /// X25519 ciphertext.
1250    X25519 {
1251        /// Ephermeral key.
1252        e: Box<[u8; 32]>,
1253        /// Symmetrically encrypted session key.
1254        key: Box<[u8]>,
1255    },
1256
1257    /// X448 ciphertext.
1258    X448 {
1259        /// Ephermeral key.
1260        e: Box<[u8; 56]>,
1261        /// Symmetrically encrypted session key.
1262        key: Box<[u8]>,
1263    },
1264
1265    /// Unknown number of MPIs for an unknown algorithm.
1266    Unknown {
1267        /// The successfully parsed MPIs.
1268        mpis: Box<[MPI]>,
1269        /// Any data that failed to parse.
1270        rest: Box<[u8]>,
1271    },
1272}
1273assert_send_and_sync!(Ciphertext);
1274
1275impl fmt::Debug for Ciphertext {
1276    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1277        match self {
1278            Ciphertext::RSA { c } =>
1279                f.debug_struct("RSA")
1280                .field("c", c)
1281                .finish(),
1282
1283            Ciphertext::ElGamal { e, c } =>
1284                f.debug_struct("ElGamal")
1285                .field("e", e)
1286                .field("c", c)
1287                .finish(),
1288
1289            Ciphertext::ECDH { e, key } =>
1290                f.debug_struct("ECDH")
1291                .field("e", e)
1292                .field("key", &hex::encode(key))
1293                .finish(),
1294
1295            Ciphertext::X25519 { e, key } =>
1296                f.debug_struct("X25519")
1297                .field("e", &hex::encode(&e[..]))
1298                .field("key", &hex::encode(key))
1299                .finish(),
1300
1301            Ciphertext::X448 { e, key } =>
1302                f.debug_struct("X448")
1303                .field("e", &hex::encode(&e[..]))
1304                .field("key", &hex::encode(key))
1305                .finish(),
1306
1307            Ciphertext::Unknown { mpis, rest } =>
1308                f.debug_struct("Unknown")
1309                .field("mpis", mpis)
1310                .field("rest", &hex::encode(rest))
1311                .finish(),
1312        }
1313    }
1314}
1315
1316impl Ciphertext {
1317    /// Returns, if known, the public-key algorithm for this
1318    /// ciphertext.
1319    pub fn pk_algo(&self) -> Option<PublicKeyAlgorithm> {
1320        use self::Ciphertext::*;
1321
1322        // Fields are mostly MPIs that consist of two octets length
1323        // plus the big endian value itself. All other field types are
1324        // commented.
1325        #[allow(deprecated)]
1326        match self {
1327            RSA { .. } => Some(PublicKeyAlgorithm::RSAEncryptSign),
1328            ElGamal { .. } => Some(PublicKeyAlgorithm::ElGamalEncrypt),
1329            ECDH { .. } => Some(PublicKeyAlgorithm::ECDH),
1330            X25519 { .. } => Some(PublicKeyAlgorithm::X25519),
1331            X448 { .. } => Some(PublicKeyAlgorithm::X448),
1332            Unknown { .. } => None,
1333        }
1334    }
1335}
1336
1337impl Hash for Ciphertext {
1338    fn hash(&self, mut hash: &mut hash::Context) -> Result<()> {
1339        self.serialize(&mut hash as &mut dyn Write)
1340    }
1341}
1342
1343#[cfg(test)]
1344impl Arbitrary for Ciphertext {
1345    fn arbitrary(g: &mut Gen) -> Self {
1346        use crate::arbitrary_helper::gen_arbitrary_from_range;
1347
1348        match gen_arbitrary_from_range(0..5, g) {
1349            0 => Ciphertext::RSA {
1350                c: MPI::arbitrary(g),
1351            },
1352
1353            1 => Ciphertext::ElGamal {
1354                e: MPI::arbitrary(g),
1355                c: MPI::arbitrary(g)
1356            },
1357
1358            2 => Ciphertext::ECDH {
1359                e: MPI::arbitrary(g),
1360                key: {
1361                    let mut k = <Vec<u8>>::arbitrary(g);
1362                    k.truncate(255);
1363                    k.into_boxed_slice()
1364                },
1365            },
1366
1367            3 => Ciphertext::X25519 {
1368                e: Box::new(arbitrary(g)),
1369                key: {
1370                    let mut k = <Vec<u8>>::arbitrary(g);
1371                    k.truncate(255);
1372                    k.into_boxed_slice()
1373                },
1374            },
1375
1376            4 => Ciphertext::X448 {
1377                e: Box::new(arbitrarize(g, [0; 56])),
1378                key: {
1379                    let mut k = <Vec<u8>>::arbitrary(g);
1380                    k.truncate(255);
1381                    k.into_boxed_slice()
1382                },
1383            },
1384            _ => unreachable!(),
1385        }
1386    }
1387}
1388
1389/// A cryptographic signature.
1390///
1391/// Provides a typed and structured way of storing multiple MPIs in
1392/// [`Signature`] packets.
1393///
1394///   [`Signature`]: crate::packet::Signature
1395#[non_exhaustive]
1396#[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
1397pub enum Signature {
1398    /// RSA signature.
1399    RSA {
1400        /// Signature m^d mod N.
1401        s: MPI,
1402    },
1403
1404    /// NIST's DSA signature.
1405    DSA {
1406        /// `r` value.
1407        r: MPI,
1408        /// `s` value.
1409        s: MPI,
1410    },
1411
1412    /// ElGamal signature.
1413    ElGamal {
1414        /// `r` value.
1415        r: MPI,
1416        /// `s` value.
1417        s: MPI,
1418    },
1419
1420    /// DJB's "Twisted" Edwards curve DSA signature.
1421    EdDSA {
1422        /// `r` value.
1423        r: MPI,
1424        /// `s` value.
1425        s: MPI,
1426    },
1427
1428    /// NIST's Elliptic curve DSA signature.
1429    ECDSA {
1430        /// `r` value.
1431        r: MPI,
1432        /// `s` value.
1433        s: MPI,
1434    },
1435
1436    /// Ed25519 signature.
1437    Ed25519 {
1438        /// The signature.
1439        s: Box<[u8; 64]>,
1440    },
1441
1442    /// Ed448 signature.
1443    Ed448 {
1444        /// The signature.
1445        s: Box<[u8; 114]>,
1446    },
1447
1448    /// Unknown number of MPIs for an unknown algorithm.
1449    Unknown {
1450        /// The successfully parsed MPIs.
1451        mpis: Box<[MPI]>,
1452        /// Any data that failed to parse.
1453        rest: Box<[u8]>,
1454    },
1455}
1456assert_send_and_sync!(Signature);
1457
1458impl fmt::Debug for Signature {
1459    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1460        match self {
1461            Signature::RSA { s } =>
1462                f.debug_struct("RSA")
1463                .field("s", s)
1464                .finish(),
1465
1466            Signature::DSA { r, s } =>
1467                f.debug_struct("DSA")
1468                .field("r", r)
1469                .field("s", s)
1470                .finish(),
1471
1472            Signature::ElGamal { r, s } =>
1473                f.debug_struct("ElGamal")
1474                .field("r", r)
1475                .field("s", s)
1476                .finish(),
1477
1478            Signature::EdDSA { r, s } =>
1479                f.debug_struct("EdDSA")
1480                .field("r", r)
1481                .field("s", s)
1482                .finish(),
1483
1484            Signature::ECDSA { r, s } =>
1485                f.debug_struct("ECDSA")
1486                .field("r", r)
1487                .field("s", s)
1488                .finish(),
1489
1490            Signature::Ed25519 { s } =>
1491                f.debug_struct("Ed25519")
1492                .field("s", &hex::encode(&s[..]))
1493                .finish(),
1494
1495            Signature::Ed448 { s } =>
1496                f.debug_struct("Ed448")
1497                .field("s", &hex::encode(&s[..]))
1498                .finish(),
1499
1500            Signature::Unknown { mpis, rest } =>
1501                f.debug_struct("Unknown")
1502                .field("mpis", mpis)
1503                .field("rest", &hex::encode(rest))
1504                .finish(),
1505        }
1506    }
1507}
1508
1509impl Hash for Signature {
1510    fn hash(&self, mut hash: &mut hash::Context) -> Result<()> {
1511        self.serialize(&mut hash as &mut dyn Write)
1512    }
1513}
1514
1515#[cfg(test)]
1516impl Arbitrary for Signature {
1517    fn arbitrary(g: &mut Gen) -> Self {
1518        use crate::arbitrary_helper::gen_arbitrary_from_range;
1519
1520        match gen_arbitrary_from_range(0..6, g) {
1521            0 => Signature::RSA  {
1522                s: MPI::arbitrary(g),
1523            },
1524
1525            1 => Signature::DSA {
1526                r: MPI::arbitrary(g),
1527                s: MPI::arbitrary(g),
1528            },
1529
1530            2 => Signature::EdDSA  {
1531                r: MPI::arbitrary(g),
1532                s: MPI::arbitrary(g),
1533            },
1534
1535            3 => Signature::ECDSA  {
1536                r: MPI::arbitrary(g),
1537                s: MPI::arbitrary(g),
1538            },
1539
1540            4 => Signature::Ed25519  {
1541                s: Box::new(arbitrarize(g, [0; 64])),
1542            },
1543
1544            5 => Signature::Ed448  {
1545                s: Box::new(arbitrarize(g, [0; 114])),
1546            },
1547
1548            _ => unreachable!(),
1549        }
1550    }
1551}
1552
1553#[cfg(test)]
1554mod tests {
1555    use super::*;
1556    use crate::parse::Parse;
1557
1558    quickcheck! {
1559        fn mpi_roundtrip(mpi: MPI) -> bool {
1560            let mut buf = Vec::new();
1561            mpi.serialize(&mut buf).unwrap();
1562            MPI::from_bytes(&buf).unwrap() == mpi
1563        }
1564    }
1565
1566    quickcheck! {
1567        fn pk_roundtrip(pk: PublicKey) -> bool {
1568            use std::io::Cursor;
1569
1570            let mut buf = Vec::new();
1571            pk.serialize(&mut buf).unwrap();
1572            let cur = Cursor::new(buf);
1573            let pk_ = PublicKey::parse(pk.algo().unwrap(), cur).unwrap();
1574
1575            pk == pk_
1576        }
1577    }
1578
1579    #[test]
1580    fn pk_bits() {
1581        for (name, key_no, bits) in &[
1582            ("testy.pgp", 0, 2048),
1583            ("testy-new.pgp", 1, 256),
1584            ("dennis-simon-anton.pgp", 0, 2048),
1585            ("dsa2048-elgamal3072.pgp", 1, 3072),
1586            ("emmelie-dorothea-dina-samantha-awina-ed25519.pgp", 0, 256),
1587            ("erika-corinna-daniela-simone-antonia-nistp256.pgp", 0, 256),
1588            ("erika-corinna-daniela-simone-antonia-nistp384.pgp", 0, 384),
1589            ("erika-corinna-daniela-simone-antonia-nistp521.pgp", 0, 521),
1590        ] {
1591            let cert = crate::Cert::from_bytes(crate::tests::key(name)).unwrap();
1592            let ka = cert.keys().nth(*key_no).unwrap();
1593            assert_eq!(ka.key().mpis().bits().unwrap(), *bits,
1594                       "Cert {}, key no {}", name, *key_no);
1595        }
1596    }
1597
1598    quickcheck! {
1599        fn sk_roundtrip(sk: SecretKeyMaterial) -> bool {
1600            let mut buf = Vec::new();
1601            sk.serialize(&mut buf).unwrap();
1602            let sk_ =
1603                SecretKeyMaterial::from_bytes(sk.algo().unwrap(),
1604                                              &buf).unwrap();
1605
1606            sk == sk_
1607        }
1608    }
1609
1610    quickcheck! {
1611        fn ct_roundtrip(ct: Ciphertext) -> bool {
1612            use std::io::Cursor;
1613
1614            let mut buf = Vec::new();
1615            ct.serialize(&mut buf).unwrap();
1616            let cur = Cursor::new(buf);
1617            let ct_ = Ciphertext::parse(ct.pk_algo().unwrap(), cur).unwrap();
1618
1619            ct == ct_
1620        }
1621    }
1622
1623    quickcheck! {
1624        fn signature_roundtrip(sig: Signature) -> bool {
1625            use std::io::Cursor;
1626            use crate::PublicKeyAlgorithm::*;
1627
1628            let mut buf = Vec::new();
1629            sig.serialize(&mut buf).unwrap();
1630            let cur = Cursor::new(buf);
1631
1632            #[allow(deprecated)]
1633            let sig_ = match &sig {
1634                Signature::RSA { .. } =>
1635                    Signature::parse(RSAEncryptSign, cur).unwrap(),
1636                Signature::DSA { .. } =>
1637                    Signature::parse(DSA, cur).unwrap(),
1638                Signature::ElGamal { .. } =>
1639                    Signature::parse(ElGamalEncryptSign, cur).unwrap(),
1640                Signature::EdDSA { .. } =>
1641                    Signature::parse(EdDSA, cur).unwrap(),
1642                Signature::ECDSA { .. } =>
1643                    Signature::parse(ECDSA, cur).unwrap(),
1644                Signature::Ed25519 { .. } =>
1645                    Signature::parse(Ed25519, cur).unwrap(),
1646                Signature::Ed448 { .. } =>
1647                    Signature::parse(Ed448, cur).unwrap(),
1648
1649                Signature::Unknown { .. } => unreachable!(),
1650            };
1651
1652            sig == sig_
1653        }
1654    }
1655}