Skip to main content

sequoia_openpgp/packet/key/
v4.rs

1//! OpenPGP v4 key packet.
2
3use std::fmt;
4use std::cmp::Ordering;
5use std::convert::TryInto;
6use std::hash::Hasher;
7use std::time;
8
9#[cfg(test)]
10use quickcheck::{Arbitrary, Gen};
11
12use crate::Error;
13use crate::crypto::{mem::Protected, mpi, hash::Hash, KeyPair};
14use crate::packet;
15use crate::packet::prelude::*;
16use crate::PublicKeyAlgorithm;
17use crate::SymmetricAlgorithm;
18use crate::HashAlgorithm;
19use crate::types::{
20    Curve,
21    Timestamp,
22};
23use crate::Result;
24use crate::crypto::Password;
25use crate::KeyID;
26use crate::Fingerprint;
27use crate::KeyHandle;
28use crate::packet::key::{
29    self,
30    KeyParts,
31    KeyRole,
32    KeyRoleRT,
33    PublicParts,
34    SecretParts,
35    UnspecifiedParts,
36};
37use crate::policy::HashAlgoSecurity;
38
39
40/// Holds a public key, public subkey, private key or private subkey
41/// packet.
42///
43/// Use [`Key4::generate_rsa`] or [`Key4::generate_ecc`] to create a
44/// new key.
45///
46/// Existing key material can be turned into an OpenPGP key using
47/// [`Key4::new`], [`Key4::with_secret`], [`Key4::import_public_cv25519`],
48/// [`Key4::import_public_ed25519`], [`Key4::import_public_rsa`],
49/// [`Key4::import_secret_cv25519`], [`Key4::import_secret_ed25519`],
50/// and [`Key4::import_secret_rsa`].
51///
52/// Whether you create a new key or import existing key material, you
53/// still need to create a binding signature, and, for signing keys, a
54/// back signature before integrating the key into a certificate.
55///
56/// Normally, you won't directly use `Key4`, but [`Key`], which is a
57/// relatively thin wrapper around `Key4`.
58///
59/// See [Section 5.5 of RFC 9580] and [the documentation for `Key`]
60/// for more details.
61///
62/// [Section 5.5 of RFC 9580]: https://www.rfc-editor.org/rfc/rfc9580.html#section-5.5
63/// [the documentation for `Key`]: super::Key
64/// [`Key`]: super::Key
65pub struct Key4<P, R>
66    where P: KeyParts, R: KeyRole
67{
68    /// CTB packet header fields.
69    pub(crate) common: packet::Common,
70    /// When the key was created.
71    pub(crate) creation_time: Timestamp,
72    /// Public key algorithm of this signature.
73    pk_algo: PublicKeyAlgorithm,
74    /// Public key MPIs.
75    mpis: mpi::PublicKey,
76    /// Optional secret part of the key.
77    pub(crate) secret: Option<SecretKeyMaterial>,
78
79    pub(crate) fingerprint: std::sync::OnceLock<Fingerprint>,
80
81    /// The key role tracked at run time.
82    role: KeyRoleRT,
83
84    p: std::marker::PhantomData<P>,
85    r: std::marker::PhantomData<R>,
86}
87
88// derive(Clone) doesn't work as expected with generic type parameters
89// that don't implement clone: it adds a trait bound on Clone to P and
90// R in the Clone implementation.  Happily, we don't need P or R to
91// implement Clone: they are just marker traits, which we can clone
92// manually.
93//
94// See: https://github.com/rust-lang/rust/issues/26925
95impl<P, R> Clone for Key4<P, R>
96    where P: KeyParts, R: KeyRole
97{
98    fn clone(&self) -> Self {
99        Key4 {
100            common: self.common.clone(),
101            creation_time: self.creation_time.clone(),
102            pk_algo: self.pk_algo.clone(),
103            mpis: self.mpis.clone(),
104            secret: self.secret.clone(),
105            fingerprint: self.fingerprint.get()
106                .map(|fp| fp.clone().into())
107                .unwrap_or_default(),
108            role: self.role,
109            p: std::marker::PhantomData,
110            r: std::marker::PhantomData,
111        }
112    }
113}
114
115assert_send_and_sync!(Key4<P, R> where P: KeyParts, R: KeyRole);
116
117impl<P: KeyParts, R: KeyRole> PartialEq for Key4<P, R> {
118    fn eq(&self, other: &Key4<P, R>) -> bool {
119        self.creation_time == other.creation_time
120            && self.pk_algo == other.pk_algo
121            && self.mpis == other.mpis
122            && (! P::significant_secrets() || self.secret == other.secret)
123    }
124}
125
126impl<P: KeyParts, R: KeyRole> Eq for Key4<P, R> {}
127
128impl<P: KeyParts, R: KeyRole> std::hash::Hash for Key4<P, R> {
129    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
130        std::hash::Hash::hash(&self.creation_time, state);
131        std::hash::Hash::hash(&self.pk_algo, state);
132        std::hash::Hash::hash(&self.mpis, state);
133        if P::significant_secrets() {
134            std::hash::Hash::hash(&self.secret, state);
135        }
136    }
137}
138
139impl<P, R> fmt::Debug for Key4<P, R>
140    where P: key::KeyParts,
141          R: key::KeyRole,
142{
143    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
144        f.debug_struct("Key4")
145            .field("fingerprint", &self.fingerprint())
146            .field("creation_time", &self.creation_time)
147            .field("pk_algo", &self.pk_algo)
148            .field("mpis", &self.mpis)
149            .field("secret", &self.secret)
150            .finish()
151    }
152}
153
154impl<P, R> fmt::Display for Key4<P, R>
155    where P: key::KeyParts,
156          R: key::KeyRole,
157{
158    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
159        write!(f, "{}", self.fingerprint())
160    }
161}
162
163impl<P, R> Key4<P, R>
164    where P: key::KeyParts,
165          R: key::KeyRole,
166{
167    /// The security requirements of the hash algorithm for
168    /// self-signatures.
169    ///
170    /// A cryptographic hash algorithm usually has [three security
171    /// properties]: pre-image resistance, second pre-image
172    /// resistance, and collision resistance.  If an attacker can
173    /// influence the signed data, then the hash algorithm needs to
174    /// have both second pre-image resistance, and collision
175    /// resistance.  If not, second pre-image resistance is
176    /// sufficient.
177    ///
178    ///   [three security properties]: https://en.wikipedia.org/wiki/Cryptographic_hash_function#Properties
179    ///
180    /// In general, an attacker may be able to influence third-party
181    /// signatures.  But direct key signatures, and binding signatures
182    /// are only over data fully determined by signer.  And, an
183    /// attacker's control over self signatures over User IDs is
184    /// limited due to their structure.
185    ///
186    /// These observations can be used to extend the life of a hash
187    /// algorithm after its collision resistance has been partially
188    /// compromised, but not completely broken.  For more details,
189    /// please refer to the documentation for [HashAlgoSecurity].
190    ///
191    ///   [HashAlgoSecurity]: crate::policy::HashAlgoSecurity
192    pub fn hash_algo_security(&self) -> HashAlgoSecurity {
193        HashAlgoSecurity::SecondPreImageResistance
194    }
195
196    /// Compares the public bits of two keys.
197    ///
198    /// This returns `Ordering::Equal` if the public MPIs, creation
199    /// time, and algorithm of the two `Key4`s match.  This does not
200    /// consider the packets' encodings, packets' tags or their secret
201    /// key material.
202    pub fn public_cmp<PB, RB>(&self, b: &Key4<PB, RB>) -> Ordering
203        where PB: key::KeyParts,
204              RB: key::KeyRole,
205    {
206        self.mpis.cmp(&b.mpis)
207            .then_with(|| self.creation_time.cmp(&b.creation_time))
208            .then_with(|| self.pk_algo.cmp(&b.pk_algo))
209    }
210
211    /// Tests whether two keys are equal modulo their secret key
212    /// material.
213    ///
214    /// This returns true if the public MPIs, creation time and
215    /// algorithm of the two `Key4`s match.  This does not consider
216    /// the packets' encodings, packets' tags or their secret key
217    /// material.
218    pub fn public_eq<PB, RB>(&self, b: &Key4<PB, RB>) -> bool
219        where PB: key::KeyParts,
220              RB: key::KeyRole,
221    {
222        self.public_cmp(b) == Ordering::Equal
223    }
224
225    /// Hashes everything but any secret key material into state.
226    ///
227    /// This is an alternate implementation of [`Hash`], which never
228    /// hashes the secret key material.
229    ///
230    ///   [`Hash`]: std::hash::Hash
231    pub fn public_hash<H>(&self, state: &mut H)
232        where H: Hasher
233    {
234        use std::hash::Hash;
235
236        self.common.hash(state);
237        self.creation_time.hash(state);
238        self.pk_algo.hash(state);
239        Hash::hash(&self.mpis(), state);
240    }
241}
242
243impl<P, R> Key4<P, R>
244     where P: key::KeyParts,
245           R: key::KeyRole,
246{
247    /// Gets the `Key`'s creation time.
248    pub fn creation_time(&self) -> time::SystemTime {
249        self.creation_time.into()
250    }
251
252    /// Gets the `Key`'s creation time without converting it to a
253    /// system time.
254    ///
255    /// This conversion may truncate the time to signed 32-bit time_t.
256    pub(crate) fn creation_time_raw(&self) -> Timestamp {
257        self.creation_time
258    }
259
260    /// Sets the `Key`'s creation time.
261    ///
262    /// `timestamp` is converted to OpenPGP's internal format,
263    /// [`Timestamp`]: a 32-bit quantity containing the number of
264    /// seconds since the Unix epoch.
265    ///
266    /// `timestamp` is silently rounded to match the internal
267    /// resolution.  An error is returned if `timestamp` is out of
268    /// range.
269    ///
270    /// [`Timestamp`]: crate::types::Timestamp
271    pub fn set_creation_time<T>(&mut self, timestamp: T)
272                                -> Result<time::SystemTime>
273        where T: Into<time::SystemTime>
274    {
275        // Clear the cache.
276        self.fingerprint = Default::default();
277
278        Ok(std::mem::replace(&mut self.creation_time,
279                             timestamp.into().try_into()?)
280           .into())
281    }
282
283    /// Gets the public key algorithm.
284    pub fn pk_algo(&self) -> PublicKeyAlgorithm {
285        self.pk_algo
286    }
287
288    /// Sets the public key algorithm.
289    ///
290    /// Returns the old public key algorithm.
291    pub fn set_pk_algo(&mut self, pk_algo: PublicKeyAlgorithm)
292        -> PublicKeyAlgorithm
293    {
294        // Clear the cache.
295        self.fingerprint = Default::default();
296
297        ::std::mem::replace(&mut self.pk_algo, pk_algo)
298    }
299
300    /// Returns a reference to the `Key`'s MPIs.
301    pub fn mpis(&self) -> &mpi::PublicKey {
302        &self.mpis
303    }
304
305    /// Returns a mutable reference to the `Key`'s MPIs.
306    pub fn mpis_mut(&mut self) -> &mut mpi::PublicKey {
307        // Clear the cache.
308        self.fingerprint = Default::default();
309
310        &mut self.mpis
311    }
312
313    /// Sets the `Key`'s MPIs.
314    ///
315    /// This function returns the old MPIs, if any.
316    pub fn set_mpis(&mut self, mpis: mpi::PublicKey) -> mpi::PublicKey {
317        // Clear the cache.
318        self.fingerprint = Default::default();
319
320        ::std::mem::replace(&mut self.mpis, mpis)
321    }
322
323    /// Returns whether the `Key` contains secret key material.
324    pub fn has_secret(&self) -> bool {
325        self.secret.is_some()
326    }
327
328    /// Returns whether the `Key` contains unencrypted secret key
329    /// material.
330    ///
331    /// This returns false if the `Key` doesn't contain any secret key
332    /// material.
333    pub fn has_unencrypted_secret(&self) -> bool {
334        matches!(self.secret, Some(SecretKeyMaterial::Unencrypted { .. }))
335    }
336
337    /// Returns `Key`'s secret key material, if any.
338    pub fn optional_secret(&self) -> Option<&SecretKeyMaterial> {
339        self.secret.as_ref()
340    }
341
342    /// Computes and returns the `Key`'s `Fingerprint` and returns it as
343    /// a `KeyHandle`.
344    ///
345    /// See [Section 5.5.4 of RFC 9580].
346    ///
347    /// [Section 5.5.4 of RFC 9580]: https://www.rfc-editor.org/rfc/rfc9580.html#section-5.5.4
348    pub fn key_handle(&self) -> KeyHandle {
349        self.fingerprint().into()
350    }
351
352    /// Computes and returns the `Key`'s `Fingerprint`.
353    ///
354    /// See [Key IDs and Fingerprints].
355    ///
356    /// [Key IDs and Fingerprints]: https://www.rfc-editor.org/rfc/rfc9580.html#key-ids-fingerprints
357    pub fn fingerprint(&self) -> Fingerprint {
358        self.fingerprint.get_or_init(|| {
359            let mut h = HashAlgorithm::SHA1.context()
360                .expect("SHA1 is MTI for RFC4880")
361            // v4 fingerprints are computed the same way a key is
362            // hashed for v4 signatures.
363                .for_signature(4);
364
365            self.hash(&mut h).expect("v4 key hashing is infallible");
366
367            let mut digest = [0u8; 20];
368            let _ = h.digest(&mut digest);
369            Fingerprint::V4(digest)
370        }).clone()
371    }
372
373    /// Computes and returns the `Key`'s `Key ID`.
374    ///
375    /// See [Section 5.5.4 of RFC 9580].
376    ///
377    /// [Section 5.5.4 of RFC 9580]: https://www.rfc-editor.org/rfc/rfc9580.html#section-5.5.4
378    pub fn keyid(&self) -> KeyID {
379        self.fingerprint().into()
380    }
381
382    /// Creates an OpenPGP public key from the specified key material.
383    ///
384    /// This is an internal version for parse.rs that avoids going
385    /// through SystemTime.
386    pub(crate) fn make(creation_time: Timestamp,
387                       pk_algo: PublicKeyAlgorithm,
388                       mpis: mpi::PublicKey,
389                       secret: Option<SecretKeyMaterial>)
390                       -> Result<Self>
391    {
392        Ok(Key4 {
393            common: Default::default(),
394            creation_time,
395            pk_algo,
396            mpis,
397            secret,
398            fingerprint: Default::default(),
399            role: R::role(),
400            p: std::marker::PhantomData,
401            r: std::marker::PhantomData,
402        })
403    }
404
405    pub(crate) fn role(&self) -> KeyRoleRT {
406        self.role
407    }
408
409    pub(crate) fn set_role(&mut self, role: KeyRoleRT) {
410        self.role = role;
411    }
412}
413
414impl<R> Key4<key::PublicParts, R>
415    where R: key::KeyRole,
416{
417    /// Creates an OpenPGP public key from the specified key material.
418    pub fn new<T>(creation_time: T, pk_algo: PublicKeyAlgorithm,
419                  mpis: mpi::PublicKey)
420                  -> Result<Self>
421        where T: Into<time::SystemTime>
422    {
423        Ok(Key4 {
424            common: Default::default(),
425            creation_time: creation_time.into().try_into()?,
426            pk_algo,
427            mpis,
428            secret: None,
429            fingerprint: Default::default(),
430            role: R::role(),
431            p: std::marker::PhantomData,
432            r: std::marker::PhantomData,
433        })
434    }
435
436    /// Creates an OpenPGP public key packet from existing X25519 key
437    /// material.
438    ///
439    /// The ECDH key will use hash algorithm `hash` and symmetric
440    /// algorithm `sym`.  If one or both are `None` secure defaults
441    /// will be used.  The key will have its creation date set to
442    /// `ctime` or the current time if `None` is given.
443    pub fn import_public_cv25519<H, S, T>(public_key: &[u8],
444                                          hash: H, sym: S, ctime: T)
445        -> Result<Self> where H: Into<Option<HashAlgorithm>>,
446                              S: Into<Option<SymmetricAlgorithm>>,
447                              T: Into<Option<time::SystemTime>>
448    {
449        let mut point = Vec::from(public_key);
450        point.insert(0, 0x40);
451
452        use crate::crypto::ecdh;
453        Self::new(
454            ctime.into().unwrap_or_else(crate::now),
455            PublicKeyAlgorithm::ECDH,
456            mpi::PublicKey::ECDH {
457                curve: Curve::Cv25519,
458                hash: hash.into().unwrap_or_else(
459                    || ecdh::default_ecdh_kdf_hash(&Curve::Cv25519)),
460                sym: sym.into().unwrap_or_else(
461                    || ecdh::default_ecdh_kek_cipher(&Curve::Cv25519)),
462                q: mpi::MPI::new(&point),
463            })
464    }
465
466    /// Creates an OpenPGP public key packet from existing X25519 key
467    /// material.
468    ///
469    /// The key will have its creation date set to `ctime` or the
470    /// current time if `None` is given.
471    pub fn import_public_x25519<T>(public_key: &[u8], ctime: T)
472                                   -> Result<Self>
473    where
474        T: Into<Option<time::SystemTime>>,
475    {
476        Ok(Key4::new(ctime.into().unwrap_or_else(crate::now),
477                     PublicKeyAlgorithm::X25519,
478                     mpi::PublicKey::X25519 {
479                         u: public_key.try_into()?,
480                     })?)
481    }
482
483    /// Creates an OpenPGP public key packet from existing X448 key
484    /// material.
485    ///
486    /// The key will have its creation date set to `ctime` or the
487    /// current time if `None` is given.
488    pub fn import_public_x448<T>(public_key: &[u8], ctime: T)
489                                 -> Result<Self>
490    where
491        T: Into<Option<time::SystemTime>>,
492    {
493        Ok(Key4::new(ctime.into().unwrap_or_else(crate::now),
494                     PublicKeyAlgorithm::X448,
495                     mpi::PublicKey::X448 {
496                         u: Box::new(public_key.try_into()?),
497                     })?)
498    }
499
500    /// Creates an OpenPGP public key packet from existing Ed25519 key
501    /// material.
502    ///
503    /// The key will have its creation date set to `ctime` or the
504    /// current time if `None` is given.
505    pub fn import_public_ed25519<T>(public_key: &[u8], ctime: T) -> Result<Self>
506        where  T: Into<Option<time::SystemTime>>
507    {
508        let mut point = Vec::from(public_key);
509        point.insert(0, 0x40);
510
511        Self::new(
512            ctime.into().unwrap_or_else(crate::now),
513            PublicKeyAlgorithm::EdDSA,
514            mpi::PublicKey::EdDSA {
515                curve: Curve::Ed25519,
516                q: mpi::MPI::new(&point),
517            })
518    }
519
520    /// Creates an OpenPGP public key packet from existing Ed448 key
521    /// material.
522    ///
523    /// The key will have its creation date set to `ctime` or the
524    /// current time if `None` is given.
525    pub fn import_public_ed448<T>(public_key: &[u8], ctime: T) -> Result<Self>
526    where
527        T: Into<Option<time::SystemTime>>,
528    {
529        Ok(Key4::new(ctime.into().unwrap_or_else(crate::now),
530                     PublicKeyAlgorithm::Ed448,
531                     mpi::PublicKey::Ed448 {
532                         a: Box::new(public_key.try_into()?),
533                     })?)
534    }
535
536    /// Creates an OpenPGP public key packet from existing RSA key
537    /// material.
538    ///
539    /// The RSA key will use the public exponent `e` and the modulo
540    /// `n`. The key will have its creation date set to `ctime` or the
541    /// current time if `None` is given.
542    pub fn import_public_rsa<T>(e: &[u8], n: &[u8], ctime: T)
543        -> Result<Self> where T: Into<Option<time::SystemTime>>
544    {
545        Self::new(
546            ctime.into().unwrap_or_else(crate::now),
547            PublicKeyAlgorithm::RSAEncryptSign,
548            mpi::PublicKey::RSA {
549                e: mpi::MPI::new(e),
550                n: mpi::MPI::new(n),
551            })
552    }
553
554    /// Creates an OpenPGP public key packet from existing
555    /// ML-KEM768+X25519 key material.
556    ///
557    /// Note: in OpenPGP, ML-KEM keys are composite keys and include
558    /// an X25519 key to provide a pre-quantum security fallback.
559    ///
560    /// ML-KEM768 keys must be exactly 1184 bytes, and X25519 keys
561    /// must be exactly 32 bytes.
562    ///
563    /// The key will have its creation date set to `ctime` or the
564    /// current time if `None` is given.
565    pub fn import_public_mlkem768_x25519<T>(mlkem: &[u8], ecdh: &[u8], ctime: T)
566        -> Result<Self>
567    where
568        T: Into<Option<time::SystemTime>>
569    {
570        Ok(Key4::new(ctime.into().unwrap_or_else(crate::now),
571                     PublicKeyAlgorithm::MLKEM768_X25519,
572                     mpi::PublicKey::MLKEM768_X25519 {
573                         ecdh: Box::new(ecdh.try_into()?),
574                         mlkem: Box::new(mlkem.try_into()?),
575                     })?)
576    }
577}
578
579impl<R> Key4<SecretParts, R>
580    where R: key::KeyRole,
581{
582    /// Creates an OpenPGP key packet from the specified secret key
583    /// material.
584    pub fn with_secret<T>(creation_time: T, pk_algo: PublicKeyAlgorithm,
585                          mpis: mpi::PublicKey,
586                          secret: SecretKeyMaterial)
587                          -> Result<Self>
588        where T: Into<time::SystemTime>
589    {
590        Ok(Key4 {
591            common: Default::default(),
592            creation_time: creation_time.into().try_into()?,
593            pk_algo,
594            mpis,
595            secret: Some(secret),
596            fingerprint: Default::default(),
597            role: R::role(),
598            p: std::marker::PhantomData,
599            r: std::marker::PhantomData,
600        })
601    }
602
603    /// Creates a new OpenPGP secret key packet for an existing X25519 key.
604    ///
605    /// The ECDH key will use hash algorithm `hash` and symmetric
606    /// algorithm `sym`.  If one or both are `None` secure defaults
607    /// will be used.  The key will have its creation date set to
608    /// `ctime` or the current time if `None` is given.
609    ///
610    /// The given `private_key` is expected to be in the native X25519
611    /// representation, i.e. as opaque byte string of length 32.  It
612    /// is transformed into OpenPGP's representation during import.
613    pub fn import_secret_cv25519<H, S, T>(private_key: &[u8],
614                                          hash: H, sym: S, ctime: T)
615        -> Result<Self> where H: Into<Option<HashAlgorithm>>,
616                              S: Into<Option<SymmetricAlgorithm>>,
617                              T: Into<Option<std::time::SystemTime>>
618    {
619        use crate::crypto::backend::{Backend, interface::Asymmetric};
620
621        let mut private_key = Protected::from(private_key);
622        let public_key = Backend::x25519_derive_public(&private_key)?;
623
624        // Clamp the X25519 secret key scalar.
625        //
626        // X25519 does the clamping implicitly, but OpenPGP's ECDH
627        // over Curve25519 requires the secret to be clamped.  To
628        // increase compatibility with OpenPGP implementations that do
629        // not implicitly clamp the secrets before use, we do that
630        // before we store the secrets in OpenPGP data structures.
631        Backend::x25519_clamp_secret(&mut private_key);
632
633        // Reverse the scalar.
634        //
635        // X25519 stores the secret as opaque byte string representing
636        // a little-endian scalar.  OpenPGP's ECDH over Curve25519 on
637        // the other hand stores it as big-endian scalar, as was
638        // customary in OpenPGP.  See
639        // https://lists.gnupg.org/pipermail/gnupg-devel/2018-February/033437.html.
640        private_key.reverse();
641
642        use crate::crypto::ecdh;
643        Self::with_secret(
644            ctime.into().unwrap_or_else(crate::now),
645            PublicKeyAlgorithm::ECDH,
646            mpi::PublicKey::ECDH {
647                curve: Curve::Cv25519,
648                hash: hash.into().unwrap_or_else(
649                    || ecdh::default_ecdh_kdf_hash(&Curve::Cv25519)),
650                sym: sym.into().unwrap_or_else(
651                    || ecdh::default_ecdh_kek_cipher(&Curve::Cv25519)),
652                q: mpi::MPI::new_compressed_point(&public_key),
653            },
654            mpi::SecretKeyMaterial::ECDH {
655                scalar: private_key.into(),
656            }.into())
657    }
658
659    /// Creates a new OpenPGP secret key packet for an existing Ed25519 key.
660    ///
661    /// The key will have its creation date set to `ctime` or the current
662    /// time if `None` is given.
663    pub fn import_secret_ed25519<T>(private_key: &[u8], ctime: T)
664        -> Result<Self> where T: Into<Option<time::SystemTime>>
665    {
666        use crate::crypto::backend::{Backend, interface::Asymmetric};
667
668        let private_key = Protected::from(private_key);
669        let public_key = Backend::ed25519_derive_public(&private_key)?;
670
671        Self::with_secret(
672            ctime.into().unwrap_or_else(crate::now),
673            PublicKeyAlgorithm::EdDSA,
674            mpi::PublicKey::EdDSA {
675                curve: Curve::Ed25519,
676                q: mpi::MPI::new_compressed_point(&public_key),
677            },
678            mpi::SecretKeyMaterial::EdDSA {
679                scalar: private_key.into(),
680            }.into())
681    }
682
683    /// Generates a new ECC key over `curve`.
684    ///
685    /// If `for_signing` is false a ECDH key, if it's true either a
686    /// EdDSA or ECDSA key is generated.  Giving `for_signing == true` and
687    /// `curve == Cv25519` will produce an error. Likewise
688    /// `for_signing == false` and `curve == Ed25519` will produce an error.
689    pub fn generate_ecc(for_signing: bool, curve: Curve) -> Result<Self> {
690        use crate::crypto::backend::{Backend, interface::Asymmetric};
691
692        let (pk_algo, public, secret) = match (curve, for_signing) {
693            (Curve::Ed25519, true) => {
694                let (secret, public) = Backend::ed25519_generate_key()?;
695
696                (
697                    PublicKeyAlgorithm::EdDSA,
698                    mpi::PublicKey::EdDSA {
699                        curve: Curve::Ed25519,
700                        q: mpi::MPI::new_compressed_point(&public),
701                    },
702                    mpi::SecretKeyMaterial::EdDSA {
703                        scalar: secret.into(),
704                    },
705                )
706            },
707
708            (Curve::Cv25519, false) => {
709                let (mut secret, public) = Backend::x25519_generate_key()?;
710
711                // Clamp the X25519 secret key scalar.
712                //
713                // X25519 does the clamping implicitly, but OpenPGP's ECDH over
714                // Curve25519 requires the secret to be clamped.  To increase
715                // compatibility with OpenPGP implementations that do not
716                // implicitly clamp the secrets before use, we do that before we
717                // store the secrets in OpenPGP data structures.
718                Backend::x25519_clamp_secret(&mut secret);
719
720                // Reverse the scalar.
721                //
722                // X25519 stores the secret as opaque byte string
723                // representing a little-endian scalar.  OpenPGP's
724                // ECDH over Curve25519 on the other hand stores it as
725                // big-endian scalar, as was customary in OpenPGP.
726                // See
727                // https://lists.gnupg.org/pipermail/gnupg-devel/2018-February/033437.html.
728                secret.reverse();
729
730                (
731                    PublicKeyAlgorithm::ECDH,
732                    mpi::PublicKey::ECDH {
733                        curve: Curve::Cv25519,
734                        q: mpi::MPI::new_compressed_point(&public),
735                        hash: crate::crypto::ecdh::default_ecdh_kdf_hash(
736                            &Curve::Cv25519),
737                        sym: crate::crypto::ecdh::default_ecdh_kek_cipher(
738                            &Curve::Cv25519),
739                    },
740                    mpi::SecretKeyMaterial::ECDH {
741                        scalar: secret.into(),
742                    },
743                )
744            },
745
746            (curve, for_signing) =>
747                Self::generate_ecc_backend(for_signing, curve)?,
748        };
749
750        Self::with_secret(crate::now(), pk_algo, public, secret.into())
751    }
752
753    /// Generates a new DSA key with a public modulus of size `p_bits`.
754    ///
755    /// Note: In order to comply with FIPS 186-4, and to increase
756    /// compatibility with implementations, you SHOULD only generate
757    /// keys with moduli of size `2048` or `3072` bits.
758    pub fn generate_dsa(p_bits: usize) -> Result<Self> {
759        use crate::crypto::backend::{Backend, interface::Asymmetric};
760
761        let (p, q, g, y, x) = Backend::dsa_generate_key(p_bits)?;
762        let public_mpis = mpi::PublicKey::DSA { p, q, g, y };
763        let private_mpis = mpi::SecretKeyMaterial::DSA { x };
764
765        Self::with_secret(
766            crate::now(),
767            #[allow(deprecated)]
768            PublicKeyAlgorithm::DSA,
769            public_mpis,
770            private_mpis.into())
771    }
772
773    /// Generates a new ElGamal key with a public modulus of size `p_bits`.
774    ///
775    /// Note: ElGamal is no longer well-supported in cryptographic
776    /// libraries and should be avoided.
777    pub fn generate_elgamal(p_bits: usize) -> Result<Self> {
778        use crate::crypto::backend::{Backend, interface::Asymmetric};
779
780        let (p, g, y, x) = Backend::elgamal_generate_key(p_bits)?;
781        let public_mpis = mpi::PublicKey::ElGamal { p, g, y };
782        let private_mpis = mpi::SecretKeyMaterial::ElGamal { x };
783
784        Self::with_secret(
785            crate::now(),
786            #[allow(deprecated)]
787            PublicKeyAlgorithm::ElGamalEncrypt,
788            public_mpis,
789            private_mpis.into())
790    }
791
792    /// Generates a new X25519 key.
793    pub fn generate_x25519() -> Result<Self> {
794        use crate::crypto::backend::{Backend, interface::Asymmetric};
795
796        let (private, public) = Backend::x25519_generate_key()?;
797
798        Self::with_secret(
799            crate::now(),
800            PublicKeyAlgorithm::X25519,
801            mpi::PublicKey::X25519 {
802                u: public,
803            },
804            mpi::SecretKeyMaterial::X25519 {
805                x: private,
806            }.into())
807    }
808
809    /// Generates a new X448 key.
810    pub fn generate_x448() -> Result<Self> {
811        use crate::crypto::backend::{Backend, interface::Asymmetric};
812
813        let (private, public) = Backend::x448_generate_key()?;
814
815        Self::with_secret(
816            crate::now(),
817            PublicKeyAlgorithm::X448,
818            mpi::PublicKey::X448 {
819                u: Box::new(public),
820            },
821            mpi::SecretKeyMaterial::X448 {
822                x: private,
823            }.into())
824    }
825
826    /// Generates a new Ed25519 key.
827    pub fn generate_ed25519() -> Result<Self> {
828        use crate::crypto::backend::{Backend, interface::Asymmetric};
829
830        let (private, public) = Backend::ed25519_generate_key()?;
831
832        Self::with_secret(
833            crate::now(),
834            PublicKeyAlgorithm::Ed25519,
835            mpi::PublicKey::Ed25519 {
836                a: public,
837            },
838            mpi::SecretKeyMaterial::Ed25519 {
839                x: private,
840            }.into())
841    }
842
843    /// Generates a new Ed448 key.
844    pub fn generate_ed448() -> Result<Self> {
845        use crate::crypto::backend::{Backend, interface::Asymmetric};
846
847        let (private, public) = Backend::ed448_generate_key()?;
848
849        Self::with_secret(
850            crate::now(),
851            PublicKeyAlgorithm::Ed448,
852            mpi::PublicKey::Ed448 {
853                a: Box::new(public),
854            },
855            mpi::SecretKeyMaterial::Ed448 {
856                x: private,
857            }.into())
858    }
859
860
861    /// Generates a new MLKEM768+X25519 key.
862    pub fn generate_mlkem768_x25519() -> Result<Self> {
863        use crate::crypto::backend::{Backend, interface::Asymmetric};
864
865        let (ecdh_secret, ecdh_public) = Backend::x25519_generate_key()?;
866        let (mlkem_secret, mlkem_public) = Backend::mlkem768_generate_key()?;
867
868        Self::with_secret(
869            crate::now(),
870            PublicKeyAlgorithm::MLKEM768_X25519,
871            mpi::PublicKey::MLKEM768_X25519 {
872                ecdh: Box::new(ecdh_public),
873                mlkem: mlkem_public,
874            },
875            mpi::SecretKeyMaterial::MLKEM768_X25519 {
876                ecdh: ecdh_secret,
877                mlkem: mlkem_secret,
878            }.into())
879    }
880
881    /// Creates a new key pair from a secret `Key` with an unencrypted
882    /// secret key.
883    ///
884    /// # Errors
885    ///
886    /// Fails if the secret key is encrypted.  You can use
887    /// [`Key::decrypt_secret`] to decrypt a key.
888    pub fn into_keypair(self) -> Result<KeyPair> {
889        let (key, secret) = self.take_secret();
890        let secret = match secret {
891            SecretKeyMaterial::Unencrypted(secret) => secret,
892            SecretKeyMaterial::Encrypted(_) =>
893                return Err(Error::InvalidArgument(
894                    "secret key material is encrypted".into()).into()),
895        };
896
897        KeyPair::new(key.role_into_unspecified().into(), secret)
898    }
899}
900
901macro_rules! impl_common_secret_functions {
902    ($t: ident) => {
903        /// Secret key material handling.
904        impl<R> Key4<$t, R>
905            where R: key::KeyRole,
906        {
907            /// Takes the `Key`'s `SecretKeyMaterial`, if any.
908            pub fn take_secret(mut self)
909                               -> (Key4<PublicParts, R>, Option<SecretKeyMaterial>)
910            {
911                let old = std::mem::replace(&mut self.secret, None);
912                (self.parts_into_public(), old)
913            }
914
915            /// Adds the secret key material to the `Key`, returning
916            /// the old secret key material, if any.
917            pub fn add_secret(mut self, secret: SecretKeyMaterial)
918                              -> (Key4<SecretParts, R>, Option<SecretKeyMaterial>)
919            {
920                let old = std::mem::replace(&mut self.secret, Some(secret));
921                (self.parts_into_secret().expect("secret just set"), old)
922            }
923
924            /// Takes the `Key`'s `SecretKeyMaterial`, if any.
925            pub fn steal_secret(&mut self) -> Option<SecretKeyMaterial>
926            {
927                std::mem::replace(&mut self.secret, None)
928            }
929        }
930    }
931}
932impl_common_secret_functions!(PublicParts);
933impl_common_secret_functions!(UnspecifiedParts);
934
935/// Secret key handling.
936impl<R> Key4<SecretParts, R>
937    where R: key::KeyRole,
938{
939    /// Gets the `Key`'s `SecretKeyMaterial`.
940    pub fn secret(&self) -> &SecretKeyMaterial {
941        self.secret.as_ref().expect("has secret")
942    }
943
944    /// Gets a mutable reference to the `Key`'s `SecretKeyMaterial`.
945    pub fn secret_mut(&mut self) -> &mut SecretKeyMaterial {
946        self.secret.as_mut().expect("has secret")
947    }
948
949    /// Takes the `Key`'s `SecretKeyMaterial`.
950    pub fn take_secret(mut self)
951                       -> (Key4<PublicParts, R>, SecretKeyMaterial)
952    {
953        let old = std::mem::replace(&mut self.secret, None);
954        (self.parts_into_public(),
955         old.expect("Key<SecretParts, _> has a secret key material"))
956    }
957
958    /// Adds `SecretKeyMaterial` to the `Key`.
959    ///
960    /// This function returns the old secret key material, if any.
961    pub fn add_secret(mut self, secret: SecretKeyMaterial)
962                      -> (Key4<SecretParts, R>, SecretKeyMaterial)
963    {
964        let old = std::mem::replace(&mut self.secret, Some(secret));
965        (self.parts_into_secret().expect("secret just set"),
966         old.expect("Key<SecretParts, _> has a secret key material"))
967    }
968
969    /// Decrypts the secret key material using `password`.
970    ///
971    /// In OpenPGP, secret key material can be [protected with a
972    /// password].  The password is usually hardened using a [KDF].
973    ///
974    /// Refer to the documentation of [`Key::decrypt_secret`] for
975    /// details.
976    ///
977    /// This function returns an error if the secret key material is
978    /// not encrypted or the password is incorrect.
979    ///
980    /// [protected with a password]: https://www.rfc-editor.org/rfc/rfc9580.html#section-5.5.3
981    /// [KDF]: https://www.rfc-editor.org/rfc/rfc9580.html#section-3.7
982    /// [`Key::decrypt_secret`]: super::Key::decrypt_secret()
983    pub fn decrypt_secret(self, password: &Password) -> Result<Self> {
984        let (key, mut secret) = self.take_secret();
985        let key = Key::V4(key);
986        secret.decrypt_in_place(&key, password)?;
987        let key = if let Key::V4(k) = key { k } else { unreachable!() };
988        Ok(key.add_secret(secret).0)
989    }
990
991    /// Encrypts the secret key material using `password`.
992    ///
993    /// In OpenPGP, secret key material can be [protected with a
994    /// password].  The password is usually hardened using a [KDF].
995    ///
996    /// Refer to the documentation of [`Key::encrypt_secret`] for
997    /// details.
998    ///
999    /// This returns an error if the secret key material is already
1000    /// encrypted.
1001    ///
1002    /// [protected with a password]: https://www.rfc-editor.org/rfc/rfc9580.html#section-5.5.3
1003    /// [KDF]: https://www.rfc-editor.org/rfc/rfc9580.html#section-3.7
1004    /// [`Key::encrypt_secret`]: super::Key::encrypt_secret()
1005    pub fn encrypt_secret(self, password: &Password)
1006        -> Result<Key4<SecretParts, R>>
1007    {
1008        let (key, mut secret) = self.take_secret();
1009        let key = Key::V4(key);
1010        secret.encrypt_in_place(&key, password)?;
1011        let key = if let Key::V4(k) = key { k } else { unreachable!() };
1012        Ok(key.add_secret(secret).0)
1013    }
1014}
1015
1016impl<P, R> From<Key4<P, R>> for super::Key<P, R>
1017    where P: key::KeyParts,
1018          R: key::KeyRole,
1019{
1020    fn from(p: Key4<P, R>) -> Self {
1021        super::Key::V4(p)
1022    }
1023}
1024
1025#[cfg(test)]
1026use crate::packet::key::{
1027    PrimaryRole,
1028    SubordinateRole,
1029    UnspecifiedRole,
1030};
1031
1032#[cfg(test)]
1033impl Arbitrary for Key4<PublicParts, PrimaryRole> {
1034    fn arbitrary(g: &mut Gen) -> Self {
1035        Key4::<PublicParts, UnspecifiedRole>::arbitrary(g).into()
1036    }
1037}
1038
1039#[cfg(test)]
1040impl Arbitrary for Key4<PublicParts, SubordinateRole> {
1041    fn arbitrary(g: &mut Gen) -> Self {
1042        Key4::<PublicParts, UnspecifiedRole>::arbitrary(g).into()
1043    }
1044}
1045
1046#[cfg(test)]
1047impl Arbitrary for Key4<PublicParts, UnspecifiedRole> {
1048    fn arbitrary(g: &mut Gen) -> Self {
1049        let mpis = mpi::PublicKey::arbitrary(g);
1050        Key4 {
1051            common: Arbitrary::arbitrary(g),
1052            creation_time: Arbitrary::arbitrary(g),
1053            pk_algo: mpis.algo()
1054                .expect("mpi::PublicKey::arbitrary only uses known algos"),
1055            mpis,
1056            secret: None,
1057            fingerprint: Default::default(),
1058            role: UnspecifiedRole::role(),
1059            p: std::marker::PhantomData,
1060            r: std::marker::PhantomData,
1061        }
1062    }
1063}
1064
1065#[cfg(test)]
1066impl Arbitrary for Key4<SecretParts, PrimaryRole> {
1067    fn arbitrary(g: &mut Gen) -> Self {
1068        Key4::<SecretParts, PrimaryRole>::arbitrary_secret_key(g)
1069    }
1070}
1071
1072#[cfg(test)]
1073impl Arbitrary for Key4<SecretParts, SubordinateRole> {
1074    fn arbitrary(g: &mut Gen) -> Self {
1075        Key4::<SecretParts, SubordinateRole>::arbitrary_secret_key(g)
1076    }
1077}
1078
1079#[cfg(test)]
1080impl<R> Key4<SecretParts, R>
1081where
1082    R: KeyRole,
1083    Key4::<PublicParts, R>: Arbitrary,
1084{
1085    fn arbitrary_secret_key(g: &mut Gen) -> Self {
1086        let key = Key::V4(Key4::<PublicParts, R>::arbitrary(g));
1087        let mut secret: SecretKeyMaterial =
1088            mpi::SecretKeyMaterial::arbitrary_for(g, key.pk_algo())
1089            .expect("only known algos used")
1090            .into();
1091
1092        if <bool>::arbitrary(g) {
1093            secret.encrypt_in_place(&key, &Password::from(Vec::arbitrary(g)))
1094                .unwrap();
1095        }
1096
1097        let key = if let Key::V4(k) = key { k } else { unreachable!() };
1098        Key4::<PublicParts, R>::add_secret(key, secret).0
1099    }
1100}
1101
1102#[cfg(test)]
1103mod tests {
1104    use std::time::Duration;
1105    use std::time::UNIX_EPOCH;
1106
1107    use crate::crypto::S2K;
1108    use crate::packet::Key;
1109    use crate::Cert;
1110    use crate::packet::pkesk::PKESK3;
1111    use crate::packet::key;
1112    use crate::packet::key::SecretKeyMaterial;
1113    use crate::packet::Packet;
1114    use super::*;
1115    use crate::PacketPile;
1116    use crate::serialize::Serialize;
1117    use crate::parse::Parse;
1118
1119    #[test]
1120    fn encrypted_rsa_key() {
1121        let cert = Cert::from_bytes(
1122            crate::tests::key("testy-new-encrypted-with-123.pgp")).unwrap();
1123        let key = cert.primary_key().key().clone();
1124        let (key, secret) = key.take_secret();
1125        let mut secret = secret.unwrap();
1126
1127        assert!(secret.is_encrypted());
1128        secret.decrypt_in_place(&key, &"123".into()).unwrap();
1129        assert!(!secret.is_encrypted());
1130        let (pair, _) = key.add_secret(secret);
1131        assert!(pair.has_unencrypted_secret());
1132
1133        match pair.secret() {
1134            SecretKeyMaterial::Unencrypted(ref u) => u.map(|mpis| match mpis {
1135                mpi::SecretKeyMaterial::RSA { .. } => (),
1136                _ => panic!(),
1137            }),
1138            _ => panic!(),
1139        }
1140    }
1141
1142    #[test]
1143    fn primary_key_encrypt_decrypt() -> Result<()> {
1144        key_encrypt_decrypt::<PrimaryRole>()
1145    }
1146
1147    #[test]
1148    fn subkey_encrypt_decrypt() -> Result<()> {
1149        key_encrypt_decrypt::<SubordinateRole>()
1150    }
1151
1152    fn key_encrypt_decrypt<R>() -> Result<()>
1153    where
1154        R: KeyRole + PartialEq,
1155    {
1156        let mut g = quickcheck::Gen::new(256);
1157        let p: Password = Vec::<u8>::arbitrary(&mut g).into();
1158
1159        let check = |key: Key4<SecretParts, R>| -> Result<()> {
1160            let key: Key<_, _> = key.into();
1161            let encrypted = key.clone().encrypt_secret(&p)?;
1162            let decrypted = encrypted.decrypt_secret(&p)?;
1163            assert_eq!(key, decrypted);
1164            Ok(())
1165        };
1166
1167        use crate::types::Curve::*;
1168        for curve in vec![NistP256, NistP384, NistP521, Ed25519] {
1169            if ! curve.is_supported() {
1170                eprintln!("Skipping unsupported {}", curve);
1171                continue;
1172            }
1173
1174            let key: Key4<_, R>
1175                = Key4::generate_ecc(true, curve.clone())?;
1176            check(key)?;
1177        }
1178
1179        for bits in vec![2048, 3072] {
1180            if ! PublicKeyAlgorithm::RSAEncryptSign.is_supported() {
1181                eprintln!("Skipping unsupported RSA");
1182                continue;
1183            }
1184
1185            let key: Key4<_, R>
1186                = Key4::generate_rsa(bits)?;
1187            check(key)?;
1188        }
1189
1190        Ok(())
1191    }
1192
1193    #[test]
1194    fn eq() {
1195        use crate::types::Curve::*;
1196
1197        for curve in vec![NistP256, NistP384, NistP521] {
1198            if ! curve.is_supported() {
1199                eprintln!("Skipping unsupported {}", curve);
1200                continue;
1201            }
1202
1203            let sign_key : Key4<_, key::UnspecifiedRole>
1204                = Key4::generate_ecc(true, curve.clone()).unwrap();
1205            let enc_key : Key4<_, key::UnspecifiedRole>
1206                = Key4::generate_ecc(false, curve).unwrap();
1207            let sign_clone = sign_key.clone();
1208            let enc_clone = enc_key.clone();
1209
1210            assert_eq!(sign_key, sign_clone);
1211            assert_eq!(enc_key, enc_clone);
1212        }
1213
1214        for bits in vec![1024, 2048, 3072, 4096] {
1215            if ! PublicKeyAlgorithm::RSAEncryptSign.is_supported() {
1216                eprintln!("Skipping unsupported RSA");
1217                continue;
1218            }
1219
1220            let key : Key4<_, key::UnspecifiedRole>
1221                = Key4::generate_rsa(bits).unwrap();
1222            let clone = key.clone();
1223            assert_eq!(key, clone);
1224        }
1225    }
1226
1227    #[test]
1228    fn generate_roundtrip() {
1229        use crate::types::Curve::*;
1230
1231        let keys = vec![NistP256, NistP384, NistP521].into_iter().flat_map(|cv|
1232        {
1233            if ! cv.is_supported() {
1234                eprintln!("Skipping unsupported {}", cv);
1235                return Vec::new();
1236            }
1237
1238            let sign_key : Key4<key::SecretParts, key::PrimaryRole>
1239                = Key4::generate_ecc(true, cv.clone()).unwrap();
1240            let enc_key = Key4::generate_ecc(false, cv).unwrap();
1241
1242            vec![sign_key, enc_key]
1243        }).chain(vec![1024, 2048, 3072, 4096].into_iter().filter_map(|b| {
1244            Key4::generate_rsa(b).ok()
1245        }));
1246
1247        for key in keys {
1248            let mut b = Vec::new();
1249            Packet::SecretKey(key.clone().into()).serialize(&mut b).unwrap();
1250
1251            let pp = PacketPile::from_bytes(&b).unwrap();
1252            if let Some(Packet::SecretKey(Key::V4(ref parsed_key))) =
1253                pp.path_ref(&[0])
1254            {
1255                assert_eq!(key.creation_time(), parsed_key.creation_time());
1256                assert_eq!(key.pk_algo(), parsed_key.pk_algo());
1257                assert_eq!(key.mpis(), parsed_key.mpis());
1258                assert_eq!(key.secret(), parsed_key.secret());
1259
1260                assert_eq!(&key, parsed_key);
1261            } else {
1262                panic!("bad packet: {:?}", pp.path_ref(&[0]));
1263            }
1264
1265            let mut b = Vec::new();
1266            let pk4 : Key4<PublicParts, PrimaryRole> = key.clone().into();
1267            Packet::PublicKey(pk4.into()).serialize(&mut b).unwrap();
1268
1269            let pp = PacketPile::from_bytes(&b).unwrap();
1270            if let Some(Packet::PublicKey(Key::V4(ref parsed_key))) =
1271                pp.path_ref(&[0])
1272            {
1273                assert!(! parsed_key.has_secret());
1274
1275                let key = key.take_secret().0;
1276                assert_eq!(&key, parsed_key);
1277            } else {
1278                panic!("bad packet: {:?}", pp.path_ref(&[0]));
1279            }
1280        }
1281    }
1282
1283    #[test]
1284    fn encryption_roundtrip() {
1285        use crate::crypto::SessionKey;
1286        use crate::types::Curve::*;
1287
1288        let keys = vec![NistP256, NistP384, NistP521].into_iter()
1289            .filter_map(|cv| {
1290                Key4::generate_ecc(false, cv).ok()
1291            }).chain(vec![1024, 2048, 3072, 4096].into_iter().filter_map(|b| {
1292                Key4::generate_rsa(b).ok()
1293            })).chain(vec![1024, 2048, 3072, 4096].into_iter().filter_map(|b| {
1294                Key4::generate_elgamal(b).ok()
1295            })).chain(
1296                Key4::generate_mlkem768_x25519().ok()
1297            );
1298
1299        for key in keys.into_iter() {
1300            let key: Key<key::SecretParts, key::UnspecifiedRole> = key.into();
1301            let mut keypair = key.clone().into_keypair().unwrap();
1302            let cipher = SymmetricAlgorithm::AES256;
1303            let sk = SessionKey::new(cipher.key_size().unwrap()).unwrap();
1304
1305            let pkesk = PKESK3::for_recipient(cipher, &sk, &key).unwrap();
1306            let (cipher_, sk_) = pkesk.decrypt(&mut keypair, None)
1307                .expect("keypair should be able to decrypt PKESK");
1308
1309            assert_eq!(cipher, cipher_);
1310            assert_eq!(sk, sk_);
1311
1312            let (cipher_, sk_) =
1313                pkesk.decrypt(&mut keypair, Some(cipher)).unwrap();
1314
1315            assert_eq!(cipher, cipher_);
1316            assert_eq!(sk, sk_);
1317        }
1318    }
1319
1320    #[test]
1321    fn secret_encryption_roundtrip() {
1322        use crate::types::Curve::*;
1323        use crate::types::SymmetricAlgorithm::*;
1324        use crate::types::AEADAlgorithm::*;
1325
1326        let keys = vec![NistP256, NistP384, NistP521].into_iter()
1327            .filter_map(|cv| -> Option<Key<key::SecretParts, key::PrimaryRole>> {
1328                Key4::generate_ecc(false, cv).map(Into::into).ok()
1329            }).chain(vec![1024, 2048, 3072, 4096].into_iter().filter_map(|b| {
1330                Key4::generate_rsa(b).map(Into::into).ok()
1331            }));
1332
1333        for key in keys {
1334          for (symm, aead) in [(AES128, None),
1335                               (AES128, Some(OCB)),
1336                               (AES256, Some(EAX))] {
1337            if ! aead.map(|a| a.is_supported()).unwrap_or(true) {
1338                continue;
1339            }
1340            assert!(! key.secret().is_encrypted());
1341
1342            let password = Password::from("foobarbaz");
1343            let mut encrypted_key = key.clone();
1344
1345            encrypted_key.secret_mut()
1346                .encrypt_in_place_with(&key, S2K::default(), symm, aead,
1347                                       &password).unwrap();
1348            assert!(encrypted_key.secret().is_encrypted());
1349
1350            encrypted_key.secret_mut()
1351                .decrypt_in_place(&key, &password).unwrap();
1352            assert!(! key.secret().is_encrypted());
1353            assert_eq!(key, encrypted_key);
1354            assert_eq!(key.secret(), encrypted_key.secret());
1355          }
1356        }
1357    }
1358
1359    #[test]
1360    fn import_cv25519() {
1361        use crate::crypto::{ecdh, mem, SessionKey};
1362        use self::mpi::{MPI, Ciphertext};
1363
1364        // X25519 key
1365        let ctime =
1366            time::UNIX_EPOCH + time::Duration::new(0x5c487129, 0);
1367        let public = b"\xed\x59\x0a\x15\x08\x95\xe9\x92\xd2\x2c\x14\x01\xb3\xe9\x3b\x7f\xff\xe6\x6f\x22\x65\xec\x69\xd9\xb8\xda\x24\x2c\x64\x84\x44\x11";
1368        let key : Key<_, key::UnspecifiedRole>
1369            = Key4::import_public_cv25519(&public[..],
1370                                          HashAlgorithm::SHA256,
1371                                          SymmetricAlgorithm::AES128,
1372                                          ctime).unwrap().into();
1373
1374        // PKESK
1375        let eph_pubkey = MPI::new(&b"\x40\xda\x1c\x69\xc4\xe3\xb6\x9c\x6e\xd4\xc6\x69\x6c\x89\xc7\x09\xe9\xf8\x6a\xf1\xe3\x8d\xb6\xaa\xb5\xf7\x29\xae\xa6\xe7\xdd\xfe\x38"[..]);
1376        let ciphertext = Ciphertext::ECDH{
1377            e: eph_pubkey.clone(),
1378            key: Vec::from(&b"\x45\x8b\xd8\x4d\x88\xb3\xd2\x16\xb6\xc2\x3b\x99\x33\xd1\x23\x4b\x10\x15\x8e\x04\x16\xc5\x7c\x94\x88\xf6\x63\xf2\x68\x37\x08\x66\xfd\x5a\x7b\x40\x58\x21\x6b\x2c\xc0\xf4\xdc\x91\xd3\x48\xed\xc1"[..]).into_boxed_slice()
1379        };
1380        let shared_sec: mem::Protected = b"\x44\x0C\x99\x27\xF7\xD6\x1E\xAD\xD1\x1E\x9E\xC8\x22\x2C\x5D\x43\xCE\xB0\xE5\x45\x94\xEC\xAF\x67\xD9\x35\x1D\xA1\xA3\xA8\x10\x0B"[..].into();
1381
1382        // Session key
1383        let dek = b"\x09\x0D\xDC\x40\xC5\x71\x51\x88\xAC\xBD\x45\x56\xD4\x2A\xDF\x77\xCD\xF4\x82\xA2\x1B\x8F\x2E\x48\x3B\xCA\xBF\xD3\xE8\x6D\x0A\x7C\xDF\x10\xe6";
1384        let sk = SessionKey::from(Vec::from(&dek[..]));
1385
1386        // Expected
1387        let got_enc = ecdh::encrypt_wrap(&key.parts_into_public().role_into_subordinate(),
1388                                           &sk, eph_pubkey, &shared_sec)
1389            .unwrap();
1390
1391        assert_eq!(ciphertext, got_enc);
1392    }
1393
1394    #[test]
1395    fn import_cv25519_sec() -> Result<()> {
1396        use self::mpi::{MPI, Ciphertext};
1397
1398        // X25519 key
1399        let ctime =
1400            time::UNIX_EPOCH + time::Duration::new(0x5c487129, 0);
1401        let public = b"\xed\x59\x0a\x15\x08\x95\xe9\x92\xd2\x2c\x14\x01\xb3\xe9\x3b\x7f\xff\xe6\x6f\x22\x65\xec\x69\xd9\xb8\xda\x24\x2c\x64\x84\x44\x11";
1402        let secret = b"\xa0\x27\x13\x99\xc9\xe3\x2e\xd2\x47\xf6\xd6\x63\x9d\xe6\xec\xcb\x57\x0b\x92\xbb\x17\xfe\xb8\xf1\xc4\x1f\x06\x7c\x55\xfc\xdd\x58";
1403        let key: Key<_, UnspecifiedRole>
1404            = Key4::import_secret_cv25519(&secret[..],
1405                                          HashAlgorithm::SHA256,
1406                                          SymmetricAlgorithm::AES128,
1407                                          ctime).unwrap().into();
1408        match key.mpis() {
1409            self::mpi::PublicKey::ECDH{ ref q,.. } =>
1410                assert_eq!(&q.value()[1..], &public[..]),
1411            _ => unreachable!(),
1412        }
1413
1414        // PKESK
1415        let eph_pubkey: &[u8; 33] = b"\x40\xda\x1c\x69\xc4\xe3\xb6\x9c\x6e\xd4\xc6\x69\x6c\x89\xc7\x09\xe9\xf8\x6a\xf1\xe3\x8d\xb6\xaa\xb5\xf7\x29\xae\xa6\xe7\xdd\xfe\x38";
1416        let ciphertext = Ciphertext::ECDH{
1417            e: MPI::new(&eph_pubkey[..]),
1418            key: Vec::from(&b"\x45\x8b\xd8\x4d\x88\xb3\xd2\x16\xb6\xc2\x3b\x99\x33\xd1\x23\x4b\x10\x15\x8e\x04\x16\xc5\x7c\x94\x88\xf6\x63\xf2\x68\x37\x08\x66\xfd\x5a\x7b\x40\x58\x21\x6b\x2c\xc0\xf4\xdc\x91\xd3\x48\xed\xc1"[..]).into_boxed_slice()
1419        };
1420        let pkesk =
1421            PKESK3::new(None, PublicKeyAlgorithm::ECDH, ciphertext)?;
1422
1423        // Session key
1424        let dek = b"\x0D\xDC\x40\xC5\x71\x51\x88\xAC\xBD\x45\x56\xD4\x2A\xDF\x77\xCD\xF4\x82\xA2\x1B\x8F\x2E\x48\x3B\xCA\xBF\xD3\xE8\x6D\x0A\x7C\xDF";
1425
1426        let key = key.parts_into_secret().unwrap();
1427        let mut keypair = key.into_keypair()?;
1428        let (sym, got_dek) = pkesk.decrypt(&mut keypair, None).unwrap();
1429
1430        assert_eq!(sym, SymmetricAlgorithm::AES256);
1431        assert_eq!(&dek[..], &got_dek[..]);
1432        Ok(())
1433    }
1434
1435    #[test]
1436    fn import_rsa() -> Result<()> {
1437        use crate::crypto::SessionKey;
1438        use self::mpi::{MPI, Ciphertext};
1439
1440        // RSA key
1441        let ctime =
1442            time::UNIX_EPOCH + time::Duration::new(1548950502, 0);
1443        let d = b"\x14\xC4\x3A\x0C\x3A\x79\xA4\xF7\x63\x0D\x89\x93\x63\x8B\x56\x9C\x29\x2E\xCD\xCF\xBF\xB0\xEC\x66\x52\xC3\x70\x1B\x19\x21\x73\xDE\x8B\xAC\x0E\xF2\xE1\x28\x42\x66\x56\x55\x00\x3B\xFD\x50\xC4\x7C\xBC\x9D\xEB\x7D\xF4\x81\xFC\xC3\xBF\xF7\xFF\xD0\x41\x3E\x50\x3B\x5F\x5D\x5F\x56\x67\x5E\x00\xCE\xA4\x53\xB8\x59\xA0\x40\xC8\x96\x6D\x12\x09\x27\xBE\x1D\xF1\xC2\x68\xFC\xF0\x14\xD6\x52\x77\x07\xC8\x12\x36\x9C\x9A\x5C\xAF\x43\xCC\x95\x20\xBB\x0A\x44\x94\xDD\xB4\x4F\x45\x4E\x3A\x1A\x30\x0D\x66\x40\xAC\x68\xE8\xB0\xFD\xCD\x6C\x6B\x6C\xB5\xF7\xE4\x36\x95\xC2\x96\x98\xFD\xCA\x39\x6C\x1A\x2E\x55\xAD\xB6\xE0\xF8\x2C\xFF\xBC\xD3\x32\x15\x52\x39\xB3\x92\x35\xDB\x8B\x68\xAF\x2D\x4A\x6E\x64\xB8\x28\x63\xC4\x24\x94\x2D\xA9\xDB\x93\x56\xE3\xBC\xD0\xB6\x38\x84\x04\xA4\xC6\x18\x48\xFE\xB2\xF8\xE1\x60\x37\x52\x96\x41\xA5\x79\xF6\x3D\xB7\x2A\x71\x5B\x7A\x75\xBF\x7F\xA2\x5A\xC8\xA1\x38\xF2\x5A\xBD\x14\xFC\xAF\xB4\x54\x83\xA4\xBD\x49\xA2\x8B\x91\xB0\xE0\x4A\x1B\x21\x54\x07\x19\x70\x64\x7C\x3E\x9F\x8D\x8B\xE4\x70\xD1\xE7\xBE\x4E\x5C\xCE\xF1";
1444        let p = b"\xC8\x32\xD1\x17\x41\x4D\x8F\x37\x09\x18\x32\x4C\x4C\xF4\xA2\x15\x27\x43\x3D\xBB\xB5\xF6\x1F\xCF\xD2\xE4\x43\x61\x07\x0E\x9E\x35\x1F\x0A\x5D\xFB\x3A\x45\x74\x61\x73\x73\x7B\x5F\x1F\x87\xFB\x54\x8D\xA8\x85\x3E\xB0\xB7\xC7\xF5\xC9\x13\x99\x8D\x40\xE6\xA6\xD0\x71\x3A\xE3\x2D\x4A\xC3\xA3\xFF\xF7\x72\x82\x14\x52\xA4\xBA\x63\x0E\x17\xCA\xCA\x18\xC4\x3A\x40\x79\xF1\x86\xB3\x10\x4B\x9F\xB2\xAE\x2E\x13\x38\x8D\x2C\xF9\x88\x4C\x25\x53\xEF\xF9\xD1\x8B\x1A\x7C\xE7\xF6\x4B\x73\x51\x31\xFA\x44\x1D\x36\x65\x71\xDA\xFC\x6F";
1445        let q = b"\xCC\x30\xE9\xCC\xCB\x31\x28\xB5\x90\xFF\x06\x62\x42\x5B\x24\x0E\x00\xFE\xE2\x37\xC4\xAC\xBB\x3B\x8F\xF2\x0E\x3F\x78\xCF\x6B\x7C\xE8\x75\x57\x7C\x15\x9D\x1A\x66\xF2\x0A\xE5\xD3\x0B\xE7\x40\xF7\xE7\x00\xB6\x86\xB5\xD9\x20\x67\xE0\x4A\xC0\x90\xA4\x13\x4D\xC9\xB0\x12\xC5\xCD\x4C\xEB\xA1\x91\x2D\x43\x58\x6E\xB6\x75\xA0\x93\xF0\x5B\xC5\x31\xCA\xB7\xC6\x22\x0C\xD3\xEC\x84\xC5\x91\xA1\x5F\x2C\x8E\x07\x5D\xA1\x98\x67\xC5\x7A\x58\x16\x71\x3D\xED\x91\x03\x0D\xD4\x25\x07\x89\x9B\x33\x98\xA3\x70\xD9\xE7\xC8\x17\xA3\xD9";
1446
1447        let reference_key = Packet::from_bytes(b"\
1448-----BEGIN PGP PRIVATE KEY BLOCK-----
1449
1450xcLYBFxTG+YBCACfrr78JBmS/7rxsQg7y1IialuUqqbXmpMXz8mmd/tYKB1kymnK
1451kciCvYJ3CKq/3c3AlTlV7x4qKcXIL5XSuONdq9xHHpFyxjMJLAYMNn+PR6BgyLJG
1452J9MThBxELQGw7MEL+/7iFT6N92eu8PTyUnQwdDXA6JV5M49fbYCiG/2sCXSyVtJJ
1453DcQWkWQSZasC82PmFX4C/5QqunZ6nXRLkx79ErHwCzqO9GqY7rgPErmV0Hd2LXUt
1454AesCmSBFiR3Ole1MwNwp67hzQmFILqoBRKmJoEOfhjOiTCMET4SP7IE2pcpGKJyP
1455yJHwlfsG8SKTXBOsu9NUizX4HvSZ4ohXU6cXABEBAAEAB/0UxDoMOnmk92MNiZNj
1456i1acKS7Nz7+w7GZSw3AbGSFz3ousDvLhKEJmVlUAO/1QxHy8net99IH8w7/3/9BB
1457PlA7X11fVmdeAM6kU7hZoEDIlm0SCSe+HfHCaPzwFNZSdwfIEjacmlyvQ8yVILsK
1458RJTdtE9FTjoaMA1mQKxo6LD9zWxrbLX35DaVwpaY/co5bBouVa224Pgs/7zTMhVS
1459ObOSNduLaK8tSm5kuChjxCSULanbk1bjvNC2OIQEpMYYSP6y+OFgN1KWQaV59j23
1460KnFbenW/f6JayKE48lq9FPyvtFSDpL1JoouRsOBKGyFUBxlwZHw+n42L5HDR575O
1461XM7xBADIMtEXQU2PNwkYMkxM9KIVJ0M9u7X2H8/S5ENhBw6eNR8KXfs6RXRhc3N7
1462Xx+H+1SNqIU+sLfH9ckTmY1A5qbQcTrjLUrDo//3coIUUqS6Yw4XysoYxDpAefGG
1463sxBLn7KuLhM4jSz5iEwlU+/50YsafOf2S3NRMfpEHTZlcdr8bwQAzDDpzMsxKLWQ
1464/wZiQlskDgD+4jfErLs7j/IOP3jPa3zodVd8FZ0aZvIK5dML50D35wC2hrXZIGfg
1465SsCQpBNNybASxc1M66GRLUNYbrZ1oJPwW8UxyrfGIgzT7ITFkaFfLI4HXaGYZ8V6
1466WBZxPe2RAw3UJQeJmzOYo3DZ58gXo9kD/jLU2VpxpU/3BKrRO5AyvfMUKWlKXleT
1467pogdwcu0hHYntKr4mce7tBlRQRhtUv4dzRQ8OJ75oyvtl9mNfWaIOB/Jv5UOxeXh
1468jh20P23NClrtoM+5lYiaLEx0ZfD8xq85AKqrhMwcw4jH0lhJebTYOEeKrfD6SPbL
1469bzBv85X5WCw7RQ8=
1470=hd62
1471-----END PGP PRIVATE KEY BLOCK-----
1472")?;
1473
1474        // PKESK
1475        let c = b"\x8A\x1A\xD4\x82\x91\x6B\xBF\xA1\x65\xD3\x82\x8C\x97\xAB\xD0\x91\xE4\xB4\xC4\x9D\x08\xD8\x8B\xB7\xE6\x13\x3F\x6F\x52\x14\xED\xC4\x77\xB7\x31\x00\xC1\x43\xF9\x62\x53\xBF\x21\x21\x52\x74\x35\xD8\xC7\xA2\x11\x89\xA5\xD5\x21\x98\x6D\x3C\x9F\xF0\xED\xDB\xD7\x0F\xAC\x3C\x15\x25\x34\x52\xC7\x7C\x82\x07\x5A\x99\xC1\xC6\xF6\xF2\x6D\x46\xC8\x56\x59\xE7\xC6\x34\x0C\xCA\x37\x70\xB4\x97\xDA\x18\x14\xC4\x03\x0A\xCB\xE5\x0C\x41\x43\x61\xBA\x32\xB6\x9A\xF3\xDF\x0C\xB0\xCE\xBD\xFE\x72\x6C\xCC\xC1\xE8\xF0\x05\x97\x61\xEA\x30\x10\xB9\x43\xC4\x9A\x41\xED\x72\x27\xA4\xD5\xE7\x08\x41\x6C\x57\x80\xF3\x64\xF0\x45\x70\x27\x36\xBD\x64\x59\x74\xCF\xCD\x39\xE6\xEB\x7C\x62\xC8\x38\x23\xF8\x4C\xB7\x30\x9F\xF1\x40\x4A\xE9\x72\x66\x99\xF7\x2A\x47\x1C\xE7\x12\x20\x58\xBA\x87\x00\xB8\xFC\x54\xBC\xA5\x1D\x7D\x8B\x50\xA4\x4B\xB3\xD7\x44\xC7\x68\x5E\x2D\xBB\xE9\x6E\xC4\xD0\x31\xB0\xD0\xB6\x02\xD1\x74\x6B\xC9\x3D\x19\x32\x3B\xF1\x0E\x74\xF6\x12\x13\xE6\x40\x8F\xA6\x97\xAD\x83\xB0\x84\xD6\xD9\xE5\x25\x8E\x57\x0B\x7A\x7B\xD0\x5C\x29\x96\xED\x29\xED";
1476        let ciphertext = Ciphertext::RSA{
1477            c: MPI::new(&c[..]),
1478        };
1479        let pkesk = PKESK3::new(None,
1480                                PublicKeyAlgorithm::RSAEncryptSign,
1481                                ciphertext).unwrap();
1482
1483        // Session key
1484        let dek = b"\xA5\x58\x3A\x04\x35\x8B\xC7\x3F\x4A\xEF\x0C\x5A\xEB\xED\x59\xCA\xFD\x96\xB5\x32\x23\x26\x0C\x91\x78\xD1\x31\x12\xF0\x41\x42\x9D";
1485        let sk = SessionKey::from(Vec::from(&dek[..]));
1486
1487        let test = |d: &[u8], p: &[u8], q: &[u8]| -> Result<()> {
1488            let key: key::SecretKey
1489                = Key4::import_secret_rsa(d, p, q, ctime)?.into();
1490            assert_eq!(Packet::from(key.clone()), reference_key);
1491            let mut decryptor = key.into_keypair()?;
1492            let got_sk = pkesk.decrypt(&mut decryptor, None).unwrap();
1493            assert_eq!(got_sk.1, sk);
1494            Ok(())
1495        };
1496
1497        test(d, p, q)?;
1498        test(d, q, p)?;
1499        Ok(())
1500    }
1501
1502    #[test]
1503    fn import_ed25519() {
1504        use crate::types::SignatureType;
1505        use crate::packet::signature::Signature4;
1506        use crate::packet::signature::subpacket::{
1507            Subpacket, SubpacketValue, SubpacketArea};
1508
1509        // Ed25519 key
1510        let ctime =
1511            time::UNIX_EPOCH + time::Duration::new(1548249630, 0);
1512        let q = b"\x57\x15\x45\x1B\x68\xA5\x13\xA2\x20\x0F\x71\x9D\xE3\x05\x3B\xED\xA2\x21\xDE\x61\x5A\xF5\x67\x45\xBB\x97\x99\x43\x53\x59\x7C\x3F";
1513        let key: key::PublicKey
1514            = Key4::import_public_ed25519(q, ctime).unwrap().into();
1515
1516        let mut hashed = SubpacketArea::default();
1517        let mut unhashed = SubpacketArea::default();
1518        let fpr = "D81A 5DC0 DEBF EE5F 9AC8  20EB 6769 5DB9 920D 4FAC"
1519            .parse().unwrap();
1520        let kid = "6769 5DB9 920D 4FAC".parse().unwrap();
1521        let ctime = 1549460479.into();
1522        let r = b"\x5A\xF9\xC7\x42\x70\x24\x73\xFF\x7F\x27\xF9\x20\x9D\x20\x0F\xE3\x8F\x71\x3C\x5F\x97\xFD\x60\x80\x39\x29\xC2\x14\xFD\xC2\x4D\x70";
1523        let s = b"\x6E\x68\x74\x11\x72\xF4\x9C\xE1\x99\x99\x1F\x67\xFC\x3A\x68\x33\xF9\x3F\x3A\xB9\x1A\xA5\x72\x4E\x78\xD4\x81\xCB\x7B\xA5\xE5\x0A";
1524
1525        hashed.add(Subpacket::new(SubpacketValue::IssuerFingerprint(fpr), false).unwrap()).unwrap();
1526        hashed.add(Subpacket::new(SubpacketValue::SignatureCreationTime(ctime), false).unwrap()).unwrap();
1527        unhashed.add(Subpacket::new(SubpacketValue::Issuer(kid), false).unwrap()).unwrap();
1528
1529        eprintln!("fpr: {}", key.fingerprint());
1530        let sig = Signature4::new(SignatureType::Binary, PublicKeyAlgorithm::EdDSA,
1531                                  HashAlgorithm::SHA256, hashed, unhashed,
1532                                  [0xa7,0x19],
1533                                  mpi::Signature::EdDSA{
1534                                      r: mpi::MPI::new(r), s: mpi::MPI::new(s)
1535                                  });
1536        let sig: Signature = sig.into();
1537        sig.verify_message(&key, b"Hello, World\n").unwrap();
1538    }
1539
1540    #[test]
1541    fn fingerprint_test() {
1542        let pile =
1543            PacketPile::from_bytes(crate::tests::key("public-key.pgp")).unwrap();
1544
1545        // The blob contains a public key and three subkeys.
1546        let mut pki = 0;
1547        let mut ski = 0;
1548
1549        let pks = [ "8F17777118A33DDA9BA48E62AACB3243630052D9" ];
1550        let sks = [ "C03FA6411B03AE12576461187223B56678E02528",
1551                    "50E6D924308DBF223CFB510AC2B819056C652598",
1552                    "2DC50AB55BE2F3B04C2D2CF8A3506AFB820ABD08"];
1553
1554        for p in pile.descendants() {
1555            if let &Packet::PublicKey(ref p) = p {
1556                let fp = p.fingerprint().to_hex();
1557                // eprintln!("PK: {:?}", fp);
1558
1559                assert!(pki < pks.len());
1560                assert_eq!(fp, pks[pki]);
1561                pki += 1;
1562            }
1563
1564            if let &Packet::PublicSubkey(ref p) = p {
1565                let fp = p.fingerprint().to_hex();
1566                // eprintln!("SK: {:?}", fp);
1567
1568                assert!(ski < sks.len());
1569                assert_eq!(fp, sks[ski]);
1570                ski += 1;
1571            }
1572        }
1573        assert!(pki == pks.len() && ski == sks.len());
1574    }
1575
1576    #[test]
1577    fn issue_617() -> Result<()> {
1578        use crate::serialize::MarshalInto;
1579        let p = Packet::from_bytes(&b"-----BEGIN PGP ARMORED FILE-----
1580
1581xcClBAAAAMUWBSuBBAAjAPDbS+Z6Ti+PouOV6c5Ypr3jn1w1Ih5GqikN5E29PGz+
1582CQMIoYc7R4YRiLr/ZJB/MW5M0kuuWyUirUKRkYCotB5omVE8fGtqW5wGCGf79Tzb
1583rKVmPl25CJdEabIfAOl0WwciipDx1tqNOOYEci/JWSbTEymEyCH9oQPObt2sdDxh
1584wLcBgsd/CVl3kuqiXFHNYDvWVBmUHeltS/J22Kfy/n1qD3CCBFooHGdc13KwtMLk
1585UPb5LTTqCk2ihQ7e+5u7EmueLUp1431HJiYa+olaPZ7caRNfQfggtHcfQOJdnWRJ
1586FN2nTDgLHX0cEOiMboZrS4S9xtjyVRLcRZcCIyeQF0Q889rq0lmxHG38XUeIj/3y
1587SJJNnZxmJtHNo+SZQ/gXhO9TzeeA6yQm2myQlRkXBtdQEz6mtznphWeWMkWApZpa
1588FwPoSAbbsLkNS/iNN2MDGAVYvezYn2QZ
1589=0cxs
1590-----END PGP ARMORED FILE-----"[..])?;
1591        let i: usize = 360;
1592        let mut buf = p.to_vec().unwrap();
1593        // Avoid first two bytes so that we don't change the
1594        // type and reduce the chance of changing the length.
1595        let bit = i.saturating_add(2 * 8) % (buf.len() * 8);
1596        buf[bit / 8] ^= 1 << (bit % 8);
1597        match Packet::from_bytes(&buf) {
1598            Ok(q) => {
1599                eprintln!("{:?}", p);
1600                eprintln!("{:?}", q);
1601                assert!(p != q);
1602            },
1603            Err(_) => unreachable!(),
1604        };
1605        Ok(())
1606    }
1607
1608    #[test]
1609    fn encrypt_huge_plaintext() -> Result<()> {
1610        let sk = crate::crypto::SessionKey::new(256).unwrap();
1611
1612        if PublicKeyAlgorithm::RSAEncryptSign.is_supported() {
1613            let rsa2k: Key<SecretParts, UnspecifiedRole> =
1614                Key4::generate_rsa(2048)?.into();
1615            assert!(matches!(
1616                rsa2k.encrypt(&sk).unwrap_err().downcast().unwrap(),
1617                crate::Error::InvalidArgument(_)
1618            ));
1619        }
1620
1621        if PublicKeyAlgorithm::ECDH.is_supported()
1622            && Curve::Cv25519.is_supported()
1623        {
1624            let cv25519: Key<SecretParts, UnspecifiedRole> =
1625                Key4::generate_ecc(false, Curve::Cv25519)?.into();
1626            assert!(matches!(
1627                cv25519.encrypt(&sk).unwrap_err().downcast().unwrap(),
1628                crate::Error::InvalidArgument(_)
1629            ));
1630        }
1631
1632        Ok(())
1633    }
1634
1635    #[test]
1636    fn cv25519_secret_is_reversed() -> Result<()> {
1637        use crate::crypto::backend::{Backend, interface::Asymmetric};
1638
1639        let (mut private_key, _) = Backend::x25519_generate_key()?;
1640        Backend::x25519_clamp_secret(&mut private_key);
1641
1642        let key: Key4<_, UnspecifiedRole> =
1643            Key4::import_secret_cv25519(&private_key, None, None, None)?;
1644        if let crate::packet::key::SecretKeyMaterial::Unencrypted(key) = key.secret() {
1645            key.map(|secret| {
1646                if let mpi::SecretKeyMaterial::ECDH { scalar } = secret {
1647                    let scalar_reversed = private_key.iter().copied().rev().collect::<Vec<u8>>();
1648                    let scalar_actual = &*scalar.value_padded(32);
1649                    assert_eq!(scalar_actual, scalar_reversed);
1650                } else {
1651                    unreachable!();
1652                }
1653            })
1654        } else {
1655            unreachable!();
1656        }
1657
1658        Ok(())
1659    }
1660
1661    #[test]
1662    fn ed25519_secret_is_not_reversed() {
1663        let private_key: &[u8] =
1664            &crate::crypto::SessionKey::new(32).unwrap();
1665        let key: Key4<_, UnspecifiedRole> = Key4::import_secret_ed25519(private_key, None).unwrap();
1666        if let crate::packet::key::SecretKeyMaterial::Unencrypted(key) = key.secret() {
1667            key.map(|secret| {
1668                if let mpi::SecretKeyMaterial::EdDSA { scalar } = secret {
1669                    assert_eq!(&*scalar.value_padded(32), private_key);
1670                } else {
1671                    unreachable!();
1672                }
1673            })
1674        } else {
1675            unreachable!();
1676        }
1677    }
1678
1679    #[test]
1680    fn issue_1016() {
1681        // The fingerprint is a function of the creation time,
1682        // algorithm, and public MPIs.  When we change them make sure
1683        // the fingerprint also changes.
1684
1685        let mut g = quickcheck::Gen::new(256);
1686
1687        let mut key = Key4::<PublicParts, UnspecifiedRole>::arbitrary(&mut g);
1688        let fpr1 = key.fingerprint();
1689        if key.creation_time() == UNIX_EPOCH {
1690            key.set_creation_time(UNIX_EPOCH + Duration::new(1, 0)).expect("ok");
1691        } else {
1692            key.set_creation_time(UNIX_EPOCH).expect("ok");
1693        }
1694        assert_ne!(fpr1, key.fingerprint());
1695
1696        let mut key = Key4::<PublicParts, UnspecifiedRole>::arbitrary(&mut g);
1697        let fpr1 = key.fingerprint();
1698        key.set_pk_algo(PublicKeyAlgorithm::from(u8::from(key.pk_algo()) + 1));
1699        assert_ne!(fpr1, key.fingerprint());
1700
1701        let mut key = Key4::<PublicParts, UnspecifiedRole>::arbitrary(&mut g);
1702        let fpr1 = key.fingerprint();
1703        loop {
1704            let mpis2 = mpi::PublicKey::arbitrary(&mut g);
1705            if key.mpis() != &mpis2 {
1706                *key.mpis_mut() = mpis2;
1707                break;
1708            }
1709        }
1710        assert_ne!(fpr1, key.fingerprint());
1711
1712        let mut key = Key4::<PublicParts, UnspecifiedRole>::arbitrary(&mut g);
1713        let fpr1 = key.fingerprint();
1714        loop {
1715            let mpis2 = mpi::PublicKey::arbitrary(&mut g);
1716            if key.mpis() != &mpis2 {
1717                key.set_mpis(mpis2);
1718                break;
1719            }
1720        }
1721        assert_ne!(fpr1, key.fingerprint());
1722    }
1723
1724    /// Smoke test for ECC key creation, signing and verification, and
1725    /// encryption and decryption.
1726    #[test]
1727    fn ecc_support() -> Result<()> {
1728        for for_signing in [true, false] {
1729            for curve in Curve::variants()
1730                .filter(Curve::is_supported)
1731            {
1732                match curve {
1733                    Curve::Cv25519 if for_signing => continue,
1734                    Curve::Ed25519 if ! for_signing => continue,
1735                    _ => (),
1736                }
1737
1738                eprintln!("curve {}, for signing {:?}", curve, for_signing);
1739                let key: Key<SecretParts, UnspecifiedRole> =
1740                    Key4::generate_ecc(for_signing, curve.clone())?.into();
1741                let mut pair = key.into_keypair()?;
1742
1743                if for_signing {
1744                    use crate::crypto::Signer;
1745                    let hash = HashAlgorithm::default();
1746                    let digest = hash.context()?
1747                        .for_signature(pair.public().version())
1748                        .into_digest()?;
1749                    let sig = pair.sign(hash, &digest)?;
1750                    pair.public().verify(&sig, hash, &digest)?;
1751                } else {
1752                    use crate::crypto::{SessionKey, Decryptor};
1753                    let sk = SessionKey::new(32).unwrap();
1754                    let ciphertext = pair.public().encrypt(&sk)?;
1755                    assert_eq!(pair.decrypt(&ciphertext, Some(sk.len()))?, sk);
1756                }
1757            }
1758        }
1759        Ok(())
1760    }
1761
1762    #[test]
1763    fn ecc_encoding() -> Result<()> {
1764        for for_signing in [true, false] {
1765            for curve in Curve::variants()
1766                .filter(Curve::is_supported)
1767            {
1768                match curve {
1769                    Curve::Cv25519 if for_signing => continue,
1770                    Curve::Ed25519 if ! for_signing => continue,
1771                    _ => (),
1772                }
1773
1774                use crate::crypto::mpi::{Ciphertext, MPI, PublicKey};
1775                eprintln!("curve {}, for signing {:?}", curve, for_signing);
1776
1777                let key: Key<SecretParts, UnspecifiedRole> =
1778                    Key4::generate_ecc(for_signing, curve.clone())?.into();
1779
1780                let compressed = |mpi: &MPI| mpi.value()[0] == 0x40;
1781                let uncompressed = |mpi: &MPI| mpi.value()[0] == 0x04;
1782
1783                match key.mpis() {
1784                    PublicKey::ECDSA { curve: c, q } if for_signing => {
1785                        assert!(c == &curve);
1786                        assert!(uncompressed(q));
1787                    },
1788                    PublicKey::EdDSA { curve: c, q } if for_signing => {
1789                        assert!(c == &curve);
1790                        assert!(compressed(q));
1791                    },
1792                    PublicKey::ECDH { curve: c, q, .. } if ! for_signing => {
1793                        assert!(c == &curve);
1794                        if curve == Curve::Cv25519 {
1795                            assert!(compressed(q));
1796                        } else {
1797                            assert!(uncompressed(q));
1798                        }
1799
1800                        use crate::crypto::SessionKey;
1801                        let sk = SessionKey::new(32).unwrap();
1802                        let ciphertext = key.encrypt(&sk)?;
1803                        if let Ciphertext::ECDH { e, .. } = &ciphertext {
1804                            if curve == Curve::Cv25519 {
1805                                assert!(compressed(e));
1806                            } else {
1807                                assert!(uncompressed(e));
1808                            }
1809                        } else {
1810                            panic!("unexpected ciphertext: {:?}", ciphertext);
1811                        }
1812                    },
1813                    mpi => unreachable!(
1814                        "curve {}, mpi {:?}, for signing {:?}",
1815                        curve, mpi, for_signing),
1816                }
1817            }
1818        }
1819        Ok(())
1820    }
1821}