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 4880]).  Multiprecision integers in OpenPGP are extended by
8//! [RFC 6637] to store curves and coordinates used in elliptic curve
9//! cryptography (ECC).
10//!
11//!   [public keys]: PublicKey
12//!   [secret keys]: SecretKeyMaterial
13//!   [ciphertexts]: Ciphertext
14//!   [signatures]: Signature
15//!   [Section 3.2 of RFC 4880]: https://tools.ietf.org/html/rfc4880#section-3.2
16//!   [RFC 6637]: https://tools.ietf.org/html/rfc6637
17
18use std::fmt;
19use std::cmp::Ordering;
20use std::io::Write;
21use std::borrow::Cow;
22
23#[cfg(test)]
24use quickcheck::{Arbitrary, Gen};
25
26use crate::types::{
27    Curve,
28    HashAlgorithm,
29    PublicKeyAlgorithm,
30    SymmetricAlgorithm,
31};
32use crate::crypto::hash::{self, Hash};
33use crate::crypto::mem::{secure_cmp, Protected};
34use crate::serialize::Marshal;
35
36use crate::Error;
37use crate::Result;
38
39/// 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 a 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 a 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            Unknown(_) if ! curve.is_brainpoolp384() =>
220                Err(Error::UnsupportedEllipticCurve(curve.clone()).into()),
221
222            NistP256
223                | NistP384
224                | NistP521
225                | BrainpoolP256
226                | Unknown(_)
227                | BrainpoolP512
228                =>
229            {
230                // Length of one coordinate in bytes, rounded up.
231                let coordinate_length = curve.field_size()?;
232
233                // Check length of Q.
234                let expected_length =
235                    1 // 0x04.
236                    + (2 // (x, y)
237                       * coordinate_length);
238
239                if value.len() != expected_length {
240                    return Err(Error::MalformedMPI(
241                        format!("Invalid length of MPI: {} (expected {})",
242                                value.len(), expected_length)).into());
243                }
244
245                if value.get(0).map(|&b| b != 0x04).unwrap_or(true) {
246                    return Err(Error::MalformedMPI(
247                        format!("Bad prefix: {:?} (expected Some(0x04))",
248                                value.get(0))).into());
249                }
250
251                Ok((&value[1..1 + coordinate_length],
252                    &value[1 + coordinate_length..]))
253            },
254        }
255    }
256
257    /// 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 dyn hash::Digest) {
286        let len = self.bits() as u16;
287
288        hash.update(&len.to_be_bytes());
289        hash.update(&self.value);
290    }
291}
292
293#[cfg(test)]
294impl Arbitrary for MPI {
295    fn arbitrary(g: &mut Gen) -> Self {
296        loop {
297            let buf = <Vec<u8>>::arbitrary(g);
298
299            if !buf.is_empty() && buf[0] != 0 {
300                break MPI::new(&buf);
301            }
302        }
303    }
304}
305
306impl PartialOrd for MPI {
307    fn partial_cmp(&self, other: &MPI) -> Option<Ordering> {
308        Some(self.cmp(other))
309    }
310}
311
312impl Ord for MPI {
313    fn cmp(&self, other: &MPI) -> Ordering {
314        self.secure_memcmp(other)
315    }
316}
317
318impl PartialEq for MPI {
319    fn eq(&self, other: &MPI) -> bool {
320        self.cmp(other) == Ordering::Equal
321    }
322}
323
324impl Eq for MPI {}
325
326impl std::hash::Hash for MPI {
327    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
328        self.value.hash(state);
329    }
330}
331
332/// Holds a single MPI containing secrets.
333///
334/// The memory will be cleared when the object is dropped.  Used by
335/// [`SecretKeyMaterial`] to protect secret keys.
336///
337#[derive(Clone)]
338pub struct ProtectedMPI {
339    /// Integer value as big-endian.
340    value: Protected,
341}
342assert_send_and_sync!(ProtectedMPI);
343
344impl From<&[u8]> for ProtectedMPI {
345    fn from(m: &[u8]) -> Self {
346        let value = Protected::from(MPI::trim_leading_zeros(m));
347        ProtectedMPI {
348            value,
349        }
350    }
351}
352
353impl From<Vec<u8>> for ProtectedMPI {
354    fn from(m: Vec<u8>) -> Self {
355        let value = Protected::from(MPI::trim_leading_zeros(&m));
356        drop(Protected::from(m)); // Erase source.
357        ProtectedMPI {
358            value,
359        }
360    }
361}
362
363impl From<Box<[u8]>> for ProtectedMPI {
364    fn from(m: Box<[u8]>) -> Self {
365        let value = Protected::from(MPI::trim_leading_zeros(&m));
366        drop(Protected::from(m)); // Erase source.
367        ProtectedMPI {
368            value,
369        }
370    }
371}
372
373impl From<Protected> for ProtectedMPI {
374    fn from(m: Protected) -> Self {
375        let value = Protected::from(MPI::trim_leading_zeros(&m));
376        drop(m); // Erase source.
377        ProtectedMPI {
378            value,
379        }
380    }
381}
382
383// XXX: In 2.0, get rid of this conversion.  If the value has been
384// parsed into an MPI, it may have already leaked.
385impl From<MPI> for ProtectedMPI {
386    fn from(m: MPI) -> Self {
387        ProtectedMPI {
388            value: m.value.into(),
389        }
390    }
391}
392
393impl PartialOrd for ProtectedMPI {
394    fn partial_cmp(&self, other: &ProtectedMPI) -> Option<Ordering> {
395        Some(self.cmp(other))
396    }
397}
398
399impl Ord for ProtectedMPI {
400    fn cmp(&self, other: &ProtectedMPI) -> Ordering {
401        self.secure_memcmp(other)
402    }
403}
404
405impl PartialEq for ProtectedMPI {
406    fn eq(&self, other: &ProtectedMPI) -> bool {
407        self.cmp(other) == Ordering::Equal
408    }
409}
410
411impl Eq for ProtectedMPI {}
412
413impl std::hash::Hash for ProtectedMPI {
414    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
415        self.value.hash(state);
416    }
417}
418
419impl ProtectedMPI {
420    /// Creates new MPI encoding an uncompressed EC point.
421    ///
422    /// Encodes the given point on a elliptic curve (see [Section 6 of
423    /// RFC 6637] for details).  This is used to encode public keys
424    /// and ciphertexts for the NIST curves (`NistP256`, `NistP384`,
425    /// and `NistP521`).
426    ///
427    ///   [Section 6 of RFC 6637]: https://tools.ietf.org/html/rfc6637#section-6
428    pub fn new_point(x: &[u8], y: &[u8], field_bits: usize) -> Self {
429        MPI::new_point_common(x, y, field_bits).into()
430    }
431
432    /// Creates new MPI encoding a compressed EC point using native
433    /// encoding.
434    ///
435    /// Encodes the given point on a elliptic curve (see [Section 13.2
436    /// of RFC4880bis] for details).  This is used to encode public
437    /// keys and ciphertexts for the Bernstein curves (currently
438    /// `X25519`).
439    ///
440    ///   [Section 13.2 of RFC4880bis]: https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-09#section-13.2
441    pub fn new_compressed_point(x: &[u8]) -> Self {
442        MPI::new_compressed_point_common(x).into()
443    }
444
445    /// Returns the length of the MPI in bits.
446    ///
447    /// Leading zero-bits are not included in the returned size.
448    pub fn bits(&self) -> usize {
449        self.value.len() * 8
450            - self.value.get(0).map(|&b| b.leading_zeros() as usize)
451                  .unwrap_or(0)
452    }
453
454    /// Returns the value of this MPI.
455    ///
456    /// Note that due to stripping of zero-bytes, the returned value
457    /// may be shorter than expected.
458    pub fn value(&self) -> &[u8] {
459        &self.value
460    }
461
462    /// Returns the value of this MPI zero-padded to the given length.
463    ///
464    /// MPI-encoding strips leading zero-bytes.  This function adds
465    /// them back.  This operation is done unconditionally to avoid
466    /// timing differences.  If the size exceeds `to`, the result is
467    /// silently truncated to avoid timing differences.
468    pub fn value_padded(&self, to: usize) -> Protected {
469        let missing = to.saturating_sub(self.value.len());
470        let limit = self.value.len().min(to);
471        let mut v: Protected = vec![0; to].into();
472        v[missing..].copy_from_slice(&self.value()[..limit]);
473        v
474    }
475
476    /// Decodes an EC point encoded as MPI.
477    ///
478    /// Decodes the MPI into a point on an elliptic curve (see
479    /// [Section 6 of RFC 6637] and [Section 13.2 of RFC4880bis] for
480    /// details).  If the point is not compressed, the function
481    /// returns `(x, y)`.  If it is compressed, `y` will be empty.
482    ///
483    ///   [Section 6 of RFC 6637]: https://tools.ietf.org/html/rfc6637#section-6
484    ///   [Section 13.2 of RFC4880bis]: https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-09#section-13.2
485    ///
486    /// # Errors
487    ///
488    /// Returns `Error::UnsupportedEllipticCurve` if the curve is not
489    /// supported, `Error::MalformedMPI` if the point is formatted
490    /// incorrectly, `Error::InvalidOperation` if the given curve is
491    /// operating on native octet strings.
492    pub fn decode_point(&self, curve: &Curve) -> Result<(&[u8], &[u8])> {
493        MPI::decode_point_common(self.value(), curve)
494    }
495
496    /// Securely compares two MPIs in constant time.
497    fn secure_memcmp(&self, other: &Self) -> Ordering {
498        (self.value.len() as i32).cmp(&(other.value.len() as i32))
499            .then(
500                // Protected compares in constant time.
501                self.value.cmp(&other.value))
502    }
503}
504
505impl fmt::Debug for ProtectedMPI {
506    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
507        if cfg!(debug_assertions) {
508            f.write_fmt(format_args!(
509                "{} bits: {}", self.bits(),
510                crate::fmt::to_hex(&*self.value, true)))
511        } else {
512            f.write_str("<Redacted>")
513        }
514    }
515}
516
517/// A public key.
518///
519/// Provides a typed and structured way of storing multiple MPIs (and
520/// the occasional elliptic curve) in [`Key`] packets.
521///
522///   [`Key`]: crate::packet::Key
523///
524/// Note: This enum cannot be exhaustively matched to allow future
525/// extensions.
526#[non_exhaustive]
527#[derive(Clone, PartialEq, Eq, Hash, Debug, PartialOrd, Ord)]
528pub enum PublicKey {
529    /// RSA public key.
530    RSA {
531        /// Public exponent
532        e: MPI,
533        /// Public modulo N = pq.
534        n: MPI,
535    },
536
537    /// NIST DSA public key.
538    DSA {
539        /// Prime of the ring Zp.
540        p: MPI,
541        /// Order of `g` in Zp.
542        q: MPI,
543        /// Public generator of Zp.
544        g: MPI,
545        /// Public key g^x mod p.
546        y: MPI,
547    },
548
549    /// ElGamal public key.
550    ElGamal {
551        /// Prime of the ring Zp.
552        p: MPI,
553        /// Generator of Zp.
554        g: MPI,
555        /// Public key g^x mod p.
556        y: MPI,
557    },
558
559    /// DJB's "Twisted" Edwards curve DSA public key.
560    EdDSA {
561        /// Curve we're using. Must be curve 25519.
562        curve: Curve,
563        /// Public point.
564        q: MPI,
565    },
566
567    /// NIST's Elliptic Curve DSA public key.
568    ECDSA {
569        /// Curve we're using.
570        curve: Curve,
571        /// Public point.
572        q: MPI,
573    },
574
575    /// Elliptic Curve Diffie-Hellman public key.
576    ECDH {
577        /// Curve we're using.
578        curve: Curve,
579        /// Public point.
580        q: MPI,
581        /// Algorithm used to derive the Key Encapsulation Key.
582        hash: HashAlgorithm,
583        /// Algorithm used to encapsulate the session key.
584        sym: SymmetricAlgorithm,
585    },
586
587    /// Unknown number of MPIs for an unknown algorithm.
588    Unknown {
589        /// The successfully parsed MPIs.
590        mpis: Box<[MPI]>,
591        /// Any data that failed to parse.
592        rest: Box<[u8]>,
593    },
594}
595assert_send_and_sync!(PublicKey);
596
597impl PublicKey {
598    /// Returns the length of the public key in bits.
599    ///
600    /// For finite field crypto this returns the size of the field we
601    /// operate in, for ECC it returns `Curve::bits()`.
602    ///
603    /// Note: This information is useless and should not be used to
604    /// gauge the security of a particular key. This function exists
605    /// only because some legacy PGP application like HKP need it.
606    ///
607    /// Returns `None` for unknown keys and curves.
608    pub fn bits(&self) -> Option<usize> {
609        use self::PublicKey::*;
610        match self {
611            RSA { ref n,.. } => Some(n.bits()),
612            DSA { ref p,.. } => Some(p.bits()),
613            ElGamal { ref p,.. } => Some(p.bits()),
614            EdDSA { ref curve,.. } => curve.bits(),
615            ECDSA { ref curve,.. } => curve.bits(),
616            ECDH { ref curve,.. } => curve.bits(),
617            Unknown { .. } => None,
618        }
619    }
620
621    /// Returns, if known, the public-key algorithm for this public
622    /// key.
623    pub fn algo(&self) -> Option<PublicKeyAlgorithm> {
624        use self::PublicKey::*;
625        match self {
626            RSA { .. } => Some(PublicKeyAlgorithm::RSAEncryptSign),
627            DSA { .. } => Some(PublicKeyAlgorithm::DSA),
628            ElGamal { .. } => Some(PublicKeyAlgorithm::ElGamalEncrypt),
629            EdDSA { .. } => Some(PublicKeyAlgorithm::EdDSA),
630            ECDSA { .. } => Some(PublicKeyAlgorithm::ECDSA),
631            ECDH { .. } => Some(PublicKeyAlgorithm::ECDH),
632            Unknown { .. } => None,
633        }
634    }
635}
636
637impl Hash for PublicKey {
638    fn hash(&self, mut hash: &mut dyn hash::Digest) {
639        self.serialize(&mut hash as &mut dyn Write)
640            .expect("hashing does not fail")
641    }
642}
643
644#[cfg(test)]
645impl Arbitrary for PublicKey {
646    fn arbitrary(g: &mut Gen) -> Self {
647        use self::PublicKey::*;
648        use crate::arbitrary_helper::gen_arbitrary_from_range;
649
650        match gen_arbitrary_from_range(0..6, g) {
651            0 => RSA {
652                e: MPI::arbitrary(g),
653                n: MPI::arbitrary(g),
654            },
655
656            1 => DSA {
657                p: MPI::arbitrary(g),
658                q: MPI::arbitrary(g),
659                g: MPI::arbitrary(g),
660                y: MPI::arbitrary(g),
661            },
662
663            2 => ElGamal {
664                p: MPI::arbitrary(g),
665                g: MPI::arbitrary(g),
666                y: MPI::arbitrary(g),
667            },
668
669            3 => EdDSA {
670                curve: Curve::arbitrary(g),
671                q: MPI::arbitrary(g),
672            },
673
674            4 => ECDSA {
675                curve: Curve::arbitrary(g),
676                q: MPI::arbitrary(g),
677            },
678
679            5 => ECDH {
680                curve: Curve::arbitrary(g),
681                q: MPI::arbitrary(g),
682                hash: HashAlgorithm::arbitrary(g),
683                sym: SymmetricAlgorithm::arbitrary(g),
684            },
685
686            _ => unreachable!(),
687        }
688    }
689}
690
691/// A secret key.
692///
693/// Provides a typed and structured way of storing multiple MPIs in
694/// [`Key`] packets.  Secret key components are protected by storing
695/// them using [`ProtectedMPI`].
696///
697///   [`Key`]: crate::packet::Key
698///
699/// Note: This enum cannot be exhaustively matched to allow future
700/// extensions.
701// Deriving Hash here is okay: PartialEq is manually implemented to
702// ensure that secrets are compared in constant-time.
703#[non_exhaustive]
704#[allow(clippy::derived_hash_with_manual_eq)]
705#[derive(Clone, Hash)]
706pub enum SecretKeyMaterial {
707    /// RSA secret key.
708    RSA {
709        /// Secret exponent, inverse of e in Phi(N).
710        d: ProtectedMPI,
711        /// Smaller secret prime.
712        p: ProtectedMPI,
713        /// Larger secret prime.
714        q: ProtectedMPI,
715        /// Inverse of p mod q.
716        u: ProtectedMPI,
717    },
718
719    /// NIST DSA secret key.
720    DSA {
721        /// Secret key log_g(y) in Zp.
722        x: ProtectedMPI,
723    },
724
725    /// ElGamal secret key.
726    ElGamal {
727        /// Secret key log_g(y) in Zp.
728        x: ProtectedMPI,
729    },
730
731    /// DJB's "Twisted" Edwards curve DSA secret key.
732    EdDSA {
733        /// Secret scalar.
734        scalar: ProtectedMPI,
735    },
736
737    /// NIST's Elliptic Curve DSA secret key.
738    ECDSA {
739        /// Secret scalar.
740        scalar: ProtectedMPI,
741    },
742
743    /// Elliptic Curve Diffie-Hellman secret key.
744    ECDH {
745        /// Secret scalar.
746        scalar: ProtectedMPI,
747    },
748
749    /// Unknown number of MPIs for an unknown algorithm.
750    Unknown {
751        /// The successfully parsed MPIs.
752        mpis: Box<[ProtectedMPI]>,
753        /// Any data that failed to parse.
754        rest: Protected,
755    },
756}
757assert_send_and_sync!(SecretKeyMaterial);
758
759impl fmt::Debug for SecretKeyMaterial {
760    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
761        if cfg!(debug_assertions) {
762            match self {
763                SecretKeyMaterial::RSA{ ref d, ref p, ref q, ref u } =>
764                    write!(f, "RSA {{ d: {:?}, p: {:?}, q: {:?}, u: {:?} }}", d, p, q, u),
765                SecretKeyMaterial::DSA{ ref x } =>
766                    write!(f, "DSA {{ x: {:?} }}", x),
767                SecretKeyMaterial::ElGamal{ ref x } =>
768                    write!(f, "ElGamal {{ x: {:?} }}", x),
769                SecretKeyMaterial::EdDSA{ ref scalar } =>
770                    write!(f, "EdDSA {{ scalar: {:?} }}", scalar),
771                SecretKeyMaterial::ECDSA{ ref scalar } =>
772                    write!(f, "ECDSA {{ scalar: {:?} }}", scalar),
773                SecretKeyMaterial::ECDH{ ref scalar } =>
774                    write!(f, "ECDH {{ scalar: {:?} }}", scalar),
775                SecretKeyMaterial::Unknown{ ref mpis, ref rest } =>
776                    write!(f, "Unknown {{ mips: {:?}, rest: {:?} }}", mpis, rest),
777            }
778        } else {
779            match self {
780                SecretKeyMaterial::RSA{ .. } =>
781                    f.write_str("RSA { <Redacted> }"),
782                SecretKeyMaterial::DSA{ .. } =>
783                    f.write_str("DSA { <Redacted> }"),
784                SecretKeyMaterial::ElGamal{ .. } =>
785                    f.write_str("ElGamal { <Redacted> }"),
786                SecretKeyMaterial::EdDSA{ .. } =>
787                    f.write_str("EdDSA { <Redacted> }"),
788                SecretKeyMaterial::ECDSA{ .. } =>
789                    f.write_str("ECDSA { <Redacted> }"),
790                SecretKeyMaterial::ECDH{ .. } =>
791                    f.write_str("ECDH { <Redacted> }"),
792                SecretKeyMaterial::Unknown{ .. } =>
793                    f.write_str("Unknown { <Redacted> }"),
794            }
795        }
796    }
797}
798
799impl PartialOrd for SecretKeyMaterial {
800    fn partial_cmp(&self, other: &SecretKeyMaterial) -> Option<Ordering> {
801        Some(self.cmp(other))
802    }
803}
804
805impl Ord for SecretKeyMaterial {
806    fn cmp(&self, other: &Self) -> Ordering {
807        use std::iter;
808
809        fn discriminant(sk: &SecretKeyMaterial) -> usize {
810            match sk {
811                SecretKeyMaterial::RSA{ .. } => 0,
812                SecretKeyMaterial::DSA{ .. } => 1,
813                SecretKeyMaterial::ElGamal{ .. } => 2,
814                SecretKeyMaterial::EdDSA{ .. } => 3,
815                SecretKeyMaterial::ECDSA{ .. } => 4,
816                SecretKeyMaterial::ECDH{ .. } => 5,
817                SecretKeyMaterial::Unknown{ .. } => 6,
818            }
819        }
820
821        let ret = match (self, other) {
822            (&SecretKeyMaterial::RSA{ d: ref d1, p: ref p1, q: ref q1, u: ref u1 }
823            ,&SecretKeyMaterial::RSA{ d: ref d2, p: ref p2, q: ref q2, u: ref u2 }) => {
824                let o1 = d1.cmp(d2);
825                let o2 = p1.cmp(p2);
826                let o3 = q1.cmp(q2);
827                let o4 = u1.cmp(u2);
828
829                if o1 != Ordering::Equal { return o1; }
830                if o2 != Ordering::Equal { return o2; }
831                if o3 != Ordering::Equal { return o3; }
832                o4
833            }
834            (&SecretKeyMaterial::DSA{ x: ref x1 }
835            ,&SecretKeyMaterial::DSA{ x: ref x2 }) => {
836                x1.cmp(x2)
837            }
838            (&SecretKeyMaterial::ElGamal{ x: ref x1 }
839            ,&SecretKeyMaterial::ElGamal{ x: ref x2 }) => {
840                x1.cmp(x2)
841            }
842            (&SecretKeyMaterial::EdDSA{ scalar: ref scalar1 }
843            ,&SecretKeyMaterial::EdDSA{ scalar: ref scalar2 }) => {
844                scalar1.cmp(scalar2)
845            }
846            (&SecretKeyMaterial::ECDSA{ scalar: ref scalar1 }
847            ,&SecretKeyMaterial::ECDSA{ scalar: ref scalar2 }) => {
848                scalar1.cmp(scalar2)
849            }
850            (&SecretKeyMaterial::ECDH{ scalar: ref scalar1 }
851            ,&SecretKeyMaterial::ECDH{ scalar: ref scalar2 }) => {
852                scalar1.cmp(scalar2)
853            }
854            (&SecretKeyMaterial::Unknown{ mpis: ref mpis1, rest: ref rest1 }
855            ,&SecretKeyMaterial::Unknown{ mpis: ref mpis2, rest: ref rest2 }) => {
856                let o1 = secure_cmp(rest1, rest2);
857                let o2 = mpis1.len().cmp(&mpis2.len());
858                let on = mpis1.iter().zip(mpis2.iter()).map(|(a,b)| {
859                    a.cmp(b)
860                }).collect::<Vec<_>>();
861
862                iter::once(o1)
863                    .chain(iter::once(o2))
864                    .chain(on.iter().cloned())
865                    .fold(Ordering::Equal, |acc, x| acc.then(x))
866            }
867
868            (a, b) => {
869                let ret = discriminant(a).cmp(&discriminant(b));
870
871                assert!(ret != Ordering::Equal);
872                ret
873            }
874        };
875
876        ret
877    }
878}
879
880impl PartialEq for SecretKeyMaterial {
881    fn eq(&self, other: &Self) -> bool { self.cmp(other) == Ordering::Equal }
882}
883
884impl Eq for SecretKeyMaterial {}
885
886impl SecretKeyMaterial {
887    /// Returns, if known, the public-key algorithm for this secret
888    /// key.
889    pub fn algo(&self) -> Option<PublicKeyAlgorithm> {
890        use self::SecretKeyMaterial::*;
891        match self {
892            RSA { .. } => Some(PublicKeyAlgorithm::RSAEncryptSign),
893            DSA { .. } => Some(PublicKeyAlgorithm::DSA),
894            ElGamal { .. } => Some(PublicKeyAlgorithm::ElGamalEncrypt),
895            EdDSA { .. } => Some(PublicKeyAlgorithm::EdDSA),
896            ECDSA { .. } => Some(PublicKeyAlgorithm::ECDSA),
897            ECDH { .. } => Some(PublicKeyAlgorithm::ECDH),
898            Unknown { .. } => None,
899        }
900    }
901}
902
903impl Hash for SecretKeyMaterial {
904    fn hash(&self, mut hash: &mut dyn hash::Digest) {
905        self.serialize(&mut hash as &mut dyn Write)
906            .expect("hashing does not fail")
907    }
908}
909
910#[cfg(test)]
911impl SecretKeyMaterial {
912    pub(crate) fn arbitrary_for(g: &mut Gen, pk: PublicKeyAlgorithm) -> Result<Self> {
913        use self::PublicKeyAlgorithm::*;
914        #[allow(deprecated)]
915        match pk {
916            RSAEncryptSign | RSASign | RSAEncrypt => Ok(SecretKeyMaterial::RSA {
917                d: MPI::arbitrary(g).into(),
918                p: MPI::arbitrary(g).into(),
919                q: MPI::arbitrary(g).into(),
920                u: MPI::arbitrary(g).into(),
921            }),
922
923            DSA => Ok(SecretKeyMaterial::DSA {
924                x: MPI::arbitrary(g).into(),
925            }),
926
927            ElGamalEncryptSign | ElGamalEncrypt => Ok(SecretKeyMaterial::ElGamal {
928                x: MPI::arbitrary(g).into(),
929            }),
930
931            EdDSA => Ok(SecretKeyMaterial::EdDSA {
932                scalar: MPI::arbitrary(g).into(),
933            }),
934
935            ECDSA => Ok(SecretKeyMaterial::ECDSA {
936                scalar: MPI::arbitrary(g).into(),
937            }),
938
939            ECDH => Ok(SecretKeyMaterial::ECDH {
940                scalar: MPI::arbitrary(g).into(),
941            }),
942
943            Private(_) | Unknown(_) =>
944                Err(Error::UnsupportedPublicKeyAlgorithm(pk).into()),
945        }
946    }
947}
948#[cfg(test)]
949impl Arbitrary for SecretKeyMaterial {
950    fn arbitrary(g: &mut Gen) -> Self {
951        let pk = *g.choose(&crate::types::PUBLIC_KEY_ALGORITHM_VARIANTS)
952            .expect("not empty");
953        Self::arbitrary_for(g, pk).expect("only known variants")
954    }
955}
956
957/// Checksum method for secret key material.
958///
959/// Secret key material may be protected by a checksum.  See [Section
960/// 5.5.3 of RFC 4880] for details.
961///
962///   [Section 5.5.3 of RFC 4880]: https://tools.ietf.org/html/rfc4880#section-5.5.3
963#[derive(PartialEq, Eq, Hash, Clone, Copy, Debug)]
964pub enum SecretKeyChecksum {
965    /// SHA1 over the decrypted secret key.
966    SHA1,
967
968    /// Sum of the decrypted secret key octets modulo 65536.
969    Sum16,
970}
971assert_send_and_sync!(SecretKeyChecksum);
972
973impl Default for SecretKeyChecksum {
974    fn default() -> Self {
975        SecretKeyChecksum::SHA1
976    }
977}
978
979impl SecretKeyChecksum {
980    /// Returns the on-wire length of the checksum.
981    pub(crate) fn len(&self) -> usize {
982        match self {
983            SecretKeyChecksum::SHA1 => 20,
984            SecretKeyChecksum::Sum16 => 2,
985        }
986    }
987}
988
989/// An encrypted session key.
990///
991/// Provides a typed and structured way of storing multiple MPIs in
992/// [`PKESK`] packets.
993///
994///   [`PKESK`]: crate::packet::PKESK
995///
996/// Note: This enum cannot be exhaustively matched to allow future
997/// extensions.
998#[non_exhaustive]
999#[derive(Clone, PartialEq, Eq, Hash, Debug, PartialOrd, Ord)]
1000pub enum Ciphertext {
1001    /// RSA ciphertext.
1002    RSA {
1003        ///  m^e mod N.
1004        c: MPI,
1005    },
1006
1007    /// ElGamal ciphertext.
1008    ElGamal {
1009        /// Ephemeral key.
1010        e: MPI,
1011        /// Ciphertext.
1012        c: MPI,
1013    },
1014
1015    /// Elliptic curve ElGamal public key.
1016    ECDH {
1017        /// Ephemeral key.
1018        e: MPI,
1019        /// Symmetrically encrypted session key.
1020        key: Box<[u8]>,
1021    },
1022
1023    /// Unknown number of MPIs for an unknown algorithm.
1024    Unknown {
1025        /// The successfully parsed MPIs.
1026        mpis: Box<[MPI]>,
1027        /// Any data that failed to parse.
1028        rest: Box<[u8]>,
1029    },
1030}
1031assert_send_and_sync!(Ciphertext);
1032
1033impl Ciphertext {
1034    /// Returns, if known, the public-key algorithm for this
1035    /// ciphertext.
1036    pub fn pk_algo(&self) -> Option<PublicKeyAlgorithm> {
1037        use self::Ciphertext::*;
1038
1039        // Fields are mostly MPIs that consist of two octets length
1040        // plus the big endian value itself. All other field types are
1041        // commented.
1042        match self {
1043            RSA { .. } => Some(PublicKeyAlgorithm::RSAEncryptSign),
1044            ElGamal { .. } => Some(PublicKeyAlgorithm::ElGamalEncrypt),
1045            ECDH { .. } => Some(PublicKeyAlgorithm::ECDH),
1046            Unknown { .. } => None,
1047        }
1048    }
1049}
1050
1051impl Hash for Ciphertext {
1052    fn hash(&self, mut hash: &mut dyn hash::Digest) {
1053        self.serialize(&mut hash as &mut dyn Write)
1054            .expect("hashing does not fail")
1055    }
1056}
1057
1058#[cfg(test)]
1059impl Arbitrary for Ciphertext {
1060    fn arbitrary(g: &mut Gen) -> Self {
1061        use crate::arbitrary_helper::gen_arbitrary_from_range;
1062
1063        match gen_arbitrary_from_range(0..3, g) {
1064            0 => Ciphertext::RSA {
1065                c: MPI::arbitrary(g),
1066            },
1067
1068            1 => Ciphertext::ElGamal {
1069                e: MPI::arbitrary(g),
1070                c: MPI::arbitrary(g)
1071            },
1072
1073            2 => Ciphertext::ECDH {
1074                e: MPI::arbitrary(g),
1075                key: {
1076                    let mut k = <Vec<u8>>::arbitrary(g);
1077                    k.truncate(255);
1078                    k.into_boxed_slice()
1079                },
1080            },
1081            _ => unreachable!(),
1082        }
1083    }
1084}
1085
1086/// A cryptographic signature.
1087///
1088/// Provides a typed and structured way of storing multiple MPIs in
1089/// [`Signature`] packets.
1090///
1091///   [`Signature`]: crate::packet::Signature
1092///
1093/// Note: This enum cannot be exhaustively matched to allow future
1094/// extensions.
1095#[non_exhaustive]
1096#[derive(Clone, PartialEq, Eq, Hash, Debug, PartialOrd, Ord)]
1097pub enum Signature {
1098    /// RSA signature.
1099    RSA {
1100        /// Signature m^d mod N.
1101        s: MPI,
1102    },
1103
1104    /// NIST's DSA signature.
1105    DSA {
1106        /// `r` value.
1107        r: MPI,
1108        /// `s` value.
1109        s: MPI,
1110    },
1111
1112    /// ElGamal signature.
1113    ElGamal {
1114        /// `r` value.
1115        r: MPI,
1116        /// `s` value.
1117        s: MPI,
1118    },
1119
1120    /// DJB's "Twisted" Edwards curve DSA signature.
1121    EdDSA {
1122        /// `r` value.
1123        r: MPI,
1124        /// `s` value.
1125        s: MPI,
1126    },
1127
1128    /// NIST's Elliptic curve DSA signature.
1129    ECDSA {
1130        /// `r` value.
1131        r: MPI,
1132        /// `s` value.
1133        s: MPI,
1134    },
1135
1136    /// Unknown number of MPIs for an unknown algorithm.
1137    Unknown {
1138        /// The successfully parsed MPIs.
1139        mpis: Box<[MPI]>,
1140        /// Any data that failed to parse.
1141        rest: Box<[u8]>,
1142    },
1143}
1144assert_send_and_sync!(Signature);
1145
1146impl Hash for Signature {
1147    fn hash(&self, mut hash: &mut dyn hash::Digest) {
1148        self.serialize(&mut hash as &mut dyn Write)
1149            .expect("hashing does not fail")
1150    }
1151}
1152
1153#[cfg(test)]
1154impl Arbitrary for Signature {
1155    fn arbitrary(g: &mut Gen) -> Self {
1156        use crate::arbitrary_helper::gen_arbitrary_from_range;
1157
1158        match gen_arbitrary_from_range(0..4, g) {
1159            0 => Signature::RSA  {
1160                s: MPI::arbitrary(g),
1161            },
1162
1163            1 => Signature::DSA {
1164                r: MPI::arbitrary(g),
1165                s: MPI::arbitrary(g),
1166            },
1167
1168            2 => Signature::EdDSA  {
1169                r: MPI::arbitrary(g),
1170                s: MPI::arbitrary(g),
1171            },
1172
1173            3 => Signature::ECDSA  {
1174                r: MPI::arbitrary(g),
1175                s: MPI::arbitrary(g),
1176            },
1177
1178            _ => unreachable!(),
1179        }
1180    }
1181}
1182
1183#[cfg(test)]
1184mod tests {
1185    use super::*;
1186    use crate::parse::Parse;
1187
1188    quickcheck! {
1189        fn mpi_roundtrip(mpi: MPI) -> bool {
1190            let mut buf = Vec::new();
1191            mpi.serialize(&mut buf).unwrap();
1192            MPI::from_bytes(&buf).unwrap() == mpi
1193        }
1194    }
1195
1196    quickcheck! {
1197        fn pk_roundtrip(pk: PublicKey) -> bool {
1198            use std::io::Cursor;
1199            use crate::PublicKeyAlgorithm::*;
1200
1201            let mut buf = Vec::new();
1202            pk.serialize(&mut buf).unwrap();
1203            let cur = Cursor::new(buf);
1204
1205            #[allow(deprecated)]
1206            let pk_ = match &pk {
1207                PublicKey::RSA { .. } =>
1208                    PublicKey::parse(RSAEncryptSign, cur).unwrap(),
1209                PublicKey::DSA { .. } =>
1210                    PublicKey::parse(DSA, cur).unwrap(),
1211                PublicKey::ElGamal { .. } =>
1212                    PublicKey::parse(ElGamalEncrypt, cur).unwrap(),
1213                PublicKey::EdDSA { .. } =>
1214                    PublicKey::parse(EdDSA, cur).unwrap(),
1215                PublicKey::ECDSA { .. } =>
1216                    PublicKey::parse(ECDSA, cur).unwrap(),
1217                PublicKey::ECDH { .. } =>
1218                    PublicKey::parse(ECDH, cur).unwrap(),
1219
1220                PublicKey::Unknown { .. } => unreachable!(),
1221            };
1222
1223            pk == pk_
1224        }
1225    }
1226
1227    #[test]
1228    fn pk_bits() {
1229        for (name, key_no, bits) in &[
1230            ("testy.pgp", 0, 2048),
1231            ("testy-new.pgp", 1, 256),
1232            ("dennis-simon-anton.pgp", 0, 2048),
1233            ("dsa2048-elgamal3072.pgp", 1, 3072),
1234            ("emmelie-dorothea-dina-samantha-awina-ed25519.pgp", 0, 256),
1235            ("erika-corinna-daniela-simone-antonia-nistp256.pgp", 0, 256),
1236            ("erika-corinna-daniela-simone-antonia-nistp384.pgp", 0, 384),
1237            ("erika-corinna-daniela-simone-antonia-nistp521.pgp", 0, 521),
1238        ] {
1239            let cert = crate::Cert::from_bytes(crate::tests::key(name)).unwrap();
1240            let ka = cert.keys().nth(*key_no).unwrap();
1241            assert_eq!(ka.key().mpis().bits().unwrap(), *bits,
1242                       "Cert {}, key no {}", name, *key_no);
1243        }
1244    }
1245
1246    quickcheck! {
1247        fn sk_roundtrip(sk: SecretKeyMaterial) -> bool {
1248            use std::io::Cursor;
1249            use crate::PublicKeyAlgorithm::*;
1250
1251            let mut buf = Vec::new();
1252            sk.serialize(&mut buf).unwrap();
1253            let cur = Cursor::new(buf);
1254
1255            #[allow(deprecated)]
1256            let sk_ = match &sk {
1257                SecretKeyMaterial::RSA { .. } =>
1258                    SecretKeyMaterial::parse(RSAEncryptSign, cur).unwrap(),
1259                SecretKeyMaterial::DSA { .. } =>
1260                    SecretKeyMaterial::parse(DSA, cur).unwrap(),
1261                SecretKeyMaterial::EdDSA { .. } =>
1262                    SecretKeyMaterial::parse(EdDSA, cur).unwrap(),
1263                SecretKeyMaterial::ECDSA { .. } =>
1264                    SecretKeyMaterial::parse(ECDSA, cur).unwrap(),
1265                SecretKeyMaterial::ECDH { .. } =>
1266                    SecretKeyMaterial::parse(ECDH, cur).unwrap(),
1267                SecretKeyMaterial::ElGamal { .. } =>
1268                    SecretKeyMaterial::parse(ElGamalEncrypt, cur).unwrap(),
1269
1270                SecretKeyMaterial::Unknown { .. } => unreachable!(),
1271            };
1272
1273            sk == sk_
1274        }
1275    }
1276
1277    quickcheck! {
1278        fn ct_roundtrip(ct: Ciphertext) -> bool {
1279            use std::io::Cursor;
1280            use crate::PublicKeyAlgorithm::*;
1281
1282            let mut buf = Vec::new();
1283            ct.serialize(&mut buf).unwrap();
1284            let cur = Cursor::new(buf);
1285
1286            #[allow(deprecated)]
1287            let ct_ = match &ct {
1288                Ciphertext::RSA { .. } =>
1289                    Ciphertext::parse(RSAEncryptSign, cur).unwrap(),
1290                Ciphertext::ElGamal { .. } =>
1291                    Ciphertext::parse(ElGamalEncrypt, cur).unwrap(),
1292                Ciphertext::ECDH { .. } =>
1293                    Ciphertext::parse(ECDH, cur).unwrap(),
1294
1295                Ciphertext::Unknown { .. } => unreachable!(),
1296            };
1297
1298            ct == ct_
1299        }
1300    }
1301
1302    quickcheck! {
1303        fn signature_roundtrip(sig: Signature) -> bool {
1304            use std::io::Cursor;
1305            use crate::PublicKeyAlgorithm::*;
1306
1307            let mut buf = Vec::new();
1308            sig.serialize(&mut buf).unwrap();
1309            let cur = Cursor::new(buf);
1310
1311            #[allow(deprecated)]
1312            let sig_ = match &sig {
1313                Signature::RSA { .. } =>
1314                    Signature::parse(RSAEncryptSign, cur).unwrap(),
1315                Signature::DSA { .. } =>
1316                    Signature::parse(DSA, cur).unwrap(),
1317                Signature::ElGamal { .. } =>
1318                    Signature::parse(ElGamalEncryptSign, cur).unwrap(),
1319                Signature::EdDSA { .. } =>
1320                    Signature::parse(EdDSA, cur).unwrap(),
1321                Signature::ECDSA { .. } =>
1322                    Signature::parse(ECDSA, cur).unwrap(),
1323
1324                Signature::Unknown { .. } => unreachable!(),
1325            };
1326
1327            sig == sig_
1328        }
1329    }
1330}