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<T>(creation_time: T,
387                          pk_algo: PublicKeyAlgorithm,
388                          mpis: mpi::PublicKey,
389                          secret: Option<SecretKeyMaterial>)
390                          -> Result<Self>
391    where
392        T: Into<Timestamp>,
393    {
394        Ok(Key4 {
395            common: Default::default(),
396            creation_time: creation_time.into(),
397            pk_algo,
398            mpis,
399            secret,
400            fingerprint: Default::default(),
401            role: R::role(),
402            p: std::marker::PhantomData,
403            r: std::marker::PhantomData,
404        })
405    }
406
407    pub(crate) fn role(&self) -> KeyRoleRT {
408        self.role
409    }
410
411    pub(crate) fn set_role(&mut self, role: KeyRoleRT) {
412        self.role = role;
413    }
414}
415
416impl<R> Key4<key::PublicParts, R>
417    where R: key::KeyRole,
418{
419    /// Creates an OpenPGP public key from the specified key material.
420    pub fn new<T>(creation_time: T, pk_algo: PublicKeyAlgorithm,
421                  mpis: mpi::PublicKey)
422                  -> Result<Self>
423        where T: Into<time::SystemTime>
424    {
425        Ok(Key4 {
426            common: Default::default(),
427            creation_time: creation_time.into().try_into()?,
428            pk_algo,
429            mpis,
430            secret: None,
431            fingerprint: Default::default(),
432            role: R::role(),
433            p: std::marker::PhantomData,
434            r: std::marker::PhantomData,
435        })
436    }
437
438    /// Creates an OpenPGP public key packet from existing X25519 key
439    /// material.
440    ///
441    /// The ECDH key will use hash algorithm `hash` and symmetric
442    /// algorithm `sym`.  If one or both are `None` secure defaults
443    /// will be used.  The key will have its creation date set to
444    /// `ctime` or the current time if `None` is given.
445    pub fn import_public_cv25519<H, S, T>(public_key: &[u8],
446                                          hash: H, sym: S, ctime: T)
447        -> Result<Self> where H: Into<Option<HashAlgorithm>>,
448                              S: Into<Option<SymmetricAlgorithm>>,
449                              T: Into<Option<time::SystemTime>>
450    {
451        let mut point = Vec::from(public_key);
452        point.insert(0, 0x40);
453
454        use crate::crypto::ecdh;
455        Self::new(
456            ctime.into().unwrap_or_else(crate::now),
457            PublicKeyAlgorithm::ECDH,
458            mpi::PublicKey::ECDH {
459                curve: Curve::Cv25519,
460                hash: hash.into().unwrap_or_else(
461                    || ecdh::default_ecdh_kdf_hash(&Curve::Cv25519)),
462                sym: sym.into().unwrap_or_else(
463                    || ecdh::default_ecdh_kek_cipher(&Curve::Cv25519)),
464                q: mpi::MPI::new(&point),
465            })
466    }
467
468    /// Creates an OpenPGP public key packet from existing Ed25519 key
469    /// material.
470    ///
471    /// The key will have its creation date set to `ctime` or the
472    /// current time if `None` is given.
473    pub fn import_public_ed25519<T>(public_key: &[u8], ctime: T) -> Result<Self>
474        where  T: Into<Option<time::SystemTime>>
475    {
476        let mut point = Vec::from(public_key);
477        point.insert(0, 0x40);
478
479        Self::new(
480            ctime.into().unwrap_or_else(crate::now),
481            PublicKeyAlgorithm::EdDSA,
482            mpi::PublicKey::EdDSA {
483                curve: Curve::Ed25519,
484                q: mpi::MPI::new(&point),
485            })
486    }
487
488    /// Creates an OpenPGP public key packet from existing RSA key
489    /// material.
490    ///
491    /// The RSA key will use the public exponent `e` and the modulo
492    /// `n`. The key will have its creation date set to `ctime` or the
493    /// current time if `None` is given.
494    pub fn import_public_rsa<T>(e: &[u8], n: &[u8], ctime: T)
495        -> Result<Self> where T: Into<Option<time::SystemTime>>
496    {
497        Self::new(
498            ctime.into().unwrap_or_else(crate::now),
499            PublicKeyAlgorithm::RSAEncryptSign,
500            mpi::PublicKey::RSA {
501                e: mpi::MPI::new(e),
502                n: mpi::MPI::new(n),
503            })
504    }
505}
506
507impl<R> Key4<SecretParts, R>
508    where R: key::KeyRole,
509{
510    /// Creates an OpenPGP key packet from the specified secret key
511    /// material.
512    pub fn with_secret<T>(creation_time: T, pk_algo: PublicKeyAlgorithm,
513                          mpis: mpi::PublicKey,
514                          secret: SecretKeyMaterial)
515                          -> Result<Self>
516        where T: Into<time::SystemTime>
517    {
518        Ok(Key4 {
519            common: Default::default(),
520            creation_time: creation_time.into().try_into()?,
521            pk_algo,
522            mpis,
523            secret: Some(secret),
524            fingerprint: Default::default(),
525            role: R::role(),
526            p: std::marker::PhantomData,
527            r: std::marker::PhantomData,
528        })
529    }
530
531    /// Creates a new OpenPGP secret key packet for an existing X25519 key.
532    ///
533    /// The ECDH key will use hash algorithm `hash` and symmetric
534    /// algorithm `sym`.  If one or both are `None` secure defaults
535    /// will be used.  The key will have its creation date set to
536    /// `ctime` or the current time if `None` is given.
537    ///
538    /// The given `private_key` is expected to be in the native X25519
539    /// representation, i.e. as opaque byte string of length 32.  It
540    /// is transformed into OpenPGP's representation during import.
541    pub fn import_secret_cv25519<H, S, T>(private_key: &[u8],
542                                          hash: H, sym: S, ctime: T)
543        -> Result<Self> where H: Into<Option<HashAlgorithm>>,
544                              S: Into<Option<SymmetricAlgorithm>>,
545                              T: Into<Option<std::time::SystemTime>>
546    {
547        use crate::crypto::backend::{Backend, interface::Asymmetric};
548
549        let mut private_key = Protected::from(private_key);
550        let public_key = Backend::x25519_derive_public(&private_key)?;
551
552        // Clamp the X25519 secret key scalar.
553        //
554        // X25519 does the clamping implicitly, but OpenPGP's ECDH
555        // over Curve25519 requires the secret to be clamped.  To
556        // increase compatibility with OpenPGP implementations that do
557        // not implicitly clamp the secrets before use, we do that
558        // before we store the secrets in OpenPGP data structures.
559        Backend::x25519_clamp_secret(&mut private_key);
560
561        // Reverse the scalar.
562        //
563        // X25519 stores the secret as opaque byte string representing
564        // a little-endian scalar.  OpenPGP's ECDH over Curve25519 on
565        // the other hand stores it as big-endian scalar, as was
566        // customary in OpenPGP.  See
567        // https://lists.gnupg.org/pipermail/gnupg-devel/2018-February/033437.html.
568        private_key.reverse();
569
570        use crate::crypto::ecdh;
571        Self::with_secret(
572            ctime.into().unwrap_or_else(crate::now),
573            PublicKeyAlgorithm::ECDH,
574            mpi::PublicKey::ECDH {
575                curve: Curve::Cv25519,
576                hash: hash.into().unwrap_or_else(
577                    || ecdh::default_ecdh_kdf_hash(&Curve::Cv25519)),
578                sym: sym.into().unwrap_or_else(
579                    || ecdh::default_ecdh_kek_cipher(&Curve::Cv25519)),
580                q: mpi::MPI::new_compressed_point(&public_key),
581            },
582            mpi::SecretKeyMaterial::ECDH {
583                scalar: private_key.into(),
584            }.into())
585    }
586
587    /// Creates a new OpenPGP secret key packet for an existing Ed25519 key.
588    ///
589    /// The key will have its creation date set to `ctime` or the current
590    /// time if `None` is given.
591    pub fn import_secret_ed25519<T>(private_key: &[u8], ctime: T)
592        -> Result<Self> where T: Into<Option<time::SystemTime>>
593    {
594        use crate::crypto::backend::{Backend, interface::Asymmetric};
595
596        let private_key = Protected::from(private_key);
597        let public_key = Backend::ed25519_derive_public(&private_key)?;
598
599        Self::with_secret(
600            ctime.into().unwrap_or_else(crate::now),
601            PublicKeyAlgorithm::EdDSA,
602            mpi::PublicKey::EdDSA {
603                curve: Curve::Ed25519,
604                q: mpi::MPI::new_compressed_point(&public_key),
605            },
606            mpi::SecretKeyMaterial::EdDSA {
607                scalar: private_key.into(),
608            }.into())
609    }
610
611    /// Generates a new ECC key over `curve`.
612    ///
613    /// If `for_signing` is false a ECDH key, if it's true either a
614    /// EdDSA or ECDSA key is generated.  Giving `for_signing == true` and
615    /// `curve == Cv25519` will produce an error. Likewise
616    /// `for_signing == false` and `curve == Ed25519` will produce an error.
617    pub fn generate_ecc(for_signing: bool, curve: Curve) -> Result<Self> {
618        use crate::crypto::backend::{Backend, interface::Asymmetric};
619
620        let (pk_algo, public, secret) = match (curve, for_signing) {
621            (Curve::Ed25519, true) => {
622                let (secret, public) = Backend::ed25519_generate_key()?;
623
624                (
625                    PublicKeyAlgorithm::EdDSA,
626                    mpi::PublicKey::EdDSA {
627                        curve: Curve::Ed25519,
628                        q: mpi::MPI::new_compressed_point(&public),
629                    },
630                    mpi::SecretKeyMaterial::EdDSA {
631                        scalar: secret.into(),
632                    },
633                )
634            },
635
636            (Curve::Cv25519, false) => {
637                let (mut secret, public) = Backend::x25519_generate_key()?;
638
639                // Clamp the X25519 secret key scalar.
640                //
641                // X25519 does the clamping implicitly, but OpenPGP's ECDH over
642                // Curve25519 requires the secret to be clamped.  To increase
643                // compatibility with OpenPGP implementations that do not
644                // implicitly clamp the secrets before use, we do that before we
645                // store the secrets in OpenPGP data structures.
646                Backend::x25519_clamp_secret(&mut secret);
647
648                // Reverse the scalar.
649                //
650                // X25519 stores the secret as opaque byte string
651                // representing a little-endian scalar.  OpenPGP's
652                // ECDH over Curve25519 on the other hand stores it as
653                // big-endian scalar, as was customary in OpenPGP.
654                // See
655                // https://lists.gnupg.org/pipermail/gnupg-devel/2018-February/033437.html.
656                secret.reverse();
657
658                (
659                    PublicKeyAlgorithm::ECDH,
660                    mpi::PublicKey::ECDH {
661                        curve: Curve::Cv25519,
662                        q: mpi::MPI::new_compressed_point(&public),
663                        hash: crate::crypto::ecdh::default_ecdh_kdf_hash(
664                            &Curve::Cv25519),
665                        sym: crate::crypto::ecdh::default_ecdh_kek_cipher(
666                            &Curve::Cv25519),
667                    },
668                    mpi::SecretKeyMaterial::ECDH {
669                        scalar: secret.into(),
670                    },
671                )
672            },
673
674            (curve, for_signing) =>
675                Self::generate_ecc_backend(for_signing, curve)?,
676        };
677
678        Self::with_secret(crate::now(), pk_algo, public, secret.into())
679    }
680
681    /// Generates a new DSA key with a public modulus of size `p_bits`.
682    ///
683    /// Note: In order to comply with FIPS 186-4, and to increase
684    /// compatibility with implementations, you SHOULD only generate
685    /// keys with moduli of size `2048` or `3072` bits.
686    pub fn generate_dsa(p_bits: usize) -> Result<Self> {
687        use crate::crypto::backend::{Backend, interface::Asymmetric};
688
689        let (p, q, g, y, x) = Backend::dsa_generate_key(p_bits)?;
690        let public_mpis = mpi::PublicKey::DSA { p, q, g, y };
691        let private_mpis = mpi::SecretKeyMaterial::DSA { x };
692
693        Self::with_secret(
694            crate::now(),
695            #[allow(deprecated)]
696            PublicKeyAlgorithm::DSA,
697            public_mpis,
698            private_mpis.into())
699    }
700
701    /// Generates a new ElGamal key with a public modulus of size `p_bits`.
702    ///
703    /// Note: ElGamal is no longer well-supported in cryptographic
704    /// libraries and should be avoided.
705    pub fn generate_elgamal(p_bits: usize) -> Result<Self> {
706        use crate::crypto::backend::{Backend, interface::Asymmetric};
707
708        let (p, g, y, x) = Backend::elgamal_generate_key(p_bits)?;
709        let public_mpis = mpi::PublicKey::ElGamal { p, g, y };
710        let private_mpis = mpi::SecretKeyMaterial::ElGamal { x };
711
712        Self::with_secret(
713            crate::now(),
714            #[allow(deprecated)]
715            PublicKeyAlgorithm::ElGamalEncrypt,
716            public_mpis,
717            private_mpis.into())
718    }
719
720    /// Generates a new X25519 key.
721    pub fn generate_x25519() -> Result<Self> {
722        use crate::crypto::backend::{Backend, interface::Asymmetric};
723
724        let (private, public) = Backend::x25519_generate_key()?;
725
726        Self::with_secret(
727            crate::now(),
728            PublicKeyAlgorithm::X25519,
729            mpi::PublicKey::X25519 {
730                u: public,
731            },
732            mpi::SecretKeyMaterial::X25519 {
733                x: private,
734            }.into())
735    }
736
737    /// Generates a new X448 key.
738    pub fn generate_x448() -> Result<Self> {
739        use crate::crypto::backend::{Backend, interface::Asymmetric};
740
741        let (private, public) = Backend::x448_generate_key()?;
742
743        Self::with_secret(
744            crate::now(),
745            PublicKeyAlgorithm::X448,
746            mpi::PublicKey::X448 {
747                u: Box::new(public),
748            },
749            mpi::SecretKeyMaterial::X448 {
750                x: private,
751            }.into())
752    }
753
754    /// Generates a new Ed25519 key.
755    pub fn generate_ed25519() -> Result<Self> {
756        use crate::crypto::backend::{Backend, interface::Asymmetric};
757
758        let (private, public) = Backend::ed25519_generate_key()?;
759
760        Self::with_secret(
761            crate::now(),
762            PublicKeyAlgorithm::Ed25519,
763            mpi::PublicKey::Ed25519 {
764                a: public,
765            },
766            mpi::SecretKeyMaterial::Ed25519 {
767                x: private,
768            }.into())
769    }
770
771    /// Generates a new Ed448 key.
772    pub fn generate_ed448() -> Result<Self> {
773        use crate::crypto::backend::{Backend, interface::Asymmetric};
774
775        let (private, public) = Backend::ed448_generate_key()?;
776
777        Self::with_secret(
778            crate::now(),
779            PublicKeyAlgorithm::Ed448,
780            mpi::PublicKey::Ed448 {
781                a: Box::new(public),
782            },
783            mpi::SecretKeyMaterial::Ed448 {
784                x: private,
785            }.into())
786    }
787
788    /// Creates a new key pair from a secret `Key` with an unencrypted
789    /// secret key.
790    ///
791    /// # Errors
792    ///
793    /// Fails if the secret key is encrypted.  You can use
794    /// [`Key::decrypt_secret`] to decrypt a key.
795    pub fn into_keypair(self) -> Result<KeyPair> {
796        let (key, secret) = self.take_secret();
797        let secret = match secret {
798            SecretKeyMaterial::Unencrypted(secret) => secret,
799            SecretKeyMaterial::Encrypted(_) =>
800                return Err(Error::InvalidArgument(
801                    "secret key material is encrypted".into()).into()),
802        };
803
804        KeyPair::new(key.role_into_unspecified().into(), secret)
805    }
806}
807
808macro_rules! impl_common_secret_functions {
809    ($t: ident) => {
810        /// Secret key material handling.
811        impl<R> Key4<$t, R>
812            where R: key::KeyRole,
813        {
814            /// Takes the `Key`'s `SecretKeyMaterial`, if any.
815            pub fn take_secret(mut self)
816                               -> (Key4<PublicParts, R>, Option<SecretKeyMaterial>)
817            {
818                let old = std::mem::replace(&mut self.secret, None);
819                (self.parts_into_public(), old)
820            }
821
822            /// Adds the secret key material to the `Key`, returning
823            /// the old secret key material, if any.
824            pub fn add_secret(mut self, secret: SecretKeyMaterial)
825                              -> (Key4<SecretParts, R>, Option<SecretKeyMaterial>)
826            {
827                let old = std::mem::replace(&mut self.secret, Some(secret));
828                (self.parts_into_secret().expect("secret just set"), old)
829            }
830
831            /// Takes the `Key`'s `SecretKeyMaterial`, if any.
832            pub fn steal_secret(&mut self) -> Option<SecretKeyMaterial>
833            {
834                std::mem::replace(&mut self.secret, None)
835            }
836        }
837    }
838}
839impl_common_secret_functions!(PublicParts);
840impl_common_secret_functions!(UnspecifiedParts);
841
842/// Secret key handling.
843impl<R> Key4<SecretParts, R>
844    where R: key::KeyRole,
845{
846    /// Gets the `Key`'s `SecretKeyMaterial`.
847    pub fn secret(&self) -> &SecretKeyMaterial {
848        self.secret.as_ref().expect("has secret")
849    }
850
851    /// Gets a mutable reference to the `Key`'s `SecretKeyMaterial`.
852    pub fn secret_mut(&mut self) -> &mut SecretKeyMaterial {
853        self.secret.as_mut().expect("has secret")
854    }
855
856    /// Takes the `Key`'s `SecretKeyMaterial`.
857    pub fn take_secret(mut self)
858                       -> (Key4<PublicParts, R>, SecretKeyMaterial)
859    {
860        let old = std::mem::replace(&mut self.secret, None);
861        (self.parts_into_public(),
862         old.expect("Key<SecretParts, _> has a secret key material"))
863    }
864
865    /// Adds `SecretKeyMaterial` to the `Key`.
866    ///
867    /// This function returns the old secret key material, if any.
868    pub fn add_secret(mut self, secret: SecretKeyMaterial)
869                      -> (Key4<SecretParts, R>, SecretKeyMaterial)
870    {
871        let old = std::mem::replace(&mut self.secret, Some(secret));
872        (self.parts_into_secret().expect("secret just set"),
873         old.expect("Key<SecretParts, _> has a secret key material"))
874    }
875
876    /// Decrypts the secret key material using `password`.
877    ///
878    /// In OpenPGP, secret key material can be [protected with a
879    /// password].  The password is usually hardened using a [KDF].
880    ///
881    /// Refer to the documentation of [`Key::decrypt_secret`] for
882    /// details.
883    ///
884    /// This function returns an error if the secret key material is
885    /// not encrypted or the password is incorrect.
886    ///
887    /// [protected with a password]: https://www.rfc-editor.org/rfc/rfc9580.html#section-5.5.3
888    /// [KDF]: https://www.rfc-editor.org/rfc/rfc9580.html#section-3.7
889    /// [`Key::decrypt_secret`]: super::Key::decrypt_secret()
890    pub fn decrypt_secret(self, password: &Password) -> Result<Self> {
891        let (key, mut secret) = self.take_secret();
892        let key = Key::V4(key);
893        secret.decrypt_in_place(&key, password)?;
894        let key = if let Key::V4(k) = key { k } else { unreachable!() };
895        Ok(key.add_secret(secret).0)
896    }
897
898    /// Encrypts the secret key material using `password`.
899    ///
900    /// In OpenPGP, secret key material can be [protected with a
901    /// password].  The password is usually hardened using a [KDF].
902    ///
903    /// Refer to the documentation of [`Key::encrypt_secret`] for
904    /// details.
905    ///
906    /// This returns an error if the secret key material is already
907    /// encrypted.
908    ///
909    /// [protected with a password]: https://www.rfc-editor.org/rfc/rfc9580.html#section-5.5.3
910    /// [KDF]: https://www.rfc-editor.org/rfc/rfc9580.html#section-3.7
911    /// [`Key::encrypt_secret`]: super::Key::encrypt_secret()
912    pub fn encrypt_secret(self, password: &Password)
913        -> Result<Key4<SecretParts, R>>
914    {
915        let (key, mut secret) = self.take_secret();
916        let key = Key::V4(key);
917        secret.encrypt_in_place(&key, password)?;
918        let key = if let Key::V4(k) = key { k } else { unreachable!() };
919        Ok(key.add_secret(secret).0)
920    }
921}
922
923impl<P, R> From<Key4<P, R>> for super::Key<P, R>
924    where P: key::KeyParts,
925          R: key::KeyRole,
926{
927    fn from(p: Key4<P, R>) -> Self {
928        super::Key::V4(p)
929    }
930}
931
932#[cfg(test)]
933use crate::packet::key::{
934    PrimaryRole,
935    SubordinateRole,
936    UnspecifiedRole,
937};
938
939#[cfg(test)]
940impl Arbitrary for Key4<PublicParts, PrimaryRole> {
941    fn arbitrary(g: &mut Gen) -> Self {
942        Key4::<PublicParts, UnspecifiedRole>::arbitrary(g).into()
943    }
944}
945
946#[cfg(test)]
947impl Arbitrary for Key4<PublicParts, SubordinateRole> {
948    fn arbitrary(g: &mut Gen) -> Self {
949        Key4::<PublicParts, UnspecifiedRole>::arbitrary(g).into()
950    }
951}
952
953#[cfg(test)]
954impl Arbitrary for Key4<PublicParts, UnspecifiedRole> {
955    fn arbitrary(g: &mut Gen) -> Self {
956        let mpis = mpi::PublicKey::arbitrary(g);
957        Key4 {
958            common: Arbitrary::arbitrary(g),
959            creation_time: Arbitrary::arbitrary(g),
960            pk_algo: mpis.algo()
961                .expect("mpi::PublicKey::arbitrary only uses known algos"),
962            mpis,
963            secret: None,
964            fingerprint: Default::default(),
965            role: UnspecifiedRole::role(),
966            p: std::marker::PhantomData,
967            r: std::marker::PhantomData,
968        }
969    }
970}
971
972#[cfg(test)]
973impl Arbitrary for Key4<SecretParts, PrimaryRole> {
974    fn arbitrary(g: &mut Gen) -> Self {
975        Key4::<SecretParts, PrimaryRole>::arbitrary_secret_key(g)
976    }
977}
978
979#[cfg(test)]
980impl Arbitrary for Key4<SecretParts, SubordinateRole> {
981    fn arbitrary(g: &mut Gen) -> Self {
982        Key4::<SecretParts, SubordinateRole>::arbitrary_secret_key(g)
983    }
984}
985
986#[cfg(test)]
987impl<R> Key4<SecretParts, R>
988where
989    R: KeyRole,
990    Key4::<PublicParts, R>: Arbitrary,
991{
992    fn arbitrary_secret_key(g: &mut Gen) -> Self {
993        let key = Key::V4(Key4::<PublicParts, R>::arbitrary(g));
994        let mut secret: SecretKeyMaterial =
995            mpi::SecretKeyMaterial::arbitrary_for(g, key.pk_algo())
996            .expect("only known algos used")
997            .into();
998
999        if <bool>::arbitrary(g) {
1000            secret.encrypt_in_place(&key, &Password::from(Vec::arbitrary(g)))
1001                .unwrap();
1002        }
1003
1004        let key = if let Key::V4(k) = key { k } else { unreachable!() };
1005        Key4::<PublicParts, R>::add_secret(key, secret).0
1006    }
1007}
1008
1009#[cfg(test)]
1010mod tests {
1011    use std::time::Duration;
1012    use std::time::UNIX_EPOCH;
1013
1014    use crate::crypto::S2K;
1015    use crate::packet::Key;
1016    use crate::Cert;
1017    use crate::packet::pkesk::PKESK3;
1018    use crate::packet::key;
1019    use crate::packet::key::SecretKeyMaterial;
1020    use crate::packet::Packet;
1021    use super::*;
1022    use crate::PacketPile;
1023    use crate::serialize::Serialize;
1024    use crate::parse::Parse;
1025
1026    #[test]
1027    fn encrypted_rsa_key() {
1028        let cert = Cert::from_bytes(
1029            crate::tests::key("testy-new-encrypted-with-123.pgp")).unwrap();
1030        let key = cert.primary_key().key().clone();
1031        let (key, secret) = key.take_secret();
1032        let mut secret = secret.unwrap();
1033
1034        assert!(secret.is_encrypted());
1035        secret.decrypt_in_place(&key, &"123".into()).unwrap();
1036        assert!(!secret.is_encrypted());
1037        let (pair, _) = key.add_secret(secret);
1038        assert!(pair.has_unencrypted_secret());
1039
1040        match pair.secret() {
1041            SecretKeyMaterial::Unencrypted(ref u) => u.map(|mpis| match mpis {
1042                mpi::SecretKeyMaterial::RSA { .. } => (),
1043                _ => panic!(),
1044            }),
1045            _ => panic!(),
1046        }
1047    }
1048
1049    #[test]
1050    fn primary_key_encrypt_decrypt() -> Result<()> {
1051        key_encrypt_decrypt::<PrimaryRole>()
1052    }
1053
1054    #[test]
1055    fn subkey_encrypt_decrypt() -> Result<()> {
1056        key_encrypt_decrypt::<SubordinateRole>()
1057    }
1058
1059    fn key_encrypt_decrypt<R>() -> Result<()>
1060    where
1061        R: KeyRole + PartialEq,
1062    {
1063        let mut g = quickcheck::Gen::new(256);
1064        let p: Password = Vec::<u8>::arbitrary(&mut g).into();
1065
1066        let check = |key: Key4<SecretParts, R>| -> Result<()> {
1067            let key: Key<_, _> = key.into();
1068            let encrypted = key.clone().encrypt_secret(&p)?;
1069            let decrypted = encrypted.decrypt_secret(&p)?;
1070            assert_eq!(key, decrypted);
1071            Ok(())
1072        };
1073
1074        use crate::types::Curve::*;
1075        for curve in vec![NistP256, NistP384, NistP521, Ed25519] {
1076            if ! curve.is_supported() {
1077                eprintln!("Skipping unsupported {}", curve);
1078                continue;
1079            }
1080
1081            let key: Key4<_, R>
1082                = Key4::generate_ecc(true, curve.clone())?;
1083            check(key)?;
1084        }
1085
1086        for bits in vec![2048, 3072] {
1087            if ! PublicKeyAlgorithm::RSAEncryptSign.is_supported() {
1088                eprintln!("Skipping unsupported RSA");
1089                continue;
1090            }
1091
1092            let key: Key4<_, R>
1093                = Key4::generate_rsa(bits)?;
1094            check(key)?;
1095        }
1096
1097        Ok(())
1098    }
1099
1100    #[test]
1101    fn eq() {
1102        use crate::types::Curve::*;
1103
1104        for curve in vec![NistP256, NistP384, NistP521] {
1105            if ! curve.is_supported() {
1106                eprintln!("Skipping unsupported {}", curve);
1107                continue;
1108            }
1109
1110            let sign_key : Key4<_, key::UnspecifiedRole>
1111                = Key4::generate_ecc(true, curve.clone()).unwrap();
1112            let enc_key : Key4<_, key::UnspecifiedRole>
1113                = Key4::generate_ecc(false, curve).unwrap();
1114            let sign_clone = sign_key.clone();
1115            let enc_clone = enc_key.clone();
1116
1117            assert_eq!(sign_key, sign_clone);
1118            assert_eq!(enc_key, enc_clone);
1119        }
1120
1121        for bits in vec![1024, 2048, 3072, 4096] {
1122            if ! PublicKeyAlgorithm::RSAEncryptSign.is_supported() {
1123                eprintln!("Skipping unsupported RSA");
1124                continue;
1125            }
1126
1127            let key : Key4<_, key::UnspecifiedRole>
1128                = Key4::generate_rsa(bits).unwrap();
1129            let clone = key.clone();
1130            assert_eq!(key, clone);
1131        }
1132    }
1133
1134    #[test]
1135    fn generate_roundtrip() {
1136        use crate::types::Curve::*;
1137
1138        let keys = vec![NistP256, NistP384, NistP521].into_iter().flat_map(|cv|
1139        {
1140            if ! cv.is_supported() {
1141                eprintln!("Skipping unsupported {}", cv);
1142                return Vec::new();
1143            }
1144
1145            let sign_key : Key4<key::SecretParts, key::PrimaryRole>
1146                = Key4::generate_ecc(true, cv.clone()).unwrap();
1147            let enc_key = Key4::generate_ecc(false, cv).unwrap();
1148
1149            vec![sign_key, enc_key]
1150        }).chain(vec![1024, 2048, 3072, 4096].into_iter().filter_map(|b| {
1151            Key4::generate_rsa(b).ok()
1152        }));
1153
1154        for key in keys {
1155            let mut b = Vec::new();
1156            Packet::SecretKey(key.clone().into()).serialize(&mut b).unwrap();
1157
1158            let pp = PacketPile::from_bytes(&b).unwrap();
1159            if let Some(Packet::SecretKey(Key::V4(ref parsed_key))) =
1160                pp.path_ref(&[0])
1161            {
1162                assert_eq!(key.creation_time(), parsed_key.creation_time());
1163                assert_eq!(key.pk_algo(), parsed_key.pk_algo());
1164                assert_eq!(key.mpis(), parsed_key.mpis());
1165                assert_eq!(key.secret(), parsed_key.secret());
1166
1167                assert_eq!(&key, parsed_key);
1168            } else {
1169                panic!("bad packet: {:?}", pp.path_ref(&[0]));
1170            }
1171
1172            let mut b = Vec::new();
1173            let pk4 : Key4<PublicParts, PrimaryRole> = key.clone().into();
1174            Packet::PublicKey(pk4.into()).serialize(&mut b).unwrap();
1175
1176            let pp = PacketPile::from_bytes(&b).unwrap();
1177            if let Some(Packet::PublicKey(Key::V4(ref parsed_key))) =
1178                pp.path_ref(&[0])
1179            {
1180                assert!(! parsed_key.has_secret());
1181
1182                let key = key.take_secret().0;
1183                assert_eq!(&key, parsed_key);
1184            } else {
1185                panic!("bad packet: {:?}", pp.path_ref(&[0]));
1186            }
1187        }
1188    }
1189
1190    #[test]
1191    fn encryption_roundtrip() {
1192        use crate::crypto::SessionKey;
1193        use crate::types::Curve::*;
1194
1195        let keys = vec![NistP256, NistP384, NistP521].into_iter()
1196            .filter_map(|cv| {
1197                Key4::generate_ecc(false, cv).ok()
1198            }).chain(vec![1024, 2048, 3072, 4096].into_iter().filter_map(|b| {
1199                Key4::generate_rsa(b).ok()
1200            })).chain(vec![1024, 2048, 3072, 4096].into_iter().filter_map(|b| {
1201                Key4::generate_elgamal(b).ok()
1202            }));
1203
1204        for key in keys.into_iter() {
1205            let key: Key<key::SecretParts, key::UnspecifiedRole> = key.into();
1206            let mut keypair = key.clone().into_keypair().unwrap();
1207            let cipher = SymmetricAlgorithm::AES256;
1208            let sk = SessionKey::new(cipher.key_size().unwrap()).unwrap();
1209
1210            let pkesk = PKESK3::for_recipient(cipher, &sk, &key).unwrap();
1211            let (cipher_, sk_) = pkesk.decrypt(&mut keypair, None)
1212                .expect("keypair should be able to decrypt PKESK");
1213
1214            assert_eq!(cipher, cipher_);
1215            assert_eq!(sk, sk_);
1216
1217            let (cipher_, sk_) =
1218                pkesk.decrypt(&mut keypair, Some(cipher)).unwrap();
1219
1220            assert_eq!(cipher, cipher_);
1221            assert_eq!(sk, sk_);
1222        }
1223    }
1224
1225    #[test]
1226    fn signature_roundtrip() {
1227        use crate::types::{Curve::*, SignatureType};
1228
1229        let keys = vec![NistP256, NistP384, NistP521].into_iter()
1230            .filter_map(|cv| {
1231                Key4::generate_ecc(true, cv).ok()
1232            }).chain(vec![1024, 2048, 3072, 4096].into_iter().filter_map(|b| {
1233                Key4::generate_rsa(b).ok()
1234            })).chain(vec![1024, 2048, 3072].into_iter().filter_map(|b| {
1235                Key4::generate_dsa(b).ok()
1236            }));
1237
1238        for key in keys.into_iter() {
1239            let key: Key<key::SecretParts, key::UnspecifiedRole> = key.into();
1240            let mut keypair = key.clone().into_keypair().unwrap();
1241            let hash = HashAlgorithm::default();
1242
1243            // Sign.
1244            let ctx = hash.context().unwrap().for_signature(key.version());
1245            let sig = SignatureBuilder::new(SignatureType::Binary)
1246                .sign_hash(&mut keypair, ctx).unwrap();
1247
1248            // Verify.
1249            let ctx = hash.context().unwrap().for_signature(key.version());
1250            sig.verify_hash(&key, ctx).unwrap();
1251        }
1252    }
1253
1254    #[test]
1255    fn secret_encryption_roundtrip() {
1256        use crate::types::Curve::*;
1257        use crate::types::SymmetricAlgorithm::*;
1258        use crate::types::AEADAlgorithm::*;
1259
1260        let keys = vec![NistP256, NistP384, NistP521].into_iter()
1261            .filter_map(|cv| -> Option<Key<key::SecretParts, key::PrimaryRole>> {
1262                Key4::generate_ecc(false, cv).map(Into::into).ok()
1263            }).chain(vec![1024, 2048, 3072, 4096].into_iter().filter_map(|b| {
1264                Key4::generate_rsa(b).map(Into::into).ok()
1265            }));
1266
1267        for key in keys {
1268          for (symm, aead) in [(AES128, None),
1269                               (AES128, Some(OCB)),
1270                               (AES256, Some(EAX))] {
1271            if ! aead.map(|a| a.is_supported()).unwrap_or(true) {
1272                continue;
1273            }
1274            assert!(! key.secret().is_encrypted());
1275
1276            let password = Password::from("foobarbaz");
1277            let mut encrypted_key = key.clone();
1278
1279            encrypted_key.secret_mut()
1280                .encrypt_in_place_with(&key, S2K::default(), symm, aead,
1281                                       &password).unwrap();
1282            assert!(encrypted_key.secret().is_encrypted());
1283
1284            encrypted_key.secret_mut()
1285                .decrypt_in_place(&key, &password).unwrap();
1286            assert!(! key.secret().is_encrypted());
1287            assert_eq!(key, encrypted_key);
1288            assert_eq!(key.secret(), encrypted_key.secret());
1289          }
1290        }
1291    }
1292
1293    #[test]
1294    fn import_cv25519() {
1295        use crate::crypto::{ecdh, mem, SessionKey};
1296        use self::mpi::{MPI, Ciphertext};
1297
1298        // X25519 key
1299        let ctime =
1300            time::UNIX_EPOCH + time::Duration::new(0x5c487129, 0);
1301        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";
1302        let key : Key<_, key::UnspecifiedRole>
1303            = Key4::import_public_cv25519(&public[..],
1304                                          HashAlgorithm::SHA256,
1305                                          SymmetricAlgorithm::AES128,
1306                                          ctime).unwrap().into();
1307
1308        // PKESK
1309        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"[..]);
1310        let ciphertext = Ciphertext::ECDH{
1311            e: eph_pubkey.clone(),
1312            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()
1313        };
1314        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();
1315
1316        // Session key
1317        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";
1318        let sk = SessionKey::from(Vec::from(&dek[..]));
1319
1320        // Expected
1321        let got_enc = ecdh::encrypt_wrap(&key.parts_into_public(),
1322                                           &sk, eph_pubkey, &shared_sec)
1323            .unwrap();
1324
1325        assert_eq!(ciphertext, got_enc);
1326    }
1327
1328    #[test]
1329    fn import_cv25519_sec() -> Result<()> {
1330        use self::mpi::{MPI, Ciphertext};
1331
1332        // X25519 key
1333        let ctime =
1334            time::UNIX_EPOCH + time::Duration::new(0x5c487129, 0);
1335        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";
1336        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";
1337        let key: Key<_, UnspecifiedRole>
1338            = Key4::import_secret_cv25519(&secret[..],
1339                                          HashAlgorithm::SHA256,
1340                                          SymmetricAlgorithm::AES128,
1341                                          ctime).unwrap().into();
1342        match key.mpis() {
1343            self::mpi::PublicKey::ECDH{ ref q,.. } =>
1344                assert_eq!(&q.value()[1..], &public[..]),
1345            _ => unreachable!(),
1346        }
1347
1348        // PKESK
1349        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";
1350        let ciphertext = Ciphertext::ECDH{
1351            e: MPI::new(&eph_pubkey[..]),
1352            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()
1353        };
1354        let pkesk =
1355            PKESK3::new(None, PublicKeyAlgorithm::ECDH, ciphertext)?;
1356
1357        // Session key
1358        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";
1359
1360        let key = key.parts_into_secret().unwrap();
1361        let mut keypair = key.into_keypair()?;
1362        let (sym, got_dek) = pkesk.decrypt(&mut keypair, None).unwrap();
1363
1364        assert_eq!(sym, SymmetricAlgorithm::AES256);
1365        assert_eq!(&dek[..], &got_dek[..]);
1366        Ok(())
1367    }
1368
1369    #[test]
1370    fn import_rsa() {
1371        use crate::crypto::SessionKey;
1372        use self::mpi::{MPI, Ciphertext};
1373
1374        // RSA key
1375        let ctime =
1376            time::UNIX_EPOCH + time::Duration::new(1548950502, 0);
1377        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";
1378        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";
1379        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";
1380        let key: key::SecretKey
1381            = Key4::import_secret_rsa(&d[..], &p[..], &q[..], ctime)
1382            .unwrap().into();
1383
1384        // PKESK
1385        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";
1386        let ciphertext = Ciphertext::RSA{
1387            c: MPI::new(&c[..]),
1388        };
1389        let pkesk = PKESK3::new(Some(key.keyid()),
1390                                PublicKeyAlgorithm::RSAEncryptSign,
1391                                ciphertext).unwrap();
1392
1393        // Session key
1394        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";
1395        let sk = SessionKey::from(Vec::from(&dek[..]));
1396
1397        // Expected
1398        let mut decryptor = key.into_keypair().unwrap();
1399        let got_sk = pkesk.decrypt(&mut decryptor, None).unwrap();
1400        assert_eq!(got_sk.1, sk);
1401    }
1402
1403    #[test]
1404    fn import_ed25519() {
1405        use crate::types::SignatureType;
1406        use crate::packet::signature::Signature4;
1407        use crate::packet::signature::subpacket::{
1408            Subpacket, SubpacketValue, SubpacketArea};
1409
1410        // Ed25519 key
1411        let ctime =
1412            time::UNIX_EPOCH + time::Duration::new(1548249630, 0);
1413        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";
1414        let key: key::PublicKey
1415            = Key4::import_public_ed25519(q, ctime).unwrap().into();
1416
1417        let mut hashed = SubpacketArea::default();
1418        let mut unhashed = SubpacketArea::default();
1419        let fpr = "D81A 5DC0 DEBF EE5F 9AC8  20EB 6769 5DB9 920D 4FAC"
1420            .parse().unwrap();
1421        let kid = "6769 5DB9 920D 4FAC".parse().unwrap();
1422        let ctime = 1549460479.into();
1423        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";
1424        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";
1425
1426        hashed.add(Subpacket::new(SubpacketValue::IssuerFingerprint(fpr), false).unwrap()).unwrap();
1427        hashed.add(Subpacket::new(SubpacketValue::SignatureCreationTime(ctime), false).unwrap()).unwrap();
1428        unhashed.add(Subpacket::new(SubpacketValue::Issuer(kid), false).unwrap()).unwrap();
1429
1430        eprintln!("fpr: {}", key.fingerprint());
1431        let sig = Signature4::new(SignatureType::Binary, PublicKeyAlgorithm::EdDSA,
1432                                  HashAlgorithm::SHA256, hashed, unhashed,
1433                                  [0xa7,0x19],
1434                                  mpi::Signature::EdDSA{
1435                                      r: mpi::MPI::new(r), s: mpi::MPI::new(s)
1436                                  });
1437        let sig: Signature = sig.into();
1438        sig.verify_message(&key, b"Hello, World\n").unwrap();
1439    }
1440
1441    #[test]
1442    fn fingerprint_test() {
1443        let pile =
1444            PacketPile::from_bytes(crate::tests::key("public-key.gpg")).unwrap();
1445
1446        // The blob contains a public key and three subkeys.
1447        let mut pki = 0;
1448        let mut ski = 0;
1449
1450        let pks = [ "8F17777118A33DDA9BA48E62AACB3243630052D9" ];
1451        let sks = [ "C03FA6411B03AE12576461187223B56678E02528",
1452                    "50E6D924308DBF223CFB510AC2B819056C652598",
1453                    "2DC50AB55BE2F3B04C2D2CF8A3506AFB820ABD08"];
1454
1455        for p in pile.descendants() {
1456            if let &Packet::PublicKey(ref p) = p {
1457                let fp = p.fingerprint().to_hex();
1458                // eprintln!("PK: {:?}", fp);
1459
1460                assert!(pki < pks.len());
1461                assert_eq!(fp, pks[pki]);
1462                pki += 1;
1463            }
1464
1465            if let &Packet::PublicSubkey(ref p) = p {
1466                let fp = p.fingerprint().to_hex();
1467                // eprintln!("SK: {:?}", fp);
1468
1469                assert!(ski < sks.len());
1470                assert_eq!(fp, sks[ski]);
1471                ski += 1;
1472            }
1473        }
1474        assert!(pki == pks.len() && ski == sks.len());
1475    }
1476
1477    #[test]
1478    fn issue_617() -> Result<()> {
1479        use crate::serialize::MarshalInto;
1480        let p = Packet::from_bytes(&b"-----BEGIN PGP ARMORED FILE-----
1481
1482xcClBAAAAMUWBSuBBAAjAPDbS+Z6Ti+PouOV6c5Ypr3jn1w1Ih5GqikN5E29PGz+
1483CQMIoYc7R4YRiLr/ZJB/MW5M0kuuWyUirUKRkYCotB5omVE8fGtqW5wGCGf79Tzb
1484rKVmPl25CJdEabIfAOl0WwciipDx1tqNOOYEci/JWSbTEymEyCH9oQPObt2sdDxh
1485wLcBgsd/CVl3kuqiXFHNYDvWVBmUHeltS/J22Kfy/n1qD3CCBFooHGdc13KwtMLk
1486UPb5LTTqCk2ihQ7e+5u7EmueLUp1431HJiYa+olaPZ7caRNfQfggtHcfQOJdnWRJ
1487FN2nTDgLHX0cEOiMboZrS4S9xtjyVRLcRZcCIyeQF0Q889rq0lmxHG38XUeIj/3y
1488SJJNnZxmJtHNo+SZQ/gXhO9TzeeA6yQm2myQlRkXBtdQEz6mtznphWeWMkWApZpa
1489FwPoSAbbsLkNS/iNN2MDGAVYvezYn2QZ
1490=0cxs
1491-----END PGP ARMORED FILE-----"[..])?;
1492        let i: usize = 360;
1493        let mut buf = p.to_vec().unwrap();
1494        // Avoid first two bytes so that we don't change the
1495        // type and reduce the chance of changing the length.
1496        let bit = i.saturating_add(2 * 8) % (buf.len() * 8);
1497        buf[bit / 8] ^= 1 << (bit % 8);
1498        match Packet::from_bytes(&buf) {
1499            Ok(q) => {
1500                eprintln!("{:?}", p);
1501                eprintln!("{:?}", q);
1502                assert!(p != q);
1503            },
1504            Err(_) => unreachable!(),
1505        };
1506        Ok(())
1507    }
1508
1509    #[test]
1510    fn encrypt_huge_plaintext() -> Result<()> {
1511        let sk = crate::crypto::SessionKey::new(256).unwrap();
1512
1513        if PublicKeyAlgorithm::RSAEncryptSign.is_supported() {
1514            let rsa2k: Key<SecretParts, UnspecifiedRole> =
1515                Key4::generate_rsa(2048)?.into();
1516            assert!(matches!(
1517                rsa2k.encrypt(&sk).unwrap_err().downcast().unwrap(),
1518                crate::Error::InvalidArgument(_)
1519            ));
1520        }
1521
1522        if PublicKeyAlgorithm::ECDH.is_supported()
1523            && Curve::Cv25519.is_supported()
1524        {
1525            let cv25519: Key<SecretParts, UnspecifiedRole> =
1526                Key4::generate_ecc(false, Curve::Cv25519)?.into();
1527            assert!(matches!(
1528                cv25519.encrypt(&sk).unwrap_err().downcast().unwrap(),
1529                crate::Error::InvalidArgument(_)
1530            ));
1531        }
1532
1533        Ok(())
1534    }
1535
1536    #[test]
1537    fn cv25519_secret_is_reversed() -> Result<()> {
1538        use crate::crypto::backend::{Backend, interface::Asymmetric};
1539
1540        let (mut private_key, _) = Backend::x25519_generate_key()?;
1541        Backend::x25519_clamp_secret(&mut private_key);
1542
1543        let key: Key4<_, UnspecifiedRole> =
1544            Key4::import_secret_cv25519(&private_key, None, None, None)?;
1545        if let crate::packet::key::SecretKeyMaterial::Unencrypted(key) = key.secret() {
1546            key.map(|secret| {
1547                if let mpi::SecretKeyMaterial::ECDH { scalar } = secret {
1548                    let scalar_reversed = private_key.iter().copied().rev().collect::<Vec<u8>>();
1549                    let scalar_actual = &*scalar.value_padded(32);
1550                    assert_eq!(scalar_actual, scalar_reversed);
1551                } else {
1552                    unreachable!();
1553                }
1554            })
1555        } else {
1556            unreachable!();
1557        }
1558
1559        Ok(())
1560    }
1561
1562    #[test]
1563    fn ed25519_secret_is_not_reversed() {
1564        let private_key: &[u8] =
1565            &crate::crypto::SessionKey::new(32).unwrap();
1566        let key: Key4<_, UnspecifiedRole> = Key4::import_secret_ed25519(private_key, None).unwrap();
1567        if let crate::packet::key::SecretKeyMaterial::Unencrypted(key) = key.secret() {
1568            key.map(|secret| {
1569                if let mpi::SecretKeyMaterial::EdDSA { scalar } = secret {
1570                    assert_eq!(&*scalar.value_padded(32), private_key);
1571                } else {
1572                    unreachable!();
1573                }
1574            })
1575        } else {
1576            unreachable!();
1577        }
1578    }
1579
1580    #[test]
1581    fn issue_1016() {
1582        // The fingerprint is a function of the creation time,
1583        // algorithm, and public MPIs.  When we change them make sure
1584        // the fingerprint also changes.
1585
1586        let mut g = quickcheck::Gen::new(256);
1587
1588        let mut key = Key4::<PublicParts, UnspecifiedRole>::arbitrary(&mut g);
1589        let fpr1 = key.fingerprint();
1590        if key.creation_time() == UNIX_EPOCH {
1591            key.set_creation_time(UNIX_EPOCH + Duration::new(1, 0)).expect("ok");
1592        } else {
1593            key.set_creation_time(UNIX_EPOCH).expect("ok");
1594        }
1595        assert_ne!(fpr1, key.fingerprint());
1596
1597        let mut key = Key4::<PublicParts, UnspecifiedRole>::arbitrary(&mut g);
1598        let fpr1 = key.fingerprint();
1599        key.set_pk_algo(PublicKeyAlgorithm::from(u8::from(key.pk_algo()) + 1));
1600        assert_ne!(fpr1, key.fingerprint());
1601
1602        let mut key = Key4::<PublicParts, UnspecifiedRole>::arbitrary(&mut g);
1603        let fpr1 = key.fingerprint();
1604        loop {
1605            let mpis2 = mpi::PublicKey::arbitrary(&mut g);
1606            if key.mpis() != &mpis2 {
1607                *key.mpis_mut() = mpis2;
1608                break;
1609            }
1610        }
1611        assert_ne!(fpr1, key.fingerprint());
1612
1613        let mut key = Key4::<PublicParts, UnspecifiedRole>::arbitrary(&mut g);
1614        let fpr1 = key.fingerprint();
1615        loop {
1616            let mpis2 = mpi::PublicKey::arbitrary(&mut g);
1617            if key.mpis() != &mpis2 {
1618                key.set_mpis(mpis2);
1619                break;
1620            }
1621        }
1622        assert_ne!(fpr1, key.fingerprint());
1623    }
1624
1625    /// Smoke test for ECC key creation, signing and verification, and
1626    /// encryption and decryption.
1627    #[test]
1628    fn ecc_support() -> Result<()> {
1629        for for_signing in [true, false] {
1630            for curve in Curve::variants()
1631                .filter(Curve::is_supported)
1632            {
1633                match curve {
1634                    Curve::Cv25519 if for_signing => continue,
1635                    Curve::Ed25519 if ! for_signing => continue,
1636                    _ => (),
1637                }
1638
1639                eprintln!("curve {}, for signing {:?}", curve, for_signing);
1640                let key: Key<SecretParts, UnspecifiedRole> =
1641                    Key4::generate_ecc(for_signing, curve.clone())?.into();
1642                let mut pair = key.into_keypair()?;
1643
1644                if for_signing {
1645                    use crate::crypto::Signer;
1646                    let hash = HashAlgorithm::default();
1647                    let digest = hash.context()?
1648                        .for_signature(pair.public().version())
1649                        .into_digest()?;
1650                    let sig = pair.sign(hash, &digest)?;
1651                    pair.public().verify(&sig, hash, &digest)?;
1652                } else {
1653                    use crate::crypto::{SessionKey, Decryptor};
1654                    let sk = SessionKey::new(32).unwrap();
1655                    let ciphertext = pair.public().encrypt(&sk)?;
1656                    assert_eq!(pair.decrypt(&ciphertext, Some(sk.len()))?, sk);
1657                }
1658            }
1659        }
1660        Ok(())
1661    }
1662
1663    #[test]
1664    fn ecc_encoding() -> Result<()> {
1665        for for_signing in [true, false] {
1666            for curve in Curve::variants()
1667                .filter(Curve::is_supported)
1668            {
1669                match curve {
1670                    Curve::Cv25519 if for_signing => continue,
1671                    Curve::Ed25519 if ! for_signing => continue,
1672                    _ => (),
1673                }
1674
1675                use crate::crypto::mpi::{Ciphertext, MPI, PublicKey};
1676                eprintln!("curve {}, for signing {:?}", curve, for_signing);
1677
1678                let key: Key<SecretParts, UnspecifiedRole> =
1679                    Key4::generate_ecc(for_signing, curve.clone())?.into();
1680
1681                let compressed = |mpi: &MPI| mpi.value()[0] == 0x40;
1682                let uncompressed = |mpi: &MPI| mpi.value()[0] == 0x04;
1683
1684                match key.mpis() {
1685                    PublicKey::ECDSA { curve: c, q } if for_signing => {
1686                        assert!(c == &curve);
1687                        assert!(uncompressed(q));
1688                    },
1689                    PublicKey::EdDSA { curve: c, q } if for_signing => {
1690                        assert!(c == &curve);
1691                        assert!(compressed(q));
1692                    },
1693                    PublicKey::ECDH { curve: c, q, .. } if ! for_signing => {
1694                        assert!(c == &curve);
1695                        if curve == Curve::Cv25519 {
1696                            assert!(compressed(q));
1697                        } else {
1698                            assert!(uncompressed(q));
1699                        }
1700
1701                        use crate::crypto::SessionKey;
1702                        let sk = SessionKey::new(32).unwrap();
1703                        let ciphertext = key.encrypt(&sk)?;
1704                        if let Ciphertext::ECDH { e, .. } = &ciphertext {
1705                            if curve == Curve::Cv25519 {
1706                                assert!(compressed(e));
1707                            } else {
1708                                assert!(uncompressed(e));
1709                            }
1710                        } else {
1711                            panic!("unexpected ciphertext: {:?}", ciphertext);
1712                        }
1713                    },
1714                    mpi => unreachable!(
1715                        "curve {}, mpi {:?}, for signing {:?}",
1716                        curve, mpi, for_signing),
1717                }
1718            }
1719        }
1720        Ok(())
1721    }
1722}