Skip to main content

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#[allow(non_camel_case_types)]
529#[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
530pub enum PublicKey {
531    /// RSA public key.
532    RSA {
533        /// Public exponent
534        e: MPI,
535        /// Public modulo N = pq.
536        n: MPI,
537    },
538
539    /// NIST DSA public key.
540    DSA {
541        /// Prime of the ring Zp.
542        p: MPI,
543        /// Order of `g` in Zp.
544        q: MPI,
545        /// Public generator of Zp.
546        g: MPI,
547        /// Public key g^x mod p.
548        y: MPI,
549    },
550
551    /// ElGamal public key.
552    ElGamal {
553        /// Prime of the ring Zp.
554        p: MPI,
555        /// Generator of Zp.
556        g: MPI,
557        /// Public key g^x mod p.
558        y: MPI,
559    },
560
561    /// DJB's "Twisted" Edwards curve DSA public key.
562    EdDSA {
563        /// Curve we're using. Must be curve 25519.
564        curve: Curve,
565        /// Public point.
566        q: MPI,
567    },
568
569    /// NIST's Elliptic Curve DSA public key.
570    ECDSA {
571        /// Curve we're using.
572        curve: Curve,
573        /// Public point.
574        q: MPI,
575    },
576
577    /// Elliptic Curve Diffie-Hellman public key.
578    ECDH {
579        /// Curve we're using.
580        curve: Curve,
581        /// Public point.
582        q: MPI,
583        /// Algorithm used to derive the Key Encapsulation Key.
584        hash: HashAlgorithm,
585        /// Algorithm used to encapsulate the session key.
586        sym: SymmetricAlgorithm,
587    },
588
589    /// X25519 public key.
590    X25519 {
591        /// The public key, an opaque string.
592        u: [u8; 32],
593    },
594
595    /// X448 public key.
596    X448 {
597        /// The public key, an opaque string.
598        u: Box<[u8; 56]>,
599    },
600
601    /// Ed25519 public key.
602    Ed25519 {
603        /// The public key, an opaque string.
604        a: [u8; 32],
605    },
606
607    /// Ed448 public key.
608    Ed448 {
609        /// The public key, an opaque string.
610        a: Box<[u8; 57]>,
611    },
612
613    /// Composite signature algorithm using ML-DSA-65 and Ed25519.
614    MLDSA65_Ed25519 {
615        /// The Ed25519 public key, an opaque string.
616        eddsa: Box<[u8; 32]>,
617
618        /// The ML-DSA public key, an opaque string.
619        mldsa: Box<[u8; 1952]>,
620    },
621
622    /// Composite signature algorithm using ML-DSA-87 and Ed448.
623    MLDSA87_Ed448 {
624        /// The Ed448 public key, an opaque string.
625        eddsa: Box<[u8; 57]>,
626
627        /// The ML-DSA public key, an opaque string.
628        mldsa: Box<[u8; 2592]>,
629    },
630
631    /// SLH-DSA-SHAKE-128s public key.
632    SLHDSA128s {
633        /// The public key, an opaque string.
634        public: [u8; 32],
635    },
636
637    /// SLH-DSA-SHAKE-128f public key.
638    SLHDSA128f {
639        /// The public key, an opaque string.
640        public: [u8; 32],
641    },
642
643    /// SLH-DSA-SHAKE-256s public key.
644    SLHDSA256s {
645        /// The public key, an opaque string.
646        public: Box<[u8; 64]>,
647    },
648
649    /// Composite KEM using ML-KEM-768 and X25519.
650    MLKEM768_X25519 {
651        /// The X25519 public key, an opaque string.
652        ecdh: Box<[u8; 32]>,
653
654        /// The ML-KEM public key, an opaque string.
655        mlkem: Box<[u8; 1184]>,
656    },
657
658    /// Composite KEM using ML-KEM-1024 and X448.
659    MLKEM1024_X448 {
660        /// The X448 public key, an opaque string.
661        ecdh: Box<[u8; 56]>,
662
663        /// The ML-KEM public key, an opaque string.
664        mlkem: Box<[u8; 1568]>,
665    },
666
667    /// Unknown number of MPIs for an unknown algorithm.
668    Unknown {
669        /// The successfully parsed MPIs.
670        mpis: Box<[MPI]>,
671        /// Any data that failed to parse.
672        rest: Box<[u8]>,
673    },
674}
675assert_send_and_sync!(PublicKey);
676
677impl fmt::Debug for PublicKey {
678    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
679        match self {
680            PublicKey::RSA { e, n } =>
681                f.debug_struct("RSA")
682                .field("e", e)
683                .field("n", n)
684                .finish(),
685
686            PublicKey::DSA { p, q, g, y } =>
687                f.debug_struct("DSA")
688                .field("p", p)
689                .field("q", q)
690                .field("g", g)
691                .field("y", y)
692                .finish(),
693
694            PublicKey::ElGamal { p, g, y } =>
695                f.debug_struct("ElGamal")
696                .field("p", p)
697                .field("g", g)
698                .field("y", y)
699                .finish(),
700
701            PublicKey::EdDSA { curve, q } =>
702                f.debug_struct("EdDSA")
703                .field("curve", curve)
704                .field("q", q)
705                .finish(),
706
707            PublicKey::ECDSA { curve, q } =>
708                f.debug_struct("ECDSA")
709                .field("curve", curve)
710                .field("q", q)
711                .finish(),
712
713            PublicKey::ECDH { curve, q, hash, sym } =>
714                f.debug_struct("ECDH")
715                .field("curve", curve)
716                .field("q", q)
717                .field("hash", hash)
718                .field("sym", sym)
719                .finish(),
720
721            PublicKey::X25519 { u } =>
722                f.debug_struct("X25519")
723                .field("u", &hex::encode(u))
724                .finish(),
725
726            PublicKey::X448 { u } =>
727                f.debug_struct("X448")
728                .field("u", &hex::encode(u.as_ref()))
729                .finish(),
730
731            PublicKey::Ed25519 { a } =>
732                f.debug_struct("Ed25519")
733                .field("a", &hex::encode(a))
734                .finish(),
735
736            PublicKey::Ed448 { a } =>
737                f.debug_struct("Ed448")
738                .field("a", &hex::encode(a.as_ref()))
739                .finish(),
740
741            PublicKey::MLDSA65_Ed25519 { eddsa, mldsa } =>
742                f.debug_struct("MLDSA65_Ed25519")
743                .field("eddsa", &hex::encode(eddsa.as_ref()))
744                .field("mldsa", &hex::encode(mldsa.as_ref()))
745                .finish(),
746
747            PublicKey::MLDSA87_Ed448 { eddsa, mldsa } =>
748                f.debug_struct("MLDSA87_Ed448")
749                .field("eddsa", &hex::encode(eddsa.as_ref()))
750                .field("mldsa", &hex::encode(mldsa.as_ref()))
751                .finish(),
752
753            PublicKey::SLHDSA128s { public } =>
754                f.debug_struct("SLHDSA128s")
755                .field("public", &hex::encode(public))
756                .finish(),
757
758            PublicKey::SLHDSA128f { public } =>
759                f.debug_struct("SLHDSA128f")
760                .field("public", &hex::encode(public))
761                .finish(),
762
763            PublicKey::SLHDSA256s { public } =>
764                f.debug_struct("SLHDSA256s")
765                .field("public", &hex::encode(public.as_ref()))
766                .finish(),
767
768            PublicKey::MLKEM768_X25519 { ecdh, mlkem } =>
769                f.debug_struct("MLKEM768_X25519")
770                .field("ecdh", &hex::encode(ecdh.as_ref()))
771                .field("mlkem", &hex::encode(mlkem.as_ref()))
772                .finish(),
773
774            PublicKey::MLKEM1024_X448 { ecdh, mlkem } =>
775                f.debug_struct("MLKEM1024_X448")
776                .field("ecdh", &hex::encode(ecdh.as_ref()))
777                .field("mlkem", &hex::encode(mlkem.as_ref()))
778                .finish(),
779
780            PublicKey::Unknown { mpis, rest } =>
781                f.debug_struct("Unknown")
782                .field("mpis", mpis)
783                .field("rest", &hex::encode(rest))
784                .finish(),
785        }
786    }
787}
788
789impl PublicKey {
790    /// Returns the length of the public key in bits.
791    ///
792    /// For finite field crypto this returns the size of the field we
793    /// operate in, for ECC it returns `Curve::bits()`.
794    ///
795    /// Note: This information is useless and should not be used to
796    /// gauge the security of a particular key. This function exists
797    /// only because some legacy PGP application like HKP need it.
798    ///
799    /// Returns `None` for unknown keys and curves.
800    pub fn bits(&self) -> Option<usize> {
801        use self::PublicKey::*;
802        match self {
803            RSA { ref n,.. } => Some(n.bits()),
804            DSA { ref p,.. } => Some(p.bits()),
805            ElGamal { ref p,.. } => Some(p.bits()),
806            EdDSA { ref curve,.. } => curve.bits().ok(),
807            ECDSA { ref curve,.. } => curve.bits().ok(),
808            ECDH { ref curve,.. } => curve.bits().ok(),
809            X25519 { .. } => Some(256),
810            X448 { .. } => Some(448),
811            Ed25519 { .. } => Some(256),
812            Ed448 { .. } => Some(456),
813            MLDSA65_Ed25519 { .. } => None,
814            MLDSA87_Ed448 { .. } => None,
815            SLHDSA128s { .. } => None,
816            SLHDSA128f { .. } => None,
817            SLHDSA256s { .. } => None,
818            MLKEM768_X25519 { .. } => None,
819            MLKEM1024_X448 { .. } => None,
820            Unknown { .. } => None,
821        }
822    }
823
824    /// Returns, if known, the public-key algorithm for this public
825    /// key.
826    pub fn algo(&self) -> Option<PublicKeyAlgorithm> {
827        use self::PublicKey::*;
828        #[allow(deprecated)]
829        match self {
830            RSA { .. } => Some(PublicKeyAlgorithm::RSAEncryptSign),
831            DSA { .. } => Some(PublicKeyAlgorithm::DSA),
832            ElGamal { .. } => Some(PublicKeyAlgorithm::ElGamalEncrypt),
833            EdDSA { .. } => Some(PublicKeyAlgorithm::EdDSA),
834            ECDSA { .. } => Some(PublicKeyAlgorithm::ECDSA),
835            ECDH { .. } => Some(PublicKeyAlgorithm::ECDH),
836            X25519 { .. } => Some(PublicKeyAlgorithm::X25519),
837            X448 { .. } => Some(PublicKeyAlgorithm::X448),
838            Ed25519 { .. } => Some(PublicKeyAlgorithm::Ed25519),
839            Ed448 { .. } => Some(PublicKeyAlgorithm::Ed448),
840            MLDSA65_Ed25519 { .. } =>
841                Some(PublicKeyAlgorithm::MLDSA65_Ed25519),
842            MLDSA87_Ed448 { .. } =>
843                Some(PublicKeyAlgorithm::MLDSA87_Ed448),
844            SLHDSA128s { .. } => Some(PublicKeyAlgorithm::SLHDSA128s),
845            SLHDSA128f { .. } => Some(PublicKeyAlgorithm::SLHDSA128f),
846            SLHDSA256s { .. } => Some(PublicKeyAlgorithm::SLHDSA256s),
847            MLKEM768_X25519 { .. } =>
848                Some(PublicKeyAlgorithm::MLKEM768_X25519),
849            MLKEM1024_X448 { .. } =>
850                Some(PublicKeyAlgorithm::MLKEM1024_X448),
851            Unknown { .. } => None,
852        }
853    }
854}
855
856impl Hash for PublicKey {
857    fn hash(&self, mut hash: &mut hash::Context) -> Result<()> {
858        self.serialize(&mut hash as &mut dyn Write)
859    }
860}
861
862#[cfg(test)]
863impl Arbitrary for PublicKey {
864    fn arbitrary(g: &mut Gen) -> Self {
865        use self::PublicKey::*;
866        use crate::arbitrary_helper::gen_arbitrary_from_range;
867
868        match gen_arbitrary_from_range(0..17, g) {
869            0 => RSA {
870                e: MPI::arbitrary(g),
871                n: MPI::arbitrary(g),
872            },
873
874            1 => DSA {
875                p: MPI::arbitrary(g),
876                q: MPI::arbitrary(g),
877                g: MPI::arbitrary(g),
878                y: MPI::arbitrary(g),
879            },
880
881            2 => ElGamal {
882                p: MPI::arbitrary(g),
883                g: MPI::arbitrary(g),
884                y: MPI::arbitrary(g),
885            },
886
887            3 => EdDSA {
888                curve: Curve::arbitrary(g),
889                q: MPI::arbitrary(g),
890            },
891
892            4 => ECDSA {
893                curve: Curve::arbitrary(g),
894                q: MPI::arbitrary(g),
895            },
896
897            5 => ECDH {
898                curve: Curve::arbitrary(g),
899                q: MPI::arbitrary(g),
900                hash: HashAlgorithm::arbitrary(g),
901                sym: SymmetricAlgorithm::arbitrary(g),
902            },
903
904            6 => X25519 { u: arbitrary(g) },
905            7 => X448 { u: Box::new(arbitrarize(g, [0; 56])) },
906            8 => Ed25519 { a: arbitrary(g) },
907            9 => Ed448 { a: Box::new(arbitrarize(g, [0; 57])) },
908
909            10 => MLDSA65_Ed25519 {
910                eddsa: Box::new(arbitrarize(g, [0; 32])),
911                mldsa: Box::new(arbitrarize(g, [0; 1952])),
912            },
913
914            11 => MLDSA87_Ed448 {
915                eddsa: Box::new(arbitrarize(g, [0; 57])),
916                mldsa: Box::new(arbitrarize(g, [0; 2592])),
917            },
918
919            12 => SLHDSA128s {
920                public: arbitrary(g),
921            },
922
923            13 => SLHDSA128f {
924                public: arbitrary(g),
925            },
926
927            14 => SLHDSA256s {
928                public: Box::new(arbitrarize(g, [0; 64])),
929            },
930
931            15 => MLKEM768_X25519 {
932                ecdh: Box::new(arbitrarize(g, [0; 32])),
933                mlkem: Box::new(arbitrarize(g, [0; 1184])),
934            },
935
936            16 => MLKEM1024_X448 {
937                ecdh: Box::new(arbitrarize(g, [0; 56])),
938                mlkem: Box::new(arbitrarize(g, [0; 1568])),
939            },
940
941            _ => unreachable!(),
942        }
943    }
944}
945
946#[cfg(test)]
947pub(crate) fn arbitrarize<T: AsMut<[u8]>>(g: &mut Gen, mut a: T) -> T
948{
949    a.as_mut().iter_mut().for_each(|p| *p = Arbitrary::arbitrary(g));
950    a
951}
952
953#[cfg(test)]
954pub(crate) fn arbitrary<T: Default + AsMut<[u8]>>(g: &mut Gen) -> T
955{
956    arbitrarize(g, Default::default())
957}
958
959
960/// A secret key.
961///
962/// Provides a typed and structured way of storing multiple MPIs in
963/// [`Key`] packets.  Secret key components are protected by storing
964/// them using [`ProtectedMPI`].
965///
966///   [`Key`]: crate::packet::Key
967// Deriving Hash here is okay: PartialEq is manually implemented to
968// ensure that secrets are compared in constant-time.
969#[non_exhaustive]
970#[allow(non_camel_case_types)]
971#[allow(clippy::derived_hash_with_manual_eq)]
972#[derive(Clone, Hash)]
973pub enum SecretKeyMaterial {
974    /// RSA secret key.
975    RSA {
976        /// Secret exponent, inverse of e in Phi(N).
977        d: ProtectedMPI,
978        /// Smaller secret prime.
979        p: ProtectedMPI,
980        /// Larger secret prime.
981        q: ProtectedMPI,
982        /// Inverse of p mod q.
983        u: ProtectedMPI,
984    },
985
986    /// NIST DSA secret key.
987    DSA {
988        /// Secret key log_g(y) in Zp.
989        x: ProtectedMPI,
990    },
991
992    /// ElGamal secret key.
993    ElGamal {
994        /// Secret key log_g(y) in Zp.
995        x: ProtectedMPI,
996    },
997
998    /// DJB's "Twisted" Edwards curve DSA secret key.
999    EdDSA {
1000        /// Secret scalar.
1001        scalar: ProtectedMPI,
1002    },
1003
1004    /// NIST's Elliptic Curve DSA secret key.
1005    ECDSA {
1006        /// Secret scalar.
1007        scalar: ProtectedMPI,
1008    },
1009
1010    /// Elliptic Curve Diffie-Hellman secret key.
1011    ECDH {
1012        /// Secret scalar.
1013        scalar: ProtectedMPI,
1014    },
1015
1016    /// X25519 secret key.
1017    X25519 {
1018        /// The secret key, an opaque string.
1019        x: Protected,
1020    },
1021
1022    /// X448 secret key.
1023    X448 {
1024        /// The secret key, an opaque string.
1025        x: Protected,
1026    },
1027
1028    /// Ed25519 secret key.
1029    Ed25519 {
1030        /// The secret key, an opaque string.
1031        x: Protected,
1032    },
1033
1034    /// Ed448 secret key.
1035    Ed448 {
1036        /// The secret key, an opaque string.
1037        x: Protected,
1038    },
1039
1040    /// Composite signature algorithm using ML-DSA-65 and Ed25519.
1041    MLDSA65_Ed25519 {
1042        /// The Ed25519 secret key, an opaque string.
1043        eddsa: Protected,
1044
1045        /// The ML-DSA secret key, an opaque string.
1046        mldsa: Protected,
1047    },
1048
1049    /// Composite signature algorithm using ML-DSA-87 and Ed448.
1050    MLDSA87_Ed448 {
1051        /// The Ed448 secret key, an opaque string.
1052        eddsa: Protected,
1053
1054        /// The ML-DSA secret key, an opaque string.
1055        mldsa: Protected,
1056    },
1057
1058    /// SLH-DSA-SHAKE-128s secret key.
1059    SLHDSA128s {
1060        /// The secret key, an opaque string.
1061        secret: Protected,
1062    },
1063
1064    /// SLH-DSA-SHAKE-128f secret key.
1065    SLHDSA128f {
1066        /// The secret key, an opaque string.
1067        secret: Protected,
1068    },
1069
1070    /// SLH-DSA-SHAKE-256s secret key.
1071    SLHDSA256s {
1072        /// The secret key, an opaque string.
1073        secret: Protected,
1074    },
1075
1076    /// Composite KEM using ML-KEM-768 and X25519.
1077    MLKEM768_X25519 {
1078        /// The X25519 secret key, an opaque string.
1079        ecdh: Protected,
1080
1081        /// The ML-KEM secret key, an opaque string.
1082        mlkem: Protected,
1083    },
1084
1085    /// Composite KEM using ML-KEM-1024 and X448.
1086    MLKEM1024_X448 {
1087        /// The X448 secret key, an opaque string.
1088        ecdh: Protected,
1089
1090        /// The ML-KEM secret key, an opaque string.
1091        mlkem: Protected,
1092    },
1093
1094    /// Unknown number of MPIs for an unknown algorithm.
1095    Unknown {
1096        /// The successfully parsed MPIs.
1097        mpis: Box<[ProtectedMPI]>,
1098        /// Any data that failed to parse.
1099        rest: Protected,
1100    },
1101}
1102assert_send_and_sync!(SecretKeyMaterial);
1103
1104impl fmt::Debug for SecretKeyMaterial {
1105    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1106        if cfg!(debug_assertions) {
1107            match self {
1108                SecretKeyMaterial::RSA { d, p, q, u } =>
1109                    f.debug_struct("RSA")
1110                    .field("d", d)
1111                    .field("p", p)
1112                    .field("q", q)
1113                    .field("u", u)
1114                    .finish(),
1115
1116                SecretKeyMaterial::DSA { x } =>
1117                    f.debug_struct("DSA")
1118                    .field("x", x)
1119                    .finish(),
1120
1121                SecretKeyMaterial::ElGamal { x } =>
1122                    f.debug_struct("ElGamal")
1123                    .field("x", x)
1124                    .finish(),
1125
1126                SecretKeyMaterial::EdDSA { scalar } =>
1127                    f.debug_struct("EdDSA")
1128                    .field("scalar", scalar)
1129                    .finish(),
1130
1131                SecretKeyMaterial::ECDSA { scalar } =>
1132                    f.debug_struct("ECDSA")
1133                    .field("scalar", scalar)
1134                    .finish(),
1135
1136                SecretKeyMaterial::ECDH { scalar } =>
1137                    f.debug_struct("ECDH")
1138                    .field("scalar", scalar)
1139                    .finish(),
1140
1141                SecretKeyMaterial::X25519 { x } =>
1142                    f.debug_struct("X25519")
1143                    .field("x", &hex::encode(x))
1144                    .finish(),
1145
1146                SecretKeyMaterial::X448 { x } =>
1147                    f.debug_struct("X448")
1148                    .field("x", &hex::encode(x))
1149                    .finish(),
1150
1151                SecretKeyMaterial::Ed25519 { x } =>
1152                    f.debug_struct("Ed25519")
1153                    .field("x", &hex::encode(x))
1154                    .finish(),
1155
1156                SecretKeyMaterial::Ed448 { x } =>
1157                    f.debug_struct("Ed448")
1158                    .field("x", &hex::encode(x))
1159                    .finish(),
1160
1161                SecretKeyMaterial::MLDSA65_Ed25519 { eddsa, mldsa } =>
1162                    f.debug_struct("MLDSA65_Ed25519")
1163                    .field("eddsa", &hex::encode(eddsa))
1164                    .field("mldsa", &hex::encode(mldsa))
1165                    .finish(),
1166
1167                SecretKeyMaterial::MLDSA87_Ed448 { eddsa, mldsa } =>
1168                    f.debug_struct("MLDSA87_Ed448")
1169                    .field("eddsa", &hex::encode(eddsa))
1170                    .field("mldsa", &hex::encode(mldsa))
1171                    .finish(),
1172
1173                SecretKeyMaterial::SLHDSA128s { secret } =>
1174                    f.debug_struct("SLHDSA128s")
1175                    .field("secret", &hex::encode(secret.as_ref()))
1176                    .finish(),
1177
1178                SecretKeyMaterial::SLHDSA128f { secret } =>
1179                    f.debug_struct("SLHDSA128f")
1180                    .field("secret", &hex::encode(secret.as_ref()))
1181                    .finish(),
1182
1183                SecretKeyMaterial::SLHDSA256s { secret } =>
1184                    f.debug_struct("SLHDSA256s")
1185                    .field("secret", &hex::encode(secret.as_ref()))
1186                    .finish(),
1187
1188                SecretKeyMaterial::MLKEM768_X25519 { ecdh, mlkem } =>
1189                    f.debug_struct("MLKEM768_X25519")
1190                    .field("ecdh", &hex::encode(ecdh))
1191                    .field("mlkem", &hex::encode(mlkem))
1192                    .finish(),
1193
1194                SecretKeyMaterial::MLKEM1024_X448 { ecdh, mlkem } =>
1195                    f.debug_struct("MLKEM1024_X448")
1196                    .field("ecdh", &hex::encode(ecdh))
1197                    .field("mlkem", &hex::encode(mlkem))
1198                    .finish(),
1199
1200                SecretKeyMaterial::Unknown{ mpis, rest } =>
1201                    f.debug_struct("Unknown")
1202                    .field("mpis", mpis)
1203                    .field("rest", &hex::encode(rest))
1204                    .finish(),
1205            }
1206        } else {
1207            match self {
1208                SecretKeyMaterial::RSA{ .. } =>
1209                    f.write_str("RSA { <Redacted> }"),
1210                SecretKeyMaterial::DSA{ .. } =>
1211                    f.write_str("DSA { <Redacted> }"),
1212                SecretKeyMaterial::ElGamal{ .. } =>
1213                    f.write_str("ElGamal { <Redacted> }"),
1214                SecretKeyMaterial::EdDSA{ .. } =>
1215                    f.write_str("EdDSA { <Redacted> }"),
1216                SecretKeyMaterial::ECDSA{ .. } =>
1217                    f.write_str("ECDSA { <Redacted> }"),
1218                SecretKeyMaterial::ECDH{ .. } =>
1219                    f.write_str("ECDH { <Redacted> }"),
1220                SecretKeyMaterial::X25519 { .. } =>
1221                    f.write_str("X25519 { <Redacted> }"),
1222                SecretKeyMaterial::X448 { .. } =>
1223                    f.write_str("X448 { <Redacted> }"),
1224                SecretKeyMaterial::Ed25519 { .. } =>
1225                    f.write_str("Ed25519 { <Redacted> }"),
1226                SecretKeyMaterial::Ed448 { .. } =>
1227                    f.write_str("Ed448 { <Redacted> }"),
1228                SecretKeyMaterial::MLDSA65_Ed25519 { .. } =>
1229                    f.write_str("MLDSA65_Ed25519 { <Redacted> }"),
1230                SecretKeyMaterial::MLDSA87_Ed448 { .. } =>
1231                    f.write_str("MLDSA87_Ed448 { <Redacted> }"),
1232                SecretKeyMaterial::SLHDSA128s { .. } =>
1233                    f.write_str("SLHDSA128s { <Redacted> }"),
1234                SecretKeyMaterial::SLHDSA128f { .. } =>
1235                    f.write_str("SLHDSA128f { <Redacted> }"),
1236                SecretKeyMaterial::SLHDSA256s { .. } =>
1237                    f.write_str("SLHDSA256s { <Redacted> }"),
1238                SecretKeyMaterial::MLKEM768_X25519 { .. } =>
1239                    f.write_str("MLKEM768_X25519 { <Redacted> }"),
1240                SecretKeyMaterial::MLKEM1024_X448 { .. } =>
1241                    f.write_str("MLKEM1024_X448 { <Redacted> }"),
1242                SecretKeyMaterial::Unknown{ .. } =>
1243                    f.write_str("Unknown { <Redacted> }"),
1244            }
1245        }
1246    }
1247}
1248
1249impl PartialOrd for SecretKeyMaterial {
1250    fn partial_cmp(&self, other: &SecretKeyMaterial) -> Option<Ordering> {
1251        Some(self.cmp(other))
1252    }
1253}
1254
1255impl Ord for SecretKeyMaterial {
1256    fn cmp(&self, other: &Self) -> Ordering {
1257        use std::iter;
1258
1259        fn discriminant(sk: &SecretKeyMaterial) -> usize {
1260            match sk {
1261                SecretKeyMaterial::RSA{ .. } => 0,
1262                SecretKeyMaterial::DSA{ .. } => 1,
1263                SecretKeyMaterial::ElGamal{ .. } => 2,
1264                SecretKeyMaterial::EdDSA{ .. } => 3,
1265                SecretKeyMaterial::ECDSA{ .. } => 4,
1266                SecretKeyMaterial::ECDH{ .. } => 5,
1267                SecretKeyMaterial::X25519 { .. } => 6,
1268                SecretKeyMaterial::X448 { .. } => 7,
1269                SecretKeyMaterial::Ed25519 { .. } => 8,
1270                SecretKeyMaterial::Ed448 { .. } => 9,
1271                SecretKeyMaterial::Unknown { .. } => 10,
1272                SecretKeyMaterial::MLDSA65_Ed25519 { .. } => 11,
1273                SecretKeyMaterial::MLDSA87_Ed448 { .. } => 12,
1274                SecretKeyMaterial::SLHDSA128s { .. } => 13,
1275                SecretKeyMaterial::SLHDSA128f { .. } => 14,
1276                SecretKeyMaterial::SLHDSA256s { .. } => 15,
1277                SecretKeyMaterial::MLKEM768_X25519 { .. } => 16,
1278                SecretKeyMaterial::MLKEM1024_X448 { .. } => 17,
1279            }
1280        }
1281
1282        let ret = match (self, other) {
1283            (&SecretKeyMaterial::RSA{ d: ref d1, p: ref p1, q: ref q1, u: ref u1 }
1284            ,&SecretKeyMaterial::RSA{ d: ref d2, p: ref p2, q: ref q2, u: ref u2 }) => {
1285                let o1 = d1.cmp(d2);
1286                let o2 = p1.cmp(p2);
1287                let o3 = q1.cmp(q2);
1288                let o4 = u1.cmp(u2);
1289
1290                if o1 != Ordering::Equal { return o1; }
1291                if o2 != Ordering::Equal { return o2; }
1292                if o3 != Ordering::Equal { return o3; }
1293                o4
1294            }
1295            (&SecretKeyMaterial::DSA{ x: ref x1 }
1296            ,&SecretKeyMaterial::DSA{ x: ref x2 }) => {
1297                x1.cmp(x2)
1298            }
1299            (&SecretKeyMaterial::ElGamal{ x: ref x1 }
1300            ,&SecretKeyMaterial::ElGamal{ x: ref x2 }) => {
1301                x1.cmp(x2)
1302            }
1303            (&SecretKeyMaterial::EdDSA{ scalar: ref scalar1 }
1304            ,&SecretKeyMaterial::EdDSA{ scalar: ref scalar2 }) => {
1305                scalar1.cmp(scalar2)
1306            }
1307            (&SecretKeyMaterial::ECDSA{ scalar: ref scalar1 }
1308            ,&SecretKeyMaterial::ECDSA{ scalar: ref scalar2 }) => {
1309                scalar1.cmp(scalar2)
1310            }
1311            (&SecretKeyMaterial::ECDH{ scalar: ref scalar1 }
1312            ,&SecretKeyMaterial::ECDH{ scalar: ref scalar2 }) => {
1313                scalar1.cmp(scalar2)
1314            }
1315            (SecretKeyMaterial::X25519 { x: x0 },
1316             SecretKeyMaterial::X25519 { x: x1 }) => x0.cmp(x1),
1317            (SecretKeyMaterial::X448 { x: x0 },
1318             SecretKeyMaterial::X448 { x: x1 }) => x0.cmp(x1),
1319            (SecretKeyMaterial::Ed25519 { x: x0 },
1320             SecretKeyMaterial::Ed25519 { x: x1 }) => x0.cmp(x1),
1321            (SecretKeyMaterial::Ed448 { x: x0 },
1322             SecretKeyMaterial::Ed448 { x: x1 }) => x0.cmp(x1),
1323
1324            (SecretKeyMaterial::MLDSA65_Ed25519 { eddsa: e0, mldsa: m0 },
1325             SecretKeyMaterial::MLDSA65_Ed25519 { eddsa: e1, mldsa: m1 }) =>
1326                iter::once(e0.cmp(e1))
1327                    .chain(iter::once(m0.cmp(m1)))
1328                    .fold(Ordering::Equal, |acc, x| acc.then(x)),
1329
1330            (SecretKeyMaterial::MLDSA87_Ed448 { eddsa: e0, mldsa: m0 },
1331             SecretKeyMaterial::MLDSA87_Ed448 { eddsa: e1, mldsa: m1 }) =>
1332                iter::once(e0.cmp(e1))
1333                    .chain(iter::once(m0.cmp(m1)))
1334                    .fold(Ordering::Equal, |acc, x| acc.then(x)),
1335
1336            (SecretKeyMaterial::SLHDSA128s { secret: s0 },
1337             SecretKeyMaterial::SLHDSA128s { secret: s1 }) => s0.cmp(s1),
1338
1339            (SecretKeyMaterial::SLHDSA128f { secret: s0 },
1340             SecretKeyMaterial::SLHDSA128f { secret: s1 }) => s0.cmp(s1),
1341
1342            (SecretKeyMaterial::SLHDSA256s { secret: s0 },
1343             SecretKeyMaterial::SLHDSA256s { secret: s1 }) => s0.cmp(s1),
1344
1345            (SecretKeyMaterial::MLKEM768_X25519 { ecdh: e0, mlkem: m0 },
1346             SecretKeyMaterial::MLKEM768_X25519 { ecdh: e1, mlkem: m1 }) =>
1347                iter::once(e0.cmp(e1))
1348                    .chain(iter::once(m0.cmp(m1)))
1349                    .fold(Ordering::Equal, |acc, x| acc.then(x)),
1350
1351            (SecretKeyMaterial::MLKEM1024_X448 { ecdh: e0, mlkem: m0 },
1352             SecretKeyMaterial::MLKEM1024_X448 { ecdh: e1, mlkem: m1 }) =>
1353                iter::once(e0.cmp(e1))
1354                    .chain(iter::once(m0.cmp(m1)))
1355                    .fold(Ordering::Equal, |acc, x| acc.then(x)),
1356
1357            (&SecretKeyMaterial::Unknown{ mpis: ref mpis1, rest: ref rest1 }
1358            ,&SecretKeyMaterial::Unknown{ mpis: ref mpis2, rest: ref rest2 }) => {
1359                let o1 = secure_cmp(rest1, rest2);
1360                let o2 = mpis1.len().cmp(&mpis2.len());
1361                let on = mpis1.iter().zip(mpis2.iter()).map(|(a,b)| {
1362                    a.cmp(b)
1363                }).collect::<Vec<_>>();
1364
1365                iter::once(o1)
1366                    .chain(iter::once(o2))
1367                    .chain(on.iter().cloned())
1368                    .fold(Ordering::Equal, |acc, x| acc.then(x))
1369            }
1370
1371            (a, b) => {
1372                let ret = discriminant(a).cmp(&discriminant(b));
1373
1374                assert!(ret != Ordering::Equal);
1375                ret
1376            }
1377        };
1378
1379        ret
1380    }
1381}
1382
1383impl PartialEq for SecretKeyMaterial {
1384    fn eq(&self, other: &Self) -> bool { self.cmp(other) == Ordering::Equal }
1385}
1386
1387impl Eq for SecretKeyMaterial {}
1388
1389impl SecretKeyMaterial {
1390    /// Returns, if known, the public-key algorithm for this secret
1391    /// key.
1392    pub fn algo(&self) -> Option<PublicKeyAlgorithm> {
1393        use self::SecretKeyMaterial::*;
1394        #[allow(deprecated)]
1395        match self {
1396            RSA { .. } => Some(PublicKeyAlgorithm::RSAEncryptSign),
1397            DSA { .. } => Some(PublicKeyAlgorithm::DSA),
1398            ElGamal { .. } => Some(PublicKeyAlgorithm::ElGamalEncrypt),
1399            EdDSA { .. } => Some(PublicKeyAlgorithm::EdDSA),
1400            ECDSA { .. } => Some(PublicKeyAlgorithm::ECDSA),
1401            ECDH { .. } => Some(PublicKeyAlgorithm::ECDH),
1402            X25519 { .. } => Some(PublicKeyAlgorithm::X25519),
1403            X448 { .. } => Some(PublicKeyAlgorithm::X448),
1404            Ed25519 { .. } => Some(PublicKeyAlgorithm::Ed25519),
1405            Ed448 { .. } => Some(PublicKeyAlgorithm::Ed448),
1406            MLDSA65_Ed25519 { .. } => Some(PublicKeyAlgorithm::MLDSA65_Ed25519),
1407            MLDSA87_Ed448 { .. } => Some(PublicKeyAlgorithm::MLDSA87_Ed448),
1408            SLHDSA128s { .. } => Some(PublicKeyAlgorithm::SLHDSA128s),
1409            SLHDSA128f { .. } => Some(PublicKeyAlgorithm::SLHDSA128f),
1410            SLHDSA256s { .. } => Some(PublicKeyAlgorithm::SLHDSA256s),
1411            MLKEM768_X25519 { .. } => Some(PublicKeyAlgorithm::MLKEM768_X25519),
1412            MLKEM1024_X448 { .. } => Some(PublicKeyAlgorithm::MLKEM1024_X448),
1413            Unknown { .. } => None,
1414        }
1415    }
1416}
1417
1418impl Hash for SecretKeyMaterial {
1419    fn hash(&self, mut hash: &mut hash::Context) -> Result<()> {
1420        self.serialize(&mut hash as &mut dyn Write)
1421    }
1422}
1423
1424#[cfg(test)]
1425impl SecretKeyMaterial {
1426    pub(crate) fn arbitrary_for(g: &mut Gen, pk: PublicKeyAlgorithm) -> Result<Self> {
1427        use self::PublicKeyAlgorithm::*;
1428        #[allow(deprecated)]
1429        match pk {
1430            RSAEncryptSign | RSASign | RSAEncrypt => Ok(SecretKeyMaterial::RSA {
1431                d: ProtectedMPI::arbitrary(g),
1432                p: ProtectedMPI::arbitrary(g),
1433                q: ProtectedMPI::arbitrary(g),
1434                u: ProtectedMPI::arbitrary(g),
1435            }),
1436
1437            DSA => Ok(SecretKeyMaterial::DSA {
1438                x: ProtectedMPI::arbitrary(g),
1439            }),
1440
1441            ElGamalEncryptSign | ElGamalEncrypt => Ok(SecretKeyMaterial::ElGamal {
1442                x: ProtectedMPI::arbitrary(g),
1443            }),
1444
1445            EdDSA => Ok(SecretKeyMaterial::EdDSA {
1446                scalar: ProtectedMPI::arbitrary(g),
1447            }),
1448
1449            ECDSA => Ok(SecretKeyMaterial::ECDSA {
1450                scalar: ProtectedMPI::arbitrary(g),
1451            }),
1452
1453            ECDH => Ok(SecretKeyMaterial::ECDH {
1454                scalar: ProtectedMPI::arbitrary(g),
1455            }),
1456
1457            X25519 => Ok(SecretKeyMaterial::X25519 {
1458                x: arbitrarize(g, vec![0; 32]).into(),
1459            }),
1460            X448 => Ok(SecretKeyMaterial::X448 {
1461                x: arbitrarize(g, vec![0; 56]).into(),
1462            }),
1463            Ed25519 => Ok(SecretKeyMaterial::Ed25519 {
1464                x: arbitrarize(g, vec![0; 32]).into(),
1465            }),
1466            Ed448 => Ok(SecretKeyMaterial::Ed448 {
1467                x: arbitrarize(g, vec![0; 57]).into(),
1468            }),
1469
1470            MLDSA65_Ed25519 => Ok(SecretKeyMaterial::MLDSA65_Ed25519 {
1471                eddsa: arbitrarize(g, vec![0; 32]).into(),
1472                mldsa: arbitrarize(g, vec![0; 32]).into(),
1473            }),
1474
1475            MLDSA87_Ed448 => Ok(SecretKeyMaterial::MLDSA87_Ed448 {
1476                eddsa: arbitrarize(g, vec![0; 57]).into(),
1477                mldsa: arbitrarize(g, vec![0; 32]).into(),
1478            }),
1479
1480            SLHDSA128s => Ok(SecretKeyMaterial::SLHDSA128s {
1481                secret: arbitrarize(g, [0; 64]).into(),
1482            }),
1483
1484            SLHDSA128f => Ok(SecretKeyMaterial::SLHDSA128f {
1485                secret: arbitrarize(g, [0; 64]).into(),
1486            }),
1487
1488            SLHDSA256s => Ok(SecretKeyMaterial::SLHDSA256s {
1489                secret: arbitrarize(g, [0; 128]).into(),
1490            }),
1491
1492            MLKEM768_X25519 => Ok(SecretKeyMaterial::MLKEM768_X25519 {
1493                ecdh: arbitrarize(g, vec![0; 32]).into(),
1494                mlkem: arbitrarize(g, vec![0; 64]).into(),
1495            }),
1496
1497            MLKEM1024_X448 => Ok(SecretKeyMaterial::MLKEM1024_X448 {
1498                ecdh: arbitrarize(g, vec![0; 56]).into(),
1499                mlkem: arbitrarize(g, vec![0; 64]).into(),
1500            }),
1501
1502            Private(_) | Unknown(_) =>
1503                Err(Error::UnsupportedPublicKeyAlgorithm(pk).into()),
1504        }
1505    }
1506}
1507#[cfg(test)]
1508impl Arbitrary for SecretKeyMaterial {
1509    fn arbitrary(g: &mut Gen) -> Self {
1510        let pk = *g.choose(
1511            &crate::crypto::types::public_key_algorithm::PUBLIC_KEY_ALGORITHM_VARIANTS)
1512            .expect("not empty");
1513        Self::arbitrary_for(g, pk).expect("only known variants")
1514    }
1515}
1516
1517/// Checksum method for secret key material.
1518///
1519/// Secret key material may be protected by a checksum.  See [Section
1520/// 5.5.3 of RFC 9580] for details.
1521///
1522///   [Section 5.5.3 of RFC 9580]: https://www.rfc-editor.org/rfc/rfc9580.html#section-5.5.3
1523#[derive(PartialEq, Eq, Hash, Clone, Copy, Debug)]
1524pub enum SecretKeyChecksum {
1525    /// SHA1 over the decrypted secret key.
1526    SHA1,
1527
1528    /// Sum of the decrypted secret key octets modulo 65536.
1529    Sum16,
1530}
1531assert_send_and_sync!(SecretKeyChecksum);
1532
1533impl Default for SecretKeyChecksum {
1534    fn default() -> Self {
1535        SecretKeyChecksum::SHA1
1536    }
1537}
1538
1539impl SecretKeyChecksum {
1540    /// Returns the on-wire length of the checksum.
1541    pub(crate) fn len(&self) -> usize {
1542        match self {
1543            SecretKeyChecksum::SHA1 => 20,
1544            SecretKeyChecksum::Sum16 => 2,
1545        }
1546    }
1547}
1548
1549/// An encrypted session key.
1550///
1551/// Provides a typed and structured way of storing multiple MPIs in
1552/// [`PKESK`] packets.
1553///
1554///   [`PKESK`]: crate::packet::PKESK
1555#[non_exhaustive]
1556#[allow(non_camel_case_types)]
1557#[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
1558pub enum Ciphertext {
1559    /// RSA ciphertext.
1560    RSA {
1561        ///  m^e mod N.
1562        c: MPI,
1563    },
1564
1565    /// ElGamal ciphertext.
1566    ElGamal {
1567        /// Ephemeral key.
1568        e: MPI,
1569        /// Ciphertext.
1570        c: MPI,
1571    },
1572
1573    /// Elliptic curve ElGamal public key.
1574    ECDH {
1575        /// Ephemeral key.
1576        e: MPI,
1577        /// Symmetrically encrypted session key.
1578        key: Box<[u8]>,
1579    },
1580
1581    /// X25519 ciphertext.
1582    X25519 {
1583        /// Ephermeral key.
1584        e: Box<[u8; 32]>,
1585        /// Symmetrically encrypted session key.
1586        key: Box<[u8]>,
1587    },
1588
1589    /// X448 ciphertext.
1590    X448 {
1591        /// Ephermeral key.
1592        e: Box<[u8; 56]>,
1593        /// Symmetrically encrypted session key.
1594        key: Box<[u8]>,
1595    },
1596
1597    /// Composite KEM using ML-KEM-768 and X25519.
1598    MLKEM768_X25519 {
1599        /// The X25519 ciphertext, an opaque string.
1600        ecdh: Box<[u8; 32]>,
1601
1602        /// The ML-KEM ciphertext, an opaque string.
1603        mlkem: Box<[u8; 1088]>,
1604
1605        /// Symmetrically encrypted session key.
1606        esk: Box<[u8]>,
1607    },
1608
1609    /// Composite KEM using ML-KEM-1024 and X448.
1610    MLKEM1024_X448 {
1611        /// The X448 ciphertext, an opaque string.
1612        ecdh: Box<[u8; 56]>,
1613
1614        /// The ML-KEM ciphertext, an opaque string.
1615        mlkem: Box<[u8; 1568]>,
1616
1617        /// Symmetrically encrypted session key.
1618        esk: Box<[u8]>,
1619    },
1620
1621    /// Unknown number of MPIs for an unknown algorithm.
1622    Unknown {
1623        /// The successfully parsed MPIs.
1624        mpis: Box<[MPI]>,
1625        /// Any data that failed to parse.
1626        rest: Box<[u8]>,
1627    },
1628}
1629assert_send_and_sync!(Ciphertext);
1630
1631impl fmt::Debug for Ciphertext {
1632    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1633        match self {
1634            Ciphertext::RSA { c } =>
1635                f.debug_struct("RSA")
1636                .field("c", c)
1637                .finish(),
1638
1639            Ciphertext::ElGamal { e, c } =>
1640                f.debug_struct("ElGamal")
1641                .field("e", e)
1642                .field("c", c)
1643                .finish(),
1644
1645            Ciphertext::ECDH { e, key } =>
1646                f.debug_struct("ECDH")
1647                .field("e", e)
1648                .field("key", &hex::encode(key))
1649                .finish(),
1650
1651            Ciphertext::X25519 { e, key } =>
1652                f.debug_struct("X25519")
1653                .field("e", &hex::encode(&e[..]))
1654                .field("key", &hex::encode(key))
1655                .finish(),
1656
1657            Ciphertext::X448 { e, key } =>
1658                f.debug_struct("X448")
1659                .field("e", &hex::encode(&e[..]))
1660                .field("key", &hex::encode(key))
1661                .finish(),
1662
1663            Ciphertext::MLKEM768_X25519 { ecdh, mlkem, esk } =>
1664                f.debug_struct("MLKEM768_X25519")
1665                .field("ecdh", &hex::encode(&ecdh[..]))
1666                .field("mlkem", &hex::encode(&mlkem[..]))
1667                .field("esk", &hex::encode(esk))
1668                .finish(),
1669
1670            Ciphertext::MLKEM1024_X448 { ecdh, mlkem, esk } =>
1671                f.debug_struct("MLKEM1024_X448")
1672                .field("ecdh", &hex::encode(&ecdh[..]))
1673                .field("mlkem", &hex::encode(&mlkem[..]))
1674                .field("esk", &hex::encode(esk))
1675                .finish(),
1676
1677            Ciphertext::Unknown { mpis, rest } =>
1678                f.debug_struct("Unknown")
1679                .field("mpis", mpis)
1680                .field("rest", &hex::encode(rest))
1681                .finish(),
1682        }
1683    }
1684}
1685
1686impl Ciphertext {
1687    /// Returns, if known, the public-key algorithm for this
1688    /// ciphertext.
1689    pub fn pk_algo(&self) -> Option<PublicKeyAlgorithm> {
1690        use self::Ciphertext::*;
1691
1692        // Fields are mostly MPIs that consist of two octets length
1693        // plus the big endian value itself. All other field types are
1694        // commented.
1695        #[allow(deprecated)]
1696        match self {
1697            RSA { .. } => Some(PublicKeyAlgorithm::RSAEncryptSign),
1698            ElGamal { .. } => Some(PublicKeyAlgorithm::ElGamalEncrypt),
1699            ECDH { .. } => Some(PublicKeyAlgorithm::ECDH),
1700            X25519 { .. } => Some(PublicKeyAlgorithm::X25519),
1701            X448 { .. } => Some(PublicKeyAlgorithm::X448),
1702            MLKEM768_X25519 { .. } => Some(PublicKeyAlgorithm::MLKEM768_X25519),
1703            MLKEM1024_X448 { .. } => Some(PublicKeyAlgorithm::MLKEM1024_X448),
1704            Unknown { .. } => None,
1705        }
1706    }
1707}
1708
1709impl Hash for Ciphertext {
1710    fn hash(&self, mut hash: &mut hash::Context) -> Result<()> {
1711        self.serialize(&mut hash as &mut dyn Write)
1712    }
1713}
1714
1715#[cfg(test)]
1716impl Arbitrary for Ciphertext {
1717    fn arbitrary(g: &mut Gen) -> Self {
1718        use crate::arbitrary_helper::gen_arbitrary_from_range;
1719
1720        match gen_arbitrary_from_range(0..7, g) {
1721            0 => Ciphertext::RSA {
1722                c: MPI::arbitrary(g),
1723            },
1724
1725            1 => Ciphertext::ElGamal {
1726                e: MPI::arbitrary(g),
1727                c: MPI::arbitrary(g)
1728            },
1729
1730            2 => Ciphertext::ECDH {
1731                e: MPI::arbitrary(g),
1732                key: {
1733                    let mut k = <Vec<u8>>::arbitrary(g);
1734                    k.truncate(255);
1735                    k.into_boxed_slice()
1736                },
1737            },
1738
1739            3 => Ciphertext::X25519 {
1740                e: Box::new(arbitrary(g)),
1741                key: {
1742                    let mut k = <Vec<u8>>::arbitrary(g);
1743                    k.truncate(255);
1744                    k.into_boxed_slice()
1745                },
1746            },
1747
1748            4 => Ciphertext::X448 {
1749                e: Box::new(arbitrarize(g, [0; 56])),
1750                key: {
1751                    let mut k = <Vec<u8>>::arbitrary(g);
1752                    k.truncate(255);
1753                    k.into_boxed_slice()
1754                },
1755            },
1756
1757            5 => Ciphertext::MLKEM768_X25519 {
1758                ecdh: Box::new(arbitrarize(g, [0; 32])),
1759                mlkem: Box::new(arbitrarize(g, [0; 1088])),
1760                esk: {
1761                    let mut k = <Vec<u8>>::arbitrary(g);
1762                    k.truncate(255);
1763                    k.into_boxed_slice()
1764                },
1765            },
1766
1767            6 => Ciphertext::MLKEM1024_X448 {
1768                ecdh: Box::new(arbitrarize(g, [0; 56])),
1769                mlkem: Box::new(arbitrarize(g, [0; 1568])),
1770                esk: {
1771                    let mut k = <Vec<u8>>::arbitrary(g);
1772                    k.truncate(255);
1773                    k.into_boxed_slice()
1774                },
1775            },
1776
1777            _ => unreachable!(),
1778        }
1779    }
1780}
1781
1782/// A cryptographic signature.
1783///
1784/// Provides a typed and structured way of storing multiple MPIs in
1785/// [`Signature`] packets.
1786///
1787///   [`Signature`]: crate::packet::Signature
1788#[non_exhaustive]
1789#[allow(non_camel_case_types)]
1790#[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
1791pub enum Signature {
1792    /// RSA signature.
1793    RSA {
1794        /// Signature m^d mod N.
1795        s: MPI,
1796    },
1797
1798    /// NIST's DSA signature.
1799    DSA {
1800        /// `r` value.
1801        r: MPI,
1802        /// `s` value.
1803        s: MPI,
1804    },
1805
1806    /// ElGamal signature.
1807    ElGamal {
1808        /// `r` value.
1809        r: MPI,
1810        /// `s` value.
1811        s: MPI,
1812    },
1813
1814    /// DJB's "Twisted" Edwards curve DSA signature.
1815    EdDSA {
1816        /// `r` value.
1817        r: MPI,
1818        /// `s` value.
1819        s: MPI,
1820    },
1821
1822    /// NIST's Elliptic curve DSA signature.
1823    ECDSA {
1824        /// `r` value.
1825        r: MPI,
1826        /// `s` value.
1827        s: MPI,
1828    },
1829
1830    /// Ed25519 signature.
1831    Ed25519 {
1832        /// The signature.
1833        s: Box<[u8; 64]>,
1834    },
1835
1836    /// Ed448 signature.
1837    Ed448 {
1838        /// The signature.
1839        s: Box<[u8; 114]>,
1840    },
1841
1842    /// Composite signature algorithm using ML-DSA-65 and Ed25519.
1843    MLDSA65_Ed25519 {
1844        /// The Ed25519 signature, an opaque string.
1845        eddsa: Box<[u8; 64]>,
1846
1847        /// The ML-DSA signature, an opaque string.
1848        mldsa: Box<[u8; 3309]>,
1849    },
1850
1851    /// Composite signature algorithm using ML-DSA-87 and Ed448.
1852    MLDSA87_Ed448 {
1853        /// The Ed448 signature, an opaque string.
1854        eddsa: Box<[u8; 114]>,
1855
1856        /// The ML-DSA signature, an opaque string.
1857        mldsa: Box<[u8; 4627]>,
1858    },
1859
1860    /// SLH-DSA-SHAKE-128s signature.
1861    SLHDSA128s {
1862        /// The signature, an opaque string.
1863        sig: Box<[u8; 7856]>,
1864    },
1865
1866    /// SLH-DSA-SHAKE-128f signature.
1867    SLHDSA128f {
1868        /// The signature, an opaque string.
1869        sig: Box<[u8; 17088]>,
1870    },
1871
1872    /// SLH-DSA-SHAKE-256s signature.
1873    SLHDSA256s {
1874        /// The signature, an opaque string.
1875        sig: Box<[u8; 29792]>,
1876    },
1877
1878    /// Unknown number of MPIs for an unknown algorithm.
1879    Unknown {
1880        /// The successfully parsed MPIs.
1881        mpis: Box<[MPI]>,
1882        /// Any data that failed to parse.
1883        rest: Box<[u8]>,
1884    },
1885}
1886assert_send_and_sync!(Signature);
1887
1888impl fmt::Debug for Signature {
1889    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1890        match self {
1891            Signature::RSA { s } =>
1892                f.debug_struct("RSA")
1893                .field("s", s)
1894                .finish(),
1895
1896            Signature::DSA { r, s } =>
1897                f.debug_struct("DSA")
1898                .field("r", r)
1899                .field("s", s)
1900                .finish(),
1901
1902            Signature::ElGamal { r, s } =>
1903                f.debug_struct("ElGamal")
1904                .field("r", r)
1905                .field("s", s)
1906                .finish(),
1907
1908            Signature::EdDSA { r, s } =>
1909                f.debug_struct("EdDSA")
1910                .field("r", r)
1911                .field("s", s)
1912                .finish(),
1913
1914            Signature::ECDSA { r, s } =>
1915                f.debug_struct("ECDSA")
1916                .field("r", r)
1917                .field("s", s)
1918                .finish(),
1919
1920            Signature::Ed25519 { s } =>
1921                f.debug_struct("Ed25519")
1922                .field("s", &hex::encode(&s[..]))
1923                .finish(),
1924
1925            Signature::Ed448 { s } =>
1926                f.debug_struct("Ed448")
1927                .field("s", &hex::encode(&s[..]))
1928                .finish(),
1929
1930            Signature::MLDSA65_Ed25519 { eddsa, mldsa } =>
1931                f.debug_struct("MLDSA65_Ed25519")
1932                .field("eddsa", &hex::encode(&eddsa[..]))
1933                .field("mldsa", &hex::encode(&mldsa[..]))
1934                .finish(),
1935
1936            Signature::MLDSA87_Ed448 { eddsa, mldsa } =>
1937                f.debug_struct("MLDSA87_Ed448")
1938                .field("eddsa", &hex::encode(&eddsa[..]))
1939                .field("mldsa", &hex::encode(&mldsa[..]))
1940                .finish(),
1941
1942            Signature::SLHDSA128s { sig } =>
1943                f.debug_struct("SLHDSA128s")
1944                .field("sig", &hex::encode(sig.as_ref()))
1945                .finish(),
1946
1947            Signature::SLHDSA128f { sig } =>
1948                f.debug_struct("SLHDSA128f")
1949                .field("sig", &hex::encode(sig.as_ref()))
1950                .finish(),
1951
1952            Signature::SLHDSA256s { sig } =>
1953                f.debug_struct("SLHDSA256s")
1954                .field("sig", &hex::encode(sig.as_ref()))
1955                .finish(),
1956
1957            Signature::Unknown { mpis, rest } =>
1958                f.debug_struct("Unknown")
1959                .field("mpis", mpis)
1960                .field("rest", &hex::encode(rest))
1961                .finish(),
1962        }
1963    }
1964}
1965
1966impl Hash for Signature {
1967    fn hash(&self, mut hash: &mut hash::Context) -> Result<()> {
1968        self.serialize(&mut hash as &mut dyn Write)
1969    }
1970}
1971
1972#[cfg(test)]
1973impl Arbitrary for Signature {
1974    fn arbitrary(g: &mut Gen) -> Self {
1975        use crate::arbitrary_helper::gen_arbitrary_from_range;
1976
1977        match gen_arbitrary_from_range(0..8, g) {
1978            0 => Signature::RSA  {
1979                s: MPI::arbitrary(g),
1980            },
1981
1982            1 => Signature::DSA {
1983                r: MPI::arbitrary(g),
1984                s: MPI::arbitrary(g),
1985            },
1986
1987            2 => Signature::EdDSA  {
1988                r: MPI::arbitrary(g),
1989                s: MPI::arbitrary(g),
1990            },
1991
1992            3 => Signature::ECDSA  {
1993                r: MPI::arbitrary(g),
1994                s: MPI::arbitrary(g),
1995            },
1996
1997            4 => Signature::Ed25519  {
1998                s: Box::new(arbitrarize(g, [0; 64])),
1999            },
2000
2001            5 => Signature::Ed448  {
2002                s: Box::new(arbitrarize(g, [0; 114])),
2003            },
2004
2005            6 => Signature::MLDSA65_Ed25519  {
2006                eddsa: Box::new(arbitrarize(g, [0; 64])),
2007                mldsa: Box::new(arbitrarize(g, [0; 3309])),
2008            },
2009
2010            7 => Signature::MLDSA87_Ed448  {
2011                eddsa: Box::new(arbitrarize(g, [0; 114])),
2012                mldsa: Box::new(arbitrarize(g, [0; 4627])),
2013            },
2014
2015            _ => unreachable!(),
2016        }
2017    }
2018}
2019
2020#[cfg(test)]
2021mod tests {
2022    use super::*;
2023    use crate::parse::Parse;
2024
2025    quickcheck! {
2026        fn mpi_roundtrip(mpi: MPI) -> bool {
2027            let mut buf = Vec::new();
2028            mpi.serialize(&mut buf).unwrap();
2029            MPI::from_bytes(&buf).unwrap() == mpi
2030        }
2031    }
2032
2033    quickcheck! {
2034        fn pk_roundtrip(pk: PublicKey) -> bool {
2035            use std::io::Cursor;
2036
2037            let mut buf = Vec::new();
2038            pk.serialize(&mut buf).unwrap();
2039            let cur = Cursor::new(buf);
2040            let pk_ = PublicKey::parse(pk.algo().unwrap(), cur).unwrap();
2041
2042            pk == pk_
2043        }
2044    }
2045
2046    #[test]
2047    fn pk_bits() {
2048        for (name, key_no, bits) in &[
2049            ("testy.pgp", 0, 2048),
2050            ("testy-new.pgp", 1, 256),
2051            ("dennis-simon-anton.pgp", 0, 2048),
2052            ("dsa2048-elgamal3072.pgp", 1, 3072),
2053            ("emmelie-dorothea-dina-samantha-awina-ed25519.pgp", 0, 256),
2054            ("erika-corinna-daniela-simone-antonia-nistp256.pgp", 0, 256),
2055            ("erika-corinna-daniela-simone-antonia-nistp384.pgp", 0, 384),
2056            ("erika-corinna-daniela-simone-antonia-nistp521.pgp", 0, 521),
2057        ] {
2058            let cert = crate::Cert::from_bytes(crate::tests::key(name)).unwrap();
2059            let ka = cert.keys().nth(*key_no).unwrap();
2060            assert_eq!(ka.key().mpis().bits().unwrap(), *bits,
2061                       "Cert {}, key no {}", name, *key_no);
2062        }
2063    }
2064
2065    quickcheck! {
2066        fn sk_roundtrip(sk: SecretKeyMaterial) -> bool {
2067            let mut buf = Vec::new();
2068            sk.serialize(&mut buf).unwrap();
2069            let sk_ =
2070                SecretKeyMaterial::from_bytes(sk.algo().unwrap(),
2071                                              &buf).unwrap();
2072
2073            sk == sk_
2074        }
2075    }
2076
2077    quickcheck! {
2078        fn ct_roundtrip(ct: Ciphertext) -> bool {
2079            use std::io::Cursor;
2080
2081            let mut buf = Vec::new();
2082            ct.serialize(&mut buf).unwrap();
2083            let cur = Cursor::new(buf);
2084            let ct_ = Ciphertext::parse(ct.pk_algo().unwrap(), cur).unwrap();
2085
2086            ct == ct_
2087        }
2088    }
2089
2090    quickcheck! {
2091        fn signature_roundtrip(sig: Signature) -> bool {
2092            use std::io::Cursor;
2093            use crate::PublicKeyAlgorithm::*;
2094
2095            let mut buf = Vec::new();
2096            sig.serialize(&mut buf).unwrap();
2097            let cur = Cursor::new(buf);
2098
2099            #[allow(deprecated)]
2100            let sig_ = match &sig {
2101                Signature::RSA { .. } =>
2102                    Signature::parse(RSAEncryptSign, cur).unwrap(),
2103                Signature::DSA { .. } =>
2104                    Signature::parse(DSA, cur).unwrap(),
2105                Signature::ElGamal { .. } =>
2106                    Signature::parse(ElGamalEncryptSign, cur).unwrap(),
2107                Signature::EdDSA { .. } =>
2108                    Signature::parse(EdDSA, cur).unwrap(),
2109                Signature::ECDSA { .. } =>
2110                    Signature::parse(ECDSA, cur).unwrap(),
2111                Signature::Ed25519 { .. } =>
2112                    Signature::parse(Ed25519, cur).unwrap(),
2113                Signature::Ed448 { .. } =>
2114                    Signature::parse(Ed448, cur).unwrap(),
2115
2116                Signature::MLDSA65_Ed25519 { .. } =>
2117                    Signature::parse(MLDSA65_Ed25519, cur).unwrap(),
2118                Signature::MLDSA87_Ed448 { .. } =>
2119                    Signature::parse(MLDSA87_Ed448, cur).unwrap(),
2120
2121                Signature::SLHDSA128s { .. } =>
2122                    Signature::parse(SLHDSA128s, cur).unwrap(),
2123                Signature::SLHDSA128f { .. } =>
2124                    Signature::parse(SLHDSA128f, cur).unwrap(),
2125                Signature::SLHDSA256s { .. } =>
2126                    Signature::parse(SLHDSA256s, cur).unwrap(),
2127
2128                Signature::Unknown { .. } => unreachable!(),
2129            };
2130
2131            sig == sig_
2132        }
2133    }
2134}