sequoia_openpgp/crypto/backend/nettle/
asymmetric.rs

1//! Hold the implementation of [`Signer`] and [`Decryptor`] for [`KeyPair`].
2//!
3//! [`Signer`]: crate::crypto::Signer
4//! [`Decryptor`]: crate::crypto::Decryptor
5//! [`KeyPair`]: crate::crypto::KeyPair
6
7use nettle::{
8    curve25519,
9    curve448,
10    dsa,
11    ecc,
12    ecdh,
13    ecdsa,
14    ed25519,
15    ed448,
16    rsa,
17    random::Yarrow,
18};
19
20use crate::{Error, Result};
21
22use crate::packet::{key, Key};
23use crate::crypto::asymmetric::KeyPair;
24use crate::crypto::backend::interface::Asymmetric;
25use crate::crypto::mpi::{self, MPI, ProtectedMPI, PublicKey};
26use crate::crypto::{
27    SessionKey,
28    mem::Protected,
29};
30use crate::types::{Curve, HashAlgorithm};
31
32impl Asymmetric for super::Backend {
33    fn supports_algo(algo: PublicKeyAlgorithm) -> bool {
34        use PublicKeyAlgorithm::*;
35        #[allow(deprecated)]
36        match algo {
37            X25519 | Ed25519 |
38            RSAEncryptSign | RSAEncrypt | RSASign | DSA | ECDH | ECDSA | EdDSA
39                => true,
40            X448 | Ed448
41                => curve448::IS_SUPPORTED,
42            ElGamalEncrypt | ElGamalEncryptSign | Private(_) | Unknown(_)
43                => false,
44        }
45    }
46
47    fn supports_curve(curve: &Curve) -> bool {
48        use Curve::*;
49        match curve {
50            NistP256 | NistP384 | NistP521 | Ed25519 | Cv25519
51                => true,
52            BrainpoolP256 | BrainpoolP384 | BrainpoolP512 | Unknown(_)
53                => false,
54        }
55    }
56
57    fn x25519_generate_key() -> Result<(Protected, [u8; 32])> {
58        debug_assert_eq!(curve25519::CURVE25519_SIZE, 32);
59        let mut rng = Yarrow::default();
60        let secret = curve25519::private_key(&mut rng);
61        let mut public = [0; 32];
62        curve25519::mul_g(&mut public, &secret)?;
63        Ok((secret.into(), public))
64    }
65
66    fn x25519_derive_public(secret: &Protected) -> Result<[u8; 32]> {
67        debug_assert_eq!(curve25519::CURVE25519_SIZE, 32);
68        let mut public = [0; 32];
69        curve25519::mul_g(&mut public, secret)?;
70        Ok(public)
71    }
72
73    fn x25519_shared_point(secret: &Protected, public: &[u8; 32])
74                           -> Result<Protected> {
75        debug_assert_eq!(curve25519::CURVE25519_SIZE, 32);
76        let mut s: Protected = vec![0; 32].into();
77        curve25519::mul(&mut s, secret, public)?;
78        Ok(s)
79    }
80
81    fn x448_generate_key() -> Result<(Protected, [u8; 56])> {
82        debug_assert_eq!(curve448::CURVE448_SIZE, 56);
83        if ! curve448::IS_SUPPORTED {
84            return Err(Error::UnsupportedPublicKeyAlgorithm(
85                PublicKeyAlgorithm::Ed448).into());
86        }
87        let mut rng = Yarrow::default();
88        let secret = curve448::private_key(&mut rng);
89        let mut public = [0; 56];
90        curve448::mul_g(&mut public, &secret)?;
91        Ok((secret.into(), public))
92    }
93
94    fn x448_derive_public(secret: &Protected) -> Result<[u8; 56]> {
95        debug_assert_eq!(curve448::CURVE448_SIZE, 56);
96        if ! curve448::IS_SUPPORTED {
97            return Err(Error::UnsupportedPublicKeyAlgorithm(
98                PublicKeyAlgorithm::Ed448).into());
99        }
100        let mut public = [0; 56];
101        curve448::mul_g(&mut public, secret)?;
102        Ok(public)
103    }
104
105    fn x448_shared_point(secret: &Protected, public: &[u8; 56])
106                           -> Result<Protected> {
107        debug_assert_eq!(curve448::CURVE448_SIZE, 56);
108        if ! curve448::IS_SUPPORTED {
109            return Err(Error::UnsupportedPublicKeyAlgorithm(
110                PublicKeyAlgorithm::Ed448).into());
111        }
112        let mut s: Protected = vec![0; 56].into();
113        curve448::mul(&mut s, secret, public)?;
114        Ok(s)
115    }
116
117    fn ed25519_generate_key() -> Result<(Protected, [u8; 32])> {
118        debug_assert_eq!(ed25519::ED25519_KEY_SIZE, 32);
119        let mut rng = Yarrow::default();
120        let mut public = [0; 32];
121        let secret: Protected =
122            ed25519::private_key(&mut rng).into();
123        ed25519::public_key(&mut public, &secret)?;
124        Ok((secret, public))
125    }
126
127    fn ed25519_derive_public(secret: &Protected) -> Result<[u8; 32]> {
128        debug_assert_eq!(ed25519::ED25519_KEY_SIZE, 32);
129        let mut public = [0; 32];
130        ed25519::public_key(&mut public, secret)?;
131        Ok(public)
132    }
133
134    fn ed25519_sign(secret: &Protected, public: &[u8; 32], digest: &[u8])
135                    -> Result<[u8; 64]> {
136        debug_assert_eq!(ed25519::ED25519_KEY_SIZE, 32);
137        debug_assert_eq!(ed25519::ED25519_SIGNATURE_SIZE, 64);
138        let mut sig = [0u8; 64];
139        ed25519::sign(public, secret, digest, &mut sig)?;
140        Ok(sig)
141    }
142
143    fn ed25519_verify(public: &[u8; 32], digest: &[u8], signature: &[u8; 64])
144                      -> Result<bool> {
145        debug_assert_eq!(ed25519::ED25519_KEY_SIZE, 32);
146        debug_assert_eq!(ed25519::ED25519_SIGNATURE_SIZE, 64);
147        Ok(ed25519::verify(public, digest, signature)?)
148    }
149
150    fn ed448_generate_key() -> Result<(Protected, [u8; 57])> {
151        debug_assert_eq!(ed448::ED448_KEY_SIZE, 57);
152        let mut rng = Yarrow::default();
153        let mut public = [0; 57];
154        let secret: Protected =
155            ed448::private_key(&mut rng).into();
156        ed448::public_key(&mut public, &secret)?;
157        Ok((secret, public))
158    }
159
160    fn ed448_derive_public(secret: &Protected) -> Result<[u8; 57]> {
161        debug_assert_eq!(ed448::ED448_KEY_SIZE, 57);
162        let mut public = [0; 57];
163        ed448::public_key(&mut public, secret)?;
164        Ok(public)
165    }
166
167    fn ed448_sign(secret: &Protected, public: &[u8; 57], digest: &[u8])
168                    -> Result<[u8; 114]> {
169        debug_assert_eq!(ed448::ED448_KEY_SIZE, 57);
170        debug_assert_eq!(ed448::ED448_SIGNATURE_SIZE, 114);
171        let mut sig = [0u8; 114];
172        ed448::sign(public, secret, digest, &mut sig)?;
173        Ok(sig)
174    }
175
176    fn ed448_verify(public: &[u8; 57], digest: &[u8], signature: &[u8; 114])
177                      -> Result<bool> {
178        debug_assert_eq!(ed448::ED448_KEY_SIZE, 57);
179        debug_assert_eq!(ed448::ED448_SIGNATURE_SIZE, 114);
180        Ok(ed448::verify(public, digest, signature)?)
181    }
182
183    fn dsa_generate_key(p_bits: usize)
184                        -> Result<(MPI, MPI, MPI, MPI, ProtectedMPI)>
185    {
186        let mut rng = Yarrow::default();
187        let q_bits = if p_bits <= 1024 { 160 } else { 256 };
188        let params = dsa::Params::generate(&mut rng, p_bits, q_bits)?;
189        let (p, q) = params.primes();
190        let g = params.g();
191        let (y, x) = dsa::generate_keypair(&params, &mut rng);
192        Ok((p.into(), q.into(), g.into(), y.as_bytes().into(),
193            x.as_bytes().into()))
194    }
195
196    fn dsa_sign(x: &ProtectedMPI,
197                p: &MPI, q: &MPI, g: &MPI, _y: &MPI,
198                digest: &[u8])
199                -> Result<(MPI, MPI)>
200    {
201        let mut rng = Yarrow::default();
202        let params = dsa::Params::new(p.value(), q.value(), g.value());
203        let secret = dsa::PrivateKey::new(x.value());
204
205        let sig = dsa::sign(&params, &secret, digest, &mut rng)?;
206
207        Ok((MPI::new(&sig.r()), MPI::new(&sig.s())))
208    }
209
210    fn dsa_verify(p: &MPI, q: &MPI, g: &MPI, y: &MPI,
211                  digest: &[u8],
212                  r: &MPI, s: &MPI)
213                  -> Result<bool>
214    {
215        let key = dsa::PublicKey::new(y.value());
216        let params = dsa::Params::new(p.value(), q.value(), g.value());
217        let signature = dsa::Signature::new(r.value(), s.value());
218        Ok(dsa::verify(&params, &key, digest, &signature))
219    }
220}
221
222impl KeyPair {
223    pub(crate) fn sign_backend(&self,
224                               secret: &mpi::SecretKeyMaterial,
225                               hash_algo: HashAlgorithm,
226                               digest: &[u8])
227                               -> Result<mpi::Signature>
228    {
229        use crate::PublicKeyAlgorithm::*;
230
231        let mut rng = Yarrow::default();
232
233        #[allow(deprecated)]
234        match (self.public().pk_algo(), self.public().mpis(), secret)
235        {
236            (RSASign,
237             &PublicKey::RSA { ref e, ref n },
238             &mpi::SecretKeyMaterial::RSA { ref p, ref q, ref d, .. }) |
239            (RSAEncryptSign,
240             &PublicKey::RSA { ref e, ref n },
241             &mpi::SecretKeyMaterial::RSA { ref p, ref q, ref d, .. }) => {
242                let public = rsa::PublicKey::new(n.value(), e.value())?;
243                let secret = rsa::PrivateKey::new(d.value(), p.value(),
244                                                  q.value(), Option::None)?;
245
246                // The signature has the length of the modulus.
247                let mut sig = vec![0u8; n.value().len()];
248
249                // As described in [Section 5.2.2 and 5.2.3 of RFC 9580],
250                // to verify the signature, we need to encode the
251                // signature data in a PKCS1-v1.5 packet.
252                //
253                //   [Section 5.2.2 and 5.2.3 of RFC 9580]:
254                //   https://www.rfc-editor.org/rfc/rfc9580.html#section-5.2.2
255                rsa::sign_digest_pkcs1(&public, &secret, digest,
256                                       hash_algo.oid()?,
257                                       &mut rng, &mut sig)?;
258
259                Ok(mpi::Signature::RSA {
260                    s: MPI::new(&sig),
261                })
262            },
263
264            (ECDSA,
265             &PublicKey::ECDSA { ref curve, .. },
266             &mpi::SecretKeyMaterial::ECDSA { ref scalar }) => {
267                let secret = match curve {
268                    Curve::NistP256 =>
269                        ecc::Scalar::new::<ecc::Secp256r1>(
270                            scalar.value())?,
271                    Curve::NistP384 =>
272                        ecc::Scalar::new::<ecc::Secp384r1>(
273                            scalar.value())?,
274                    Curve::NistP521 =>
275                        ecc::Scalar::new::<ecc::Secp521r1>(
276                            scalar.value())?,
277                    _ =>
278                        return Err(
279                            Error::UnsupportedEllipticCurve(curve.clone())
280                                .into()),
281                };
282
283                let sig = ecdsa::sign(&secret, digest, &mut rng);
284
285                Ok(mpi::Signature::ECDSA {
286                    r: MPI::new(&sig.r()),
287                    s: MPI::new(&sig.s()),
288                })
289            },
290
291            (pk_algo, _, _) => Err(Error::InvalidOperation(format!(
292                "unsupported combination of algorithm {:?}, key {:?}, \
293                 and secret key {:?}",
294                pk_algo, self.public(), self.secret())).into()),
295        }
296    }
297}
298
299impl KeyPair {
300    pub(crate) fn decrypt_backend(&self, secret: &mpi::SecretKeyMaterial, ciphertext: &mpi::Ciphertext,
301               plaintext_len: Option<usize>)
302               -> Result<SessionKey>
303    {
304        use crate::PublicKeyAlgorithm::*;
305
306        Ok(match (self.public().mpis(), secret, ciphertext) {
307            (PublicKey::RSA{ ref e, ref n },
308             mpi::SecretKeyMaterial::RSA{ ref p, ref q, ref d, .. },
309             mpi::Ciphertext::RSA{ ref c }) => {
310                let public = rsa::PublicKey::new(n.value(), e.value())?;
311                let secret = rsa::PrivateKey::new(d.value(), p.value(),
312                                                  q.value(), Option::None)?;
313                let mut rand = Yarrow::default();
314                if let Some(l) = plaintext_len {
315                    let mut plaintext: SessionKey = vec![0; l].into();
316                    rsa::decrypt_pkcs1(&public, &secret, &mut rand,
317                                       c.value(), plaintext.as_mut())?;
318                    plaintext
319                } else {
320                    rsa::decrypt_pkcs1_insecure(&public, &secret,
321                                                &mut rand, c.value())?
322                    .into()
323                }
324            }
325
326            (PublicKey::ElGamal{ .. },
327             mpi::SecretKeyMaterial::ElGamal{ .. },
328             mpi::Ciphertext::ElGamal{ .. }) => {
329                #[allow(deprecated)]
330                return Err(
331                    Error::UnsupportedPublicKeyAlgorithm(ElGamalEncrypt).into());
332            },
333
334            (PublicKey::ECDH{ .. },
335             mpi::SecretKeyMaterial::ECDH { .. },
336             mpi::Ciphertext::ECDH { .. }) =>
337                crate::crypto::ecdh::decrypt(self.public(), secret, ciphertext,
338                                             plaintext_len)?,
339
340            (public, secret, ciphertext) =>
341                return Err(Error::InvalidOperation(format!(
342                    "unsupported combination of key pair {:?}/{:?} \
343                     and ciphertext {:?}",
344                    public, secret, ciphertext)).into()),
345        })
346    }
347}
348
349
350impl<P: key::KeyParts, R: key::KeyRole> Key<P, R> {
351    /// Encrypts the given data with this key.
352    pub(crate) fn encrypt_backend(&self, data: &SessionKey) -> Result<mpi::Ciphertext> {
353        use crate::PublicKeyAlgorithm::*;
354
355        #[allow(deprecated)]
356        match self.pk_algo() {
357            RSAEncryptSign | RSAEncrypt => {
358                // Extract the public recipient.
359                match self.mpis() {
360                    mpi::PublicKey::RSA { e, n } => {
361                        // The ciphertext has the length of the modulus.
362                        let ciphertext_len = n.value().len();
363                        if data.len() + 11 > ciphertext_len {
364                            return Err(Error::InvalidArgument(
365                                "Plaintext data too large".into()).into());
366                        }
367
368                        let mut esk = vec![0u8; ciphertext_len];
369                        let mut rng = Yarrow::default();
370                        let pk = rsa::PublicKey::new(n.value(), e.value())?;
371                        rsa::encrypt_pkcs1(&pk, &mut rng, data,
372                                           &mut esk)?;
373                        Ok(mpi::Ciphertext::RSA {
374                            c: MPI::new(&esk),
375                        })
376                    },
377                    pk => {
378                        Err(Error::MalformedPacket(
379                            format!(
380                                "Key: Expected RSA public key, got {:?}",
381                                pk)).into())
382                    },
383                }
384            },
385
386            ECDH => crate::crypto::ecdh::encrypt(self.parts_as_public(),
387                                                 data),
388
389            RSASign | DSA | ECDSA | EdDSA | Ed25519 | Ed448 =>
390                Err(Error::InvalidOperation(
391                    format!("{} is not an encryption algorithm", self.pk_algo())
392                ).into()),
393
394            X25519 | // Handled in common code.
395            X448 | // Handled in common code.
396            ElGamalEncrypt | ElGamalEncryptSign |
397            Private(_) | Unknown(_) =>
398                Err(Error::UnsupportedPublicKeyAlgorithm(self.pk_algo()).into()),
399        }
400    }
401
402    /// Verifies the given signature.
403    pub(crate) fn verify_backend(&self, sig: &mpi::Signature, hash_algo: HashAlgorithm,
404                  digest: &[u8]) -> Result<()>
405    {
406        use crate::crypto::mpi::Signature;
407
408        let ok = match (self.mpis(), sig) {
409            (PublicKey::RSA { e, n }, Signature::RSA { s }) => {
410                let key = rsa::PublicKey::new(n.value(), e.value())?;
411
412                // As described in [Section 5.2.2 and 5.2.3 of RFC 9580],
413                // to verify the signature, we need to encode the
414                // signature data in a PKCS1-v1.5 packet.
415                //
416                //   [Section 5.2.2 and 5.2.3 of RFC 9580]:
417                //   https://www.rfc-editor.org/rfc/rfc9580.html#section-5.2.2
418                rsa::verify_digest_pkcs1(&key, digest, hash_algo.oid()?,
419                                         s.value())?
420            },
421            (PublicKey::ECDSA { curve, q }, Signature::ECDSA { s, r }) =>
422            {
423                let (x, y) = q.decode_point(curve)?;
424                let key = match curve {
425                    Curve::NistP256 => ecc::Point::new::<ecc::Secp256r1>(x, y)?,
426                    Curve::NistP384 => ecc::Point::new::<ecc::Secp384r1>(x, y)?,
427                    Curve::NistP521 => ecc::Point::new::<ecc::Secp521r1>(x, y)?,
428                    _ => return Err(
429                        Error::UnsupportedEllipticCurve(curve.clone()).into()),
430                };
431
432                let signature = dsa::Signature::new(r.value(), s.value());
433                ecdsa::verify(&key, digest, &signature)
434            },
435            _ => return Err(Error::MalformedPacket(format!(
436                "unsupported combination of key {} and signature {:?}.",
437                self.pk_algo(), sig)).into()),
438        };
439
440        if ok {
441            Ok(())
442        } else {
443            Err(Error::ManipulatedMessage.into())
444        }
445    }
446}
447
448use std::time::SystemTime;
449use crate::packet::key::{Key4, SecretParts};
450use crate::types::PublicKeyAlgorithm;
451
452impl<R> Key4<SecretParts, R>
453    where R: key::KeyRole,
454{
455    /// Creates a new OpenPGP secret key packet for an existing RSA key.
456    ///
457    /// The RSA key will use the secret exponent `d`, derived from the
458    /// secret primes `p` and `q`.  The key will have its creation
459    /// date set to `ctime` or the current time if `None` is given.
460    pub fn import_secret_rsa<T>(d: &[u8], p: &[u8], q: &[u8], ctime: T)
461        -> Result<Self> where T: Into<Option<SystemTime>>
462    {
463        let sec = rsa::PrivateKey::new(d, p, q, None)?;
464        let key = sec.public_key()?;
465        let (a, b, c) = sec.as_rfc4880();
466
467        Self::with_secret(
468            ctime.into().unwrap_or_else(crate::now),
469            PublicKeyAlgorithm::RSAEncryptSign,
470            mpi::PublicKey::RSA {
471                e: mpi::MPI::new(&key.e()[..]),
472                n: mpi::MPI::new(&key.n()[..]),
473            },
474            mpi::SecretKeyMaterial::RSA {
475                d: d.into(),
476                p: a.into(),
477                q: b.into(),
478                u: c.into(),
479            }.into())
480    }
481
482    /// Generates a new RSA key with a public modulus of size `bits`.
483    pub fn generate_rsa(bits: usize) -> Result<Self> {
484        let mut rng = Yarrow::default();
485
486        let (public, private) = rsa::generate_keypair(&mut rng, bits as u32)?;
487        let (p, q, u) = private.as_rfc4880();
488        let public_mpis = PublicKey::RSA {
489            e: MPI::new(&*public.e()),
490            n: MPI::new(&*public.n()),
491        };
492        let private_mpis = mpi::SecretKeyMaterial::RSA {
493            d: private.d().into(),
494            p: p.into(),
495            q: q.into(),
496            u: u.into(),
497        };
498
499        Self::with_secret(
500            crate::now(),
501            PublicKeyAlgorithm::RSAEncryptSign,
502            public_mpis,
503            private_mpis.into())
504    }
505
506    /// Generates a new ECC key over `curve`.
507    ///
508    /// If `for_signing` is false a ECDH key, if it's true either a
509    /// EdDSA or ECDSA key is generated.  Giving `for_signing == true` and
510    /// `curve == Cv25519` will produce an error. Likewise
511    /// `for_signing == false` and `curve == Ed25519` will produce an error.
512    pub(crate) fn generate_ecc_backend(for_signing: bool, curve: Curve)
513                                       -> Result<(PublicKeyAlgorithm,
514                                                  mpi::PublicKey,
515                                                  mpi::SecretKeyMaterial)>
516    {
517        let mut rng = Yarrow::default();
518
519        match (curve.clone(), for_signing) {
520            (Curve::Ed25519, true) =>
521                unreachable!("handled in Key4::generate_ecc"),
522
523            (Curve::Cv25519, false) =>
524                unreachable!("handled in Key4::generate_ecc"),
525
526            (Curve::NistP256, true)  | (Curve::NistP384, true)
527            | (Curve::NistP521, true) => {
528                let (public, private, field_sz) = match curve {
529                    Curve::NistP256 => {
530                        let (pu, sec) =
531                            ecdsa::generate_keypair::<ecc::Secp256r1, _>(&mut rng)?;
532                        (pu, sec, 256)
533                    }
534                    Curve::NistP384 => {
535                        let (pu, sec) =
536                            ecdsa::generate_keypair::<ecc::Secp384r1, _>(&mut rng)?;
537                        (pu, sec, 384)
538                    }
539                    Curve::NistP521 => {
540                        let (pu, sec) =
541                            ecdsa::generate_keypair::<ecc::Secp521r1, _>(&mut rng)?;
542                        (pu, sec, 521)
543                    }
544                    _ => unreachable!(),
545                };
546                let (pub_x, pub_y) = public.as_bytes();
547                let public_mpis =  mpi::PublicKey::ECDSA{
548                    curve,
549                    q: MPI::new_point(&pub_x, &pub_y, field_sz),
550                };
551                let private_mpis = mpi::SecretKeyMaterial::ECDSA{
552                    scalar: private.as_bytes().into(),
553                };
554
555                Ok((PublicKeyAlgorithm::ECDSA, public_mpis, private_mpis))
556            }
557
558            (Curve::NistP256, false)  | (Curve::NistP384, false)
559            | (Curve::NistP521, false) => {
560                    let (private, field_sz) = match curve {
561                        Curve::NistP256 => {
562                            let pv =
563                                ecc::Scalar::new_random::<ecc::Secp256r1, _>(&mut rng);
564
565                            (pv, 256)
566                        }
567                        Curve::NistP384 => {
568                            let pv =
569                                ecc::Scalar::new_random::<ecc::Secp384r1, _>(&mut rng);
570
571                            (pv, 384)
572                        }
573                        Curve::NistP521 => {
574                            let pv =
575                                ecc::Scalar::new_random::<ecc::Secp521r1, _>(&mut rng);
576
577                            (pv, 521)
578                        }
579                        _ => unreachable!(),
580                    };
581                    let public = ecdh::point_mul_g(&private);
582                    let (pub_x, pub_y) = public.as_bytes();
583                    let public_mpis = mpi::PublicKey::ECDH{
584                        q: MPI::new_point(&pub_x, &pub_y, field_sz),
585                        hash:
586                        crate::crypto::ecdh::default_ecdh_kdf_hash(&curve),
587                        sym:
588                        crate::crypto::ecdh::default_ecdh_kek_cipher(&curve),
589                        curve,
590                    };
591                    let private_mpis = mpi::SecretKeyMaterial::ECDH{
592                        scalar: private.as_bytes().into(),
593                    };
594
595                    Ok((PublicKeyAlgorithm::ECDH, public_mpis, private_mpis))
596                }
597
598            _ => Err(Error::UnsupportedEllipticCurve(curve).into()),
599        }
600    }
601}