diff options
author | Justus Winter <justus@sequoia-pgp.org> | 2019-05-28 22:21:12 +0200 |
---|---|---|
committer | Justus Winter <justus@sequoia-pgp.org> | 2019-05-30 12:09:47 +0200 |
commit | a0378343f6f0d311021437435c14670a6d7dc3e2 (patch) | |
tree | 796e209906a13d14341edc0587100b08a8162f76 | |
parent | 6ce1f915a0de8b2db46ef4d724d54459fc0fde37 (diff) |
openpgp: New trait crypto::Decryptor.
-rw-r--r-- | openpgp/src/crypto/asymmetric.rs | 63 | ||||
-rw-r--r-- | openpgp/src/crypto/mod.rs | 1 |
2 files changed, 64 insertions, 0 deletions
diff --git a/openpgp/src/crypto/asymmetric.rs b/openpgp/src/crypto/asymmetric.rs index 74764cb9..7bc293d3 100644 --- a/openpgp/src/crypto/asymmetric.rs +++ b/openpgp/src/crypto/asymmetric.rs @@ -3,6 +3,7 @@ use nettle::{dsa, ecc, ecdsa, ed25519, rsa, Yarrow}; use packet::Key; +use crypto::SessionKey; use crypto::mpis::{self, MPI}; use constants::{Curve, HashAlgorithm}; @@ -24,6 +25,21 @@ pub trait Signer { -> Result<mpis::Signature>; } +/// Decrypts a message. +/// +/// This is a low-level mechanism to decrypt an arbitrary OpenPGP +/// ciphertext. Using this trait allows Sequoia to perform all +/// operations involving decryption to use a variety of secret key +/// storage mechanisms (e.g. smart cards). +pub trait Decryptor { + /// Returns a reference to the public key. + fn public(&self) -> &Key; + + /// Creates a signature over the `digest` produced by `hash_algo`. + fn decrypt(&mut self, ciphertext: &mpis::Ciphertext) + -> Result<SessionKey>; +} + /// A cryptographic key pair. /// /// A `KeyPair` is a combination of public and secret key. If both @@ -183,3 +199,50 @@ impl Signer for KeyPair { } } } + +impl Decryptor for KeyPair { + fn public(&self) -> &Key { + &self.public + } + + /// Creates a signature over the `digest` produced by `hash_algo`. + fn decrypt(&mut self, ciphertext: &mpis::Ciphertext) + -> Result<SessionKey> + { + use PublicKeyAlgorithm::*; + use crypto::mpis::PublicKey; + use nettle::rsa; + + Ok(match (self.public.mpis(), &self.secret, ciphertext) + { + (PublicKey::RSA{ ref e, ref n }, + mpis::SecretKey::RSA{ ref p, ref q, ref d, .. }, + mpis::Ciphertext::RSA{ ref c }) => { + let public = rsa::PublicKey::new(&n.value, &e.value)?; + let secret = rsa::PrivateKey::new(&d.value, &p.value, + &q.value, Option::None)?; + let mut rand = Yarrow::default(); + rsa::decrypt_pkcs1(&public, &secret, &mut rand, &c.value)? + } + + (PublicKey::Elgamal{ .. }, + mpis::SecretKey::Elgamal{ .. }, + mpis::Ciphertext::Elgamal{ .. }) => + return Err( + Error::UnsupportedPublicKeyAlgorithm(ElgamalEncrypt).into()), + + (PublicKey::ECDH{ .. }, + mpis::SecretKey::ECDH { .. }, + mpis::Ciphertext::ECDH { .. }) => + ::crypto::ecdh::unwrap_session_key(&self.public, + &self.secret, + ciphertext)?, + + (public, secret, ciphertext) => + return Err(Error::MalformedPacket(format!( + "unsupported combination of key pair {:?}/{:?} \ + and ciphertext {:?}", + public, secret, ciphertext)).into()), + }.into()) + } +} diff --git a/openpgp/src/crypto/mod.rs b/openpgp/src/crypto/mod.rs index e75e4ccb..a31b60e9 100644 --- a/openpgp/src/crypto/mod.rs +++ b/openpgp/src/crypto/mod.rs @@ -23,6 +23,7 @@ pub(crate) mod symmetric; pub use self::asymmetric::{ Signer, + Decryptor, KeyPair, }; |