summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJustus Winter <justus@sequoia-pgp.org>2019-05-28 22:21:12 +0200
committerJustus Winter <justus@sequoia-pgp.org>2019-05-30 12:09:47 +0200
commita0378343f6f0d311021437435c14670a6d7dc3e2 (patch)
tree796e209906a13d14341edc0587100b08a8162f76
parent6ce1f915a0de8b2db46ef4d724d54459fc0fde37 (diff)
openpgp: New trait crypto::Decryptor.
-rw-r--r--openpgp/src/crypto/asymmetric.rs63
-rw-r--r--openpgp/src/crypto/mod.rs1
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,
};