From 3646644294ed07a5731168ec4a0a9361e39e6793 Mon Sep 17 00:00:00 2001 From: Justus Winter Date: Fri, 12 May 2023 15:17:10 +0200 Subject: openpgp: Introduce a common public facade for public key operations. --- openpgp/src/crypto/asymmetric.rs | 38 ++++++++++++++++++++++ openpgp/src/crypto/backend/botan/asymmetric.rs | 40 +++++++++-------------- openpgp/src/crypto/backend/cng/asymmetric.rs | 41 ++++++++++-------------- openpgp/src/crypto/backend/nettle/asymmetric.rs | 40 +++++++++-------------- openpgp/src/crypto/backend/openssl/asymmetric.rs | 40 ++++++++++------------- openpgp/src/crypto/backend/rust/asymmetric.rs | 33 ++++++++----------- openpgp/src/packet/key.rs | 17 ++++++++++ 7 files changed, 135 insertions(+), 114 deletions(-) diff --git a/openpgp/src/crypto/asymmetric.rs b/openpgp/src/crypto/asymmetric.rs index 8f401a17..936f292c 100644 --- a/openpgp/src/crypto/asymmetric.rs +++ b/openpgp/src/crypto/asymmetric.rs @@ -209,3 +209,41 @@ impl From for Key { key.add_secret(secret.into()).0 } } + +impl Signer for KeyPair { + fn public(&self) -> &Key { + KeyPair::public(self) + } + + fn sign(&mut self, hash_algo: HashAlgorithm, digest: &[u8]) + -> Result + { + self.secret().map(|secret| { + #[allow(clippy::match_single_binding)] + match (self.public().pk_algo(), self.public().mpis(), secret) { + (_algo, _public, secret) => + self.sign_backend(secret, hash_algo, digest), + } + }) + } +} + +impl Decryptor for KeyPair { + fn public(&self) -> &Key { + KeyPair::public(self) + } + + fn decrypt(&mut self, + ciphertext: &mpi::Ciphertext, + plaintext_len: Option) + -> Result + { + self.secret().map(|secret| { + #[allow(clippy::match_single_binding)] + match (self.public().mpis(), secret, ciphertext) { + (_public, secret, _ciphertext) => + self.decrypt_backend(secret, ciphertext, plaintext_len), + } + }) + } +} diff --git a/openpgp/src/crypto/backend/botan/asymmetric.rs b/openpgp/src/crypto/backend/botan/asymmetric.rs index 265b83f7..ba2f0c96 100644 --- a/openpgp/src/crypto/backend/botan/asymmetric.rs +++ b/openpgp/src/crypto/backend/botan/asymmetric.rs @@ -16,7 +16,7 @@ use crate::{ Error, Result, crypto::{ - asymmetric::{KeyPair, Decryptor, Signer}, + asymmetric::KeyPair, backend::interface::Asymmetric, mem::Protected, mpi::{self, MPI, ProtectedMPI, PublicKey}, @@ -133,21 +133,19 @@ impl TryFrom for MPI { } } -impl Signer for KeyPair { - fn public(&self) -> &Key { - KeyPair::public(self) - } - - fn sign(&mut self, hash_algo: HashAlgorithm, digest: &[u8]) - -> Result +impl KeyPair { + pub(crate) fn sign_backend(&self, + secret: &mpi::SecretKeyMaterial, + hash_algo: HashAlgorithm, + digest: &[u8]) + -> Result { use crate::PublicKeyAlgorithm::*; let mut rng = RandomNumberGenerator::new_userspace()?; - self.secret().map(|secret| { - #[allow(deprecated)] - match (self.public().pk_algo(), self.public().mpis(), secret) + #[allow(deprecated)] + match (self.public().pk_algo(), self.public().mpis(), secret) { (RSASign, PublicKey::RSA { e, .. }, @@ -235,16 +233,12 @@ impl Signer for KeyPair { "unsupported combination of algorithm {:?}, key {:?}, \ and secret key {:?}", pk_algo, self.public(), self.secret())).into()), - }}) + } } } -impl Decryptor for KeyPair { - fn public(&self) -> &Key { - KeyPair::public(self) - } - - fn decrypt(&mut self, ciphertext: &mpi::Ciphertext, +impl KeyPair { + pub(crate) fn decrypt_backend(&self, secret: &mpi::SecretKeyMaterial, ciphertext: &mpi::Ciphertext, _plaintext_len: Option) -> Result { @@ -253,9 +247,7 @@ impl Decryptor for KeyPair { Error::MalformedMessage(e.to_string()).into() } - self.secret().map( - |secret| Ok(match (self.public().mpis(), secret, ciphertext) - { + Ok(match (self.public().mpis(), secret, ciphertext) { (PublicKey::RSA { e, .. }, mpi::SecretKeyMaterial::RSA { p, q, .. }, mpi::Ciphertext::RSA { c }) => { @@ -294,14 +286,14 @@ impl Decryptor for KeyPair { "unsupported combination of key pair {:?}/{:?} \ and ciphertext {:?}", public, secret, ciphertext)).into()), - })) + }) } } impl Key { /// Encrypts the given data with this key. - pub fn encrypt(&self, data: &SessionKey) -> Result { + pub(crate) fn encrypt_backend(&self, data: &SessionKey) -> Result { use crate::PublicKeyAlgorithm::*; #[allow(deprecated)] @@ -371,7 +363,7 @@ impl Key { } /// Verifies the given signature. - pub fn verify(&self, sig: &mpi::Signature, hash_algo: HashAlgorithm, + pub(crate) fn verify_backend(&self, sig: &mpi::Signature, hash_algo: HashAlgorithm, digest: &[u8]) -> Result<()> { use crate::crypto::mpi::Signature; diff --git a/openpgp/src/crypto/backend/cng/asymmetric.rs b/openpgp/src/crypto/backend/cng/asymmetric.rs index de49587d..e47f3911 100644 --- a/openpgp/src/crypto/backend/cng/asymmetric.rs +++ b/openpgp/src/crypto/backend/cng/asymmetric.rs @@ -6,7 +6,7 @@ use std::convert::TryInto; use crate::{Error, Result}; -use crate::crypto::asymmetric::{Decryptor, KeyPair, Signer}; +use crate::crypto::asymmetric::KeyPair; use crate::crypto::backend::interface::Asymmetric; use crate::crypto::mem::Protected; use crate::crypto::mpi; @@ -131,12 +131,13 @@ impl Asymmetric for super::Backend { } } -impl Signer for KeyPair { - fn public(&self) -> &Key { - KeyPair::public(self) - } - - fn sign(&mut self, hash_algo: HashAlgorithm, digest: &[u8]) -> Result { +impl KeyPair { + pub(crate) fn sign_backend(&self, + secret: &mpi::SecretKeyMaterial, + hash_algo: HashAlgorithm, + digest: &[u8]) + -> Result + { use cng::asymmetric::{AsymmetricAlgorithm, AsymmetricAlgorithmId}; use cng::asymmetric::{AsymmetricKey, Private, Rsa}; use cng::asymmetric::signature::{Signer, SignaturePadding}; @@ -145,8 +146,7 @@ impl Signer for KeyPair { use cng::asymmetric::ecc::NamedCurve; #[allow(deprecated)] - self.secret().map(|secret| { - Ok(match (self.public().pk_algo(), self.public().mpis(), secret) { + Ok(match (self.public().pk_algo(), self.public().mpis(), secret) { (PublicKeyAlgorithm::RSAEncryptSign, &mpi::PublicKey::RSA { ref e, ref n }, &mpi::SecretKeyMaterial::RSA { ref p, ref q, ref d, .. }) | @@ -403,27 +403,20 @@ impl Signer for KeyPair { "unsupported combination of algorithm {:?}, key {:?}, \ and secret key {:?}", pk_algo, self.public(), self.secret())))?, - }) }) } } -impl Decryptor for KeyPair { - fn public(&self) -> &Key { - KeyPair::public(self) - } - - /// Creates a signature over the `digest` produced by `hash_algo`. - fn decrypt( - &mut self, +impl KeyPair { + pub(crate) fn decrypt_backend( + &self, + secret: &mpi::SecretKeyMaterial, ciphertext: &mpi::Ciphertext, plaintext_len: Option, ) -> Result { use crate::PublicKeyAlgorithm::*; - self.secret().map( - |secret| Ok(match (self.public().mpis(), secret, ciphertext) - { + Ok(match (self.public().mpis(), secret, ciphertext) { (mpi::PublicKey::RSA { ref e, ref n }, mpi::SecretKeyMaterial::RSA { ref p, ref q, ref d, .. }, mpi::Ciphertext::RSA { ref c }) => { @@ -471,13 +464,13 @@ impl Decryptor for KeyPair { "unsupported combination of key pair {:?}/{:?} \ and ciphertext {:?}", public, secret, ciphertext)).into()), - })) + }) } } impl Key { /// Encrypts the given data with this key. - pub fn encrypt(&self, data: &SessionKey) -> Result { + pub(crate) fn encrypt_backend(&self, data: &SessionKey) -> Result { use cng::asymmetric::{AsymmetricAlgorithm, AsymmetricAlgorithmId}; use cng::asymmetric::{AsymmetricKey, Public, Rsa}; use cng::key_blob::RsaKeyPublicPayload; @@ -536,7 +529,7 @@ impl Key { } /// Verifies the given signature. - pub fn verify(&self, sig: &mpi::Signature, hash_algo: HashAlgorithm, + pub(crate) fn verify_backend(&self, sig: &mpi::Signature, hash_algo: HashAlgorithm, digest: &[u8]) -> Result<()> { use cng::asymmetric::{AsymmetricAlgorithm, AsymmetricAlgorithmId}; use cng::asymmetric::{AsymmetricKey, Public, Rsa}; diff --git a/openpgp/src/crypto/backend/nettle/asymmetric.rs b/openpgp/src/crypto/backend/nettle/asymmetric.rs index debb8a5b..e18fa249 100644 --- a/openpgp/src/crypto/backend/nettle/asymmetric.rs +++ b/openpgp/src/crypto/backend/nettle/asymmetric.rs @@ -9,7 +9,7 @@ use nettle::{curve25519, ecc, ecdh, ecdsa, ed25519, dsa, rsa, random::Yarrow}; use crate::{Error, Result}; use crate::packet::{key, Key}; -use crate::crypto::asymmetric::{KeyPair, Decryptor, Signer}; +use crate::crypto::asymmetric::KeyPair; use crate::crypto::backend::interface::Asymmetric; use crate::crypto::mpi::{self, MPI, PublicKey}; use crate::crypto::SessionKey; @@ -74,21 +74,19 @@ impl Asymmetric for super::Backend { } } -impl Signer for KeyPair { - fn public(&self) -> &Key { - KeyPair::public(self) - } - - fn sign(&mut self, hash_algo: HashAlgorithm, digest: &[u8]) - -> Result +impl KeyPair { + pub(crate) fn sign_backend(&self, + secret: &mpi::SecretKeyMaterial, + hash_algo: HashAlgorithm, + digest: &[u8]) + -> Result { use crate::PublicKeyAlgorithm::*; let mut rng = Yarrow::default(); - self.secret().map(|secret| { - #[allow(deprecated)] - match (self.public().pk_algo(), self.public().mpis(), secret) + #[allow(deprecated)] + match (self.public().pk_algo(), self.public().mpis(), secret) { (RSASign, &PublicKey::RSA { ref e, ref n }, @@ -189,24 +187,18 @@ impl Signer for KeyPair { "unsupported combination of algorithm {:?}, key {:?}, \ and secret key {:?}", pk_algo, self.public(), self.secret())).into()), - }}) + } } } -impl Decryptor for KeyPair { - fn public(&self) -> &Key { - KeyPair::public(self) - } - - fn decrypt(&mut self, ciphertext: &mpi::Ciphertext, +impl KeyPair { + pub(crate) fn decrypt_backend(&self, secret: &mpi::SecretKeyMaterial, ciphertext: &mpi::Ciphertext, plaintext_len: Option) -> Result { use crate::PublicKeyAlgorithm::*; - self.secret().map( - |secret| Ok(match (self.public().mpis(), secret, ciphertext) - { + Ok(match (self.public().mpis(), secret, ciphertext) { (PublicKey::RSA{ ref e, ref n }, mpi::SecretKeyMaterial::RSA{ ref p, ref q, ref d, .. }, mpi::Ciphertext::RSA{ ref c }) => { @@ -242,14 +234,14 @@ impl Decryptor for KeyPair { "unsupported combination of key pair {:?}/{:?} \ and ciphertext {:?}", public, secret, ciphertext)).into()), - })) + }) } } impl Key { /// Encrypts the given data with this key. - pub fn encrypt(&self, data: &SessionKey) -> Result { + pub(crate) fn encrypt_backend(&self, data: &SessionKey) -> Result { use crate::PublicKeyAlgorithm::*; #[allow(deprecated)] @@ -298,7 +290,7 @@ impl Key { } /// Verifies the given signature. - pub fn verify(&self, sig: &mpi::Signature, hash_algo: HashAlgorithm, + pub(crate) fn verify_backend(&self, sig: &mpi::Signature, hash_algo: HashAlgorithm, digest: &[u8]) -> Result<()> { use crate::crypto::mpi::Signature; diff --git a/openpgp/src/crypto/backend/openssl/asymmetric.rs b/openpgp/src/crypto/backend/openssl/asymmetric.rs index d45443fd..77ee9ff5 100644 --- a/openpgp/src/crypto/backend/openssl/asymmetric.rs +++ b/openpgp/src/crypto/backend/openssl/asymmetric.rs @@ -1,6 +1,6 @@ use crate::{Error, Result}; -use crate::crypto::asymmetric::{Decryptor, KeyPair, Signer}; +use crate::crypto::asymmetric::KeyPair; use crate::crypto::backend::interface::Asymmetric; use crate::crypto::mpi; use crate::crypto::mpi::{ProtectedMPI, MPI}; @@ -136,16 +136,16 @@ impl TryFrom<&Curve> for Nid { } } -impl Signer for KeyPair { - fn public(&self) -> &Key { - KeyPair::public(self) - } - - fn sign(&mut self, hash_algo: HashAlgorithm, digest: &[u8]) -> Result { +impl KeyPair { + pub(crate) fn sign_backend(&self, + secret: &mpi::SecretKeyMaterial, + hash_algo: HashAlgorithm, + digest: &[u8]) + -> Result + { use crate::PublicKeyAlgorithm::*; #[allow(deprecated)] - self.secret().map( - |secret| match (self.public().pk_algo(), self.public().mpis(), secret) { + match (self.public().pk_algo(), self.public().mpis(), secret) { ( RSAEncryptSign, mpi::PublicKey::RSA { e, n }, @@ -254,25 +254,20 @@ impl Signer for KeyPair { self.secret() )) .into()), - }, - ) + } } } -impl Decryptor for KeyPair { - fn public(&self) -> &Key { - KeyPair::public(self) - } - - fn decrypt( - &mut self, +impl KeyPair { + pub(crate) fn decrypt_backend( + &self, + secret: &mpi::SecretKeyMaterial, ciphertext: &mpi::Ciphertext, _plaintext_len: Option, ) -> Result { use crate::crypto::mpi::PublicKey; - self.secret().map(|secret| { - Ok(match (self.public().mpis(), secret, ciphertext) { + Ok(match (self.public().mpis(), secret, ciphertext) { ( PublicKey::RSA { ref e, ref n }, mpi::SecretKeyMaterial::RSA { @@ -307,14 +302,13 @@ impl Decryptor for KeyPair { )) .into()) } - }) }) } } impl Key { /// Encrypts the given data with this key. - pub fn encrypt(&self, data: &SessionKey) -> Result { + pub(crate) fn encrypt_backend(&self, data: &SessionKey) -> Result { use PublicKeyAlgorithm::*; #[allow(deprecated)] match self.pk_algo() { @@ -361,7 +355,7 @@ impl Key { } /// Verifies the given signature. - pub fn verify( + pub(crate) fn verify_backend( &self, sig: &mpi::Signature, hash_algo: HashAlgorithm, diff --git a/openpgp/src/crypto/backend/rust/asymmetric.rs b/openpgp/src/crypto/backend/rust/asymmetric.rs index d52b66b9..9654e788 100644 --- a/openpgp/src/crypto/backend/rust/asymmetric.rs +++ b/openpgp/src/crypto/backend/rust/asymmetric.rs @@ -13,7 +13,7 @@ use rsa::traits::{PrivateKeyParts, PublicKeyParts}; use rsa::{Pkcs1v15Encrypt, RsaPublicKey, RsaPrivateKey, Pkcs1v15Sign}; use crate::{Error, Result}; -use crate::crypto::asymmetric::{KeyPair, Decryptor, Signer}; +use crate::crypto::asymmetric::KeyPair; use crate::crypto::backend::interface::Asymmetric; use crate::crypto::mem::Protected; use crate::crypto::mpi::{self, MPI, ProtectedMPI}; @@ -149,17 +149,16 @@ fn rsa_private_key(e: &MPI, n: &MPI, p: &ProtectedMPI, q: &ProtectedMPI, d: &Pro Ok(RsaPrivateKey::from_components(n, e, d, vec![p, q])?) } -impl Signer for KeyPair { - fn public(&self) -> &Key { - KeyPair::public(self) - } - - fn sign(&mut self, hash_algo: HashAlgorithm, digest: &[u8]) +impl KeyPair { + pub(crate) fn sign_backend(&self, + secret: &mpi::SecretKeyMaterial, + hash_algo: HashAlgorithm, + digest: &[u8]) -> Result { use crate::PublicKeyAlgorithm::*; #[allow(deprecated)] - self.secret().map(|secret| match (self.public().pk_algo(), self.public().mpis(), secret) { + match (self.public().pk_algo(), self.public().mpis(), secret) { (RSAEncryptSign, mpi::PublicKey::RSA { e, n }, mpi::SecretKeyMaterial::RSA { p, q, d, .. }) | @@ -267,21 +266,17 @@ impl Signer for KeyPair { self.secret() )).into()) } - }) + } } } -impl Decryptor for KeyPair { - fn public(&self) -> &Key { - KeyPair::public(self) - } - - fn decrypt(&mut self, ciphertext: &mpi::Ciphertext, +impl KeyPair { + pub(crate) fn decrypt_backend(&self, secret: &mpi::SecretKeyMaterial, ciphertext: &mpi::Ciphertext, _plaintext_len: Option) -> Result { use crate::PublicKeyAlgorithm::*; - self.secret().map(|secret| match (self.public().mpis(), secret, ciphertext) { + match (self.public().mpis(), secret, ciphertext) { (mpi::PublicKey::RSA { e, n }, mpi::SecretKeyMaterial::RSA { p, q, d, .. }, mpi::Ciphertext::RSA { c }) => { @@ -305,14 +300,14 @@ impl Decryptor for KeyPair { "unsupported combination of key pair {:?}/{:?} \ and ciphertext {:?}", public, secret, ciphertext)).into()), - }) + } } } impl Key { /// Encrypts the given data with this key. - pub fn encrypt(&self, data: &SessionKey) -> Result { + pub(crate) fn encrypt_backend(&self, data: &SessionKey) -> Result { use PublicKeyAlgorithm::*; #[allow(deprecated)] match self.pk_algo() { @@ -350,7 +345,7 @@ impl Key { } /// Verifies the given signature. - pub fn verify(&self, sig: &mpi::Signature, hash_algo: HashAlgorithm, + pub(crate) fn verify_backend(&self, sig: &mpi::Signature, hash_algo: HashAlgorithm, digest: &[u8]) -> Result<()> { fn bad(e: impl ToString) -> anyhow::Error { diff --git a/openpgp/src/packet/key.rs b/openpgp/src/packet/key.rs index 4f9b496a..c1d9545c 100644 --- a/openpgp/src/packet/key.rs +++ b/openpgp/src/packet/key.rs @@ -102,6 +102,7 @@ use crate::types::{Curve, Timestamp}; use crate::crypto::S2K; use crate::Result; use crate::crypto::Password; +use crate::crypto::SessionKey; use crate::KeyID; use crate::Fingerprint; use crate::KeyHandle; @@ -734,6 +735,22 @@ pub(crate) type UnspecifiedSecondary = Key; #[allow(dead_code)] pub(crate) type UnspecifiedKey = Key; +/// Cryptographic operations using the key material. +impl Key + where P: key::KeyParts, + R: key::KeyRole, +{ + /// Encrypts the given data with this key. + pub fn encrypt(&self, data: &SessionKey) -> Result { + self.encrypt_backend(data) + } + + /// Verifies the given signature. + pub fn verify(&self, sig: &mpi::Signature, hash_algo: HashAlgorithm, + digest: &[u8]) -> Result<()> { + self.verify_backend(sig, hash_algo, digest) + } +} /// Holds a public key, public subkey, private key or private subkey /// packet. -- cgit v1.2.3