From 5487f1db091d032363f76d295195bcb5b8036e36 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Wed, 19 Apr 2023 00:38:12 +0300 Subject: [PATCH] pss: make the implementation generic around the PublicKey/PrivateKey Signed-off-by: Dmitry Baryshkov --- README.md | 2 +- src/key.rs | 36 +++++++---- src/lib.rs | 12 ++-- src/pss.rs | 183 +++++++++++++++++++++++++++-------------------------- 4 files changed, 126 insertions(+), 107 deletions(-) diff --git a/README.md b/README.md index 551058b1..d7d8eb48 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ A portable RSA implementation in pure Rust. ## Example ```rust -use rsa::{Pkcs1v15Encrypt, PublicKey, RsaPrivateKey, RsaPublicKey}; +use rsa::{Pkcs1v15Encrypt, PublicKey, PrivateKey, RsaPrivateKey, RsaPublicKey}; let mut rng = rand::thread_rng(); let bits = 2048; diff --git a/src/key.rs b/src/key.rs index 87784395..c0ad9cfa 100644 --- a/src/key.rs +++ b/src/key.rs @@ -31,7 +31,17 @@ pub trait PublicKeyParts { } } -pub trait PrivateKey: DecryptionPrimitive + PublicKeyParts {} +/// Generic trait for operations on a private key. +pub trait PrivateKey: DecryptionPrimitive + PublicKeyParts + Sized { + /// Corresponding public key type + type PublicKey: PublicKey; + + /// generate new random private key of the specified bit size + fn new(rng: &mut R, bit_size: usize) -> Result; + + /// convert this private key to the corresponding public key + fn to_public_key(&self) -> Self::PublicKey; +} /// Represents the public part of an RSA key. #[derive(Debug, Clone, Hash, PartialEq, Eq)] @@ -251,14 +261,24 @@ impl PublicKeyParts for RsaPrivateKey { } } -impl PrivateKey for RsaPrivateKey {} +impl PrivateKey for RsaPrivateKey { + type PublicKey = RsaPublicKey; -impl RsaPrivateKey { /// Generate a new Rsa key pair of the given bit size using the passed in `rng`. - pub fn new(rng: &mut R, bit_size: usize) -> Result { + fn new(rng: &mut R, bit_size: usize) -> Result { generate_multi_prime_key(rng, 2, bit_size) } + /// Get the public key from the private key, cloning `n` and `e`. + /// + /// Generally this is not needed since `RsaPrivateKey` implements the `PublicKey` trait, + /// but it can occasionally be useful to discard the private information entirely. + fn to_public_key(&self) -> Self::PublicKey { + self.pubkey_components.clone() + } +} + +impl RsaPrivateKey { /// Generate a new RSA key pair of the given bit size and the public exponent /// using the passed in `rng`. /// @@ -297,14 +317,6 @@ impl RsaPrivateKey { Ok(k) } - /// Get the public key from the private key, cloning `n` and `e`. - /// - /// Generally this is not needed since `RsaPrivateKey` implements the `PublicKey` trait, - /// but it can occasionally be useful to discard the private information entirely. - pub fn to_public_key(&self) -> RsaPublicKey { - self.pubkey_components.clone() - } - /// Performs some calculations to speed up private key operations. pub fn precompute(&mut self) -> Result<()> { if self.precomputed.is_some() { diff --git a/src/lib.rs b/src/lib.rs index 76956fe6..c1ab95c9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -14,7 +14,7 @@ //! //! ## PKCS#1 v1.5 encryption //! ``` -//! use rsa::{PublicKey, RsaPrivateKey, RsaPublicKey, Pkcs1v15Encrypt}; +//! use rsa::{PrivateKey, PublicKey, RsaPrivateKey, RsaPublicKey, Pkcs1v15Encrypt}; //! //! let mut rng = rand::thread_rng(); //! @@ -34,7 +34,7 @@ //! //! ## OAEP encryption //! ``` -//! use rsa::{PublicKey, RsaPrivateKey, RsaPublicKey, Oaep}; +//! use rsa::{PrivateKey, PublicKey, RsaPrivateKey, RsaPublicKey, Oaep}; //! //! let mut rng = rand::thread_rng(); //! @@ -60,7 +60,7 @@ //! #![cfg_attr(feature = "sha2", doc = "```")] #![cfg_attr(not(feature = "sha2"), doc = "```ignore")] -//! use rsa::RsaPrivateKey; +//! use rsa::{PrivateKey, RsaPrivateKey}; //! use rsa::pkcs1v15::{SigningKey, VerifyingKey}; //! use rsa::signature::{Keypair, RandomizedSigner, SignatureEncoding, Verifier}; //! use rsa::sha2::{Digest, Sha256}; @@ -87,7 +87,7 @@ //! #![cfg_attr(feature = "sha2", doc = "```")] #![cfg_attr(not(feature = "sha2"), doc = "```ignore")] -//! use rsa::RsaPrivateKey; +//! use rsa::{PrivateKey, RsaPrivateKey}; //! use rsa::pss::{BlindedSigningKey, VerifyingKey}; //! use rsa::signature::{Keypair,RandomizedSigner, SignatureEncoding, Verifier}; //! use rsa::sha2::{Digest, Sha256}; @@ -96,7 +96,7 @@ //! //! let bits = 2048; //! let private_key = RsaPrivateKey::new(&mut rng, bits).expect("failed to generate a key"); -//! let signing_key = BlindedSigningKey::::new(private_key); +//! let signing_key = BlindedSigningKey::::new(private_key); //! let verifying_key = signing_key.verifying_key(); //! //! // Sign @@ -241,7 +241,7 @@ pub use pkcs8; pub use sha2; pub use crate::{ - key::{PublicKey, PublicKeyParts, RsaPrivateKey, RsaPublicKey}, + key::{PrivateKey, PublicKey, PublicKeyParts, RsaPrivateKey, RsaPublicKey}, oaep::Oaep, padding::{PaddingScheme, SignatureScheme}, pkcs1v15::{Pkcs1v15Encrypt, Pkcs1v15Sign}, diff --git a/src/pss.rs b/src/pss.rs index 1ef9a259..500223de 100644 --- a/src/pss.rs +++ b/src/pss.rs @@ -36,7 +36,6 @@ use crate::algorithms::{mgf1_xor, mgf1_xor_digest}; use crate::errors::{Error, Result}; use crate::key::{PrivateKey, PublicKey}; use crate::padding::SignatureScheme; -use crate::{RsaPrivateKey, RsaPublicKey}; #[cfg(feature = "getrandom")] use {rand_core::OsRng, signature::Signer}; @@ -617,27 +616,29 @@ where /// /// [RFC8017 § 8.1]: https://datatracker.ietf.org/doc/html/rfc8017#section-8.1 #[derive(Debug, Clone)] -pub struct SigningKey +pub struct SigningKey where D: Digest, + Priv: PrivateKey, { - inner: RsaPrivateKey, + inner: Priv, salt_len: usize, phantom: PhantomData, } -impl SigningKey +impl SigningKey where D: Digest, + Priv: PrivateKey, { /// Create a new RSASSA-PSS signing key. /// Digest output size is used as a salt length. - pub fn new(key: RsaPrivateKey) -> Self { + pub fn new(key: Priv) -> Self { Self::new_with_salt_len(key, ::output_size()) } /// Create a new RSASSA-PSS signing key with a salt of the given length. - pub fn new_with_salt_len(key: RsaPrivateKey, salt_len: usize) -> Self { + pub fn new_with_salt_len(key: Priv, salt_len: usize) -> Self { Self { inner: key, salt_len, @@ -658,7 +659,7 @@ where salt_len: usize, ) -> Result { Ok(Self { - inner: RsaPrivateKey::new(rng, bit_size)?, + inner: Priv::new(rng, bit_size)?, salt_len, phantom: Default::default(), }) @@ -684,56 +685,53 @@ where }) } -impl AssociatedAlgorithmIdentifier for SigningKey +impl AssociatedAlgorithmIdentifier for SigningKey where D: Digest, + Priv: PrivateKey, { type Params = AnyRef<'static>; const ALGORITHM_IDENTIFIER: AlgorithmIdentifierRef<'static> = pkcs1::ALGORITHM_ID; } -impl DynSignatureAlgorithmIdentifier for SigningKey +impl DynSignatureAlgorithmIdentifier for SigningKey where D: Digest + AssociatedOid, + Priv: PrivateKey, { fn signature_algorithm_identifier(&self) -> pkcs8::spki::Result { get_pss_signature_algo_id::(self.salt_len as u8) } } -impl From for SigningKey +impl From for SigningKey where D: Digest, + Priv: PrivateKey, { - fn from(key: RsaPrivateKey) -> Self { + fn from(key: Priv) -> Self { Self::new(key) } } -impl From> for RsaPrivateKey -where - D: Digest, -{ - fn from(key: SigningKey) -> Self { - key.inner - } -} - -impl EncodePrivateKey for SigningKey +impl EncodePrivateKey for SigningKey where D: Digest, + Priv: PrivateKey + EncodePrivateKey, { fn to_pkcs8_der(&self) -> pkcs8::Result { self.inner.to_pkcs8_der() } } -impl Keypair for SigningKey +impl Keypair for SigningKey where D: Digest, + Priv: PrivateKey, + Priv::PublicKey: Clone, { - type VerifyingKey = VerifyingKey; + type VerifyingKey = VerifyingKey; fn verifying_key(&self) -> Self::VerifyingKey { VerifyingKey { inner: self.inner.to_public_key(), @@ -744,18 +742,20 @@ where } #[cfg(feature = "getrandom")] -impl Signer for SigningKey +impl Signer for SigningKey where D: Digest + FixedOutputReset, + Priv: PrivateKey, { fn try_sign(&self, msg: &[u8]) -> signature::Result { self.try_sign_with_rng(&mut OsRng, msg) } } -impl RandomizedSigner for SigningKey +impl RandomizedSigner for SigningKey where D: Digest + FixedOutputReset, + Priv: PrivateKey, { fn try_sign_with_rng( &self, @@ -768,9 +768,10 @@ where } } -impl RandomizedDigestSigner for SigningKey +impl RandomizedDigestSigner for SigningKey where D: Digest + FixedOutputReset, + Priv: PrivateKey, { fn try_sign_digest_with_rng( &self, @@ -783,9 +784,10 @@ where } } -impl RandomizedPrehashSigner for SigningKey +impl RandomizedPrehashSigner for SigningKey where D: Digest + FixedOutputReset, + Priv: PrivateKey, { fn sign_prehash_with_rng( &self, @@ -798,11 +800,12 @@ where } } -impl AsRef for SigningKey +impl AsRef for SigningKey where D: Digest, + Priv: PrivateKey, { - fn as_ref(&self) -> &RsaPrivateKey { + fn as_ref(&self) -> &Priv { &self.inner } } @@ -810,29 +813,31 @@ where /// Signing key for producing "blinded" RSASSA-PSS signatures as described in /// [draft-irtf-cfrg-rsa-blind-signatures](https://datatracker.ietf.org/doc/draft-irtf-cfrg-rsa-blind-signatures/). #[derive(Debug, Clone)] -pub struct BlindedSigningKey +pub struct BlindedSigningKey where D: Digest, + Priv: PrivateKey, { - inner: RsaPrivateKey, + inner: Priv, salt_len: usize, phantom: PhantomData, } -impl BlindedSigningKey +impl BlindedSigningKey where D: Digest, + Priv: PrivateKey, { /// Create a new RSASSA-PSS signing key which produces "blinded" /// signatures. /// Digest output size is used as a salt length. - pub fn new(key: RsaPrivateKey) -> Self { + pub fn new(key: Priv) -> Self { Self::new_with_salt_len(key, ::output_size()) } /// Create a new RSASSA-PSS signing key which produces "blinded" /// signatures with a salt of the given length. - pub fn new_with_salt_len(key: RsaPrivateKey, salt_len: usize) -> Self { + pub fn new_with_salt_len(key: Priv, salt_len: usize) -> Self { Self { inner: key, salt_len, @@ -855,7 +860,7 @@ where salt_len: usize, ) -> Result { Ok(Self { - inner: RsaPrivateKey::new(rng, bit_size)?, + inner: Priv::new(rng, bit_size)?, salt_len, phantom: Default::default(), }) @@ -867,56 +872,53 @@ where } } -impl AssociatedAlgorithmIdentifier for BlindedSigningKey +impl AssociatedAlgorithmIdentifier for BlindedSigningKey where D: Digest, + Priv: PrivateKey, { type Params = AnyRef<'static>; const ALGORITHM_IDENTIFIER: AlgorithmIdentifierRef<'static> = pkcs1::ALGORITHM_ID; } -impl DynSignatureAlgorithmIdentifier for BlindedSigningKey +impl DynSignatureAlgorithmIdentifier for BlindedSigningKey where D: Digest + AssociatedOid, + Priv: PrivateKey, { fn signature_algorithm_identifier(&self) -> pkcs8::spki::Result { get_pss_signature_algo_id::(self.salt_len as u8) } } -impl From for BlindedSigningKey +impl From for BlindedSigningKey where D: Digest, + Priv: PrivateKey, { - fn from(key: RsaPrivateKey) -> Self { + fn from(key: Priv) -> Self { Self::new(key) } } -impl From> for RsaPrivateKey -where - D: Digest, -{ - fn from(key: BlindedSigningKey) -> Self { - key.inner - } -} - -impl EncodePrivateKey for BlindedSigningKey +impl EncodePrivateKey for BlindedSigningKey where D: Digest, + Priv: PrivateKey + EncodePrivateKey, { fn to_pkcs8_der(&self) -> pkcs8::Result { self.inner.to_pkcs8_der() } } -impl Keypair for BlindedSigningKey +impl Keypair for BlindedSigningKey where D: Digest, + Priv: PrivateKey, + Priv::PublicKey: Clone, { - type VerifyingKey = VerifyingKey; + type VerifyingKey = VerifyingKey; fn verifying_key(&self) -> Self::VerifyingKey { VerifyingKey { inner: self.inner.to_public_key(), @@ -926,9 +928,10 @@ where } } -impl RandomizedSigner for BlindedSigningKey +impl RandomizedSigner for BlindedSigningKey where D: Digest + FixedOutputReset, + Priv: PrivateKey, { fn try_sign_with_rng( &self, @@ -941,9 +944,10 @@ where } } -impl RandomizedDigestSigner for BlindedSigningKey +impl RandomizedDigestSigner for BlindedSigningKey where D: Digest + FixedOutputReset, + Priv: PrivateKey, { fn try_sign_digest_with_rng( &self, @@ -956,9 +960,10 @@ where } } -impl RandomizedPrehashSigner for BlindedSigningKey +impl RandomizedPrehashSigner for BlindedSigningKey where D: Digest + FixedOutputReset, + Priv: PrivateKey, { fn sign_prehash_with_rng( &self, @@ -971,11 +976,12 @@ where } } -impl AsRef for BlindedSigningKey +impl AsRef for BlindedSigningKey where D: Digest, + Priv: PrivateKey, { - fn as_ref(&self) -> &RsaPrivateKey { + fn as_ref(&self) -> &Priv { &self.inner } } @@ -985,19 +991,21 @@ where /// /// [RFC8017 § 8.1]: https://datatracker.ietf.org/doc/html/rfc8017#section-8.1 #[derive(Debug)] -pub struct VerifyingKey +pub struct VerifyingKey where D: Digest, + Pub: PublicKey, { - inner: RsaPublicKey, + inner: Pub, salt_len: usize, phantom: PhantomData, } /* Implemented manually so we don't have to bind D with Clone */ -impl Clone for VerifyingKey +impl Clone for VerifyingKey where D: Digest, + Pub: PublicKey + Clone, { fn clone(&self) -> Self { Self { @@ -1008,18 +1016,19 @@ where } } -impl VerifyingKey +impl VerifyingKey where D: Digest, + Pub: PublicKey, { /// Create a new RSASSA-PSS verifying key. /// Digest output size is used as a salt length. - pub fn new(key: RsaPublicKey) -> Self { + pub fn new(key: Pub) -> Self { Self::new_with_salt_len(key, ::output_size()) } /// Create a new RSASSA-PSS verifying key. - pub fn new_with_salt_len(key: RsaPublicKey, salt_len: usize) -> Self { + pub fn new_with_salt_len(key: Pub, salt_len: usize) -> Self { Self { inner: key, salt_len, @@ -1028,36 +1037,30 @@ where } } -impl AssociatedAlgorithmIdentifier for VerifyingKey +impl AssociatedAlgorithmIdentifier for VerifyingKey where D: Digest, + Pub: PublicKey, { type Params = AnyRef<'static>; const ALGORITHM_IDENTIFIER: AlgorithmIdentifierRef<'static> = pkcs1::ALGORITHM_ID; } -impl From for VerifyingKey +impl From for VerifyingKey where D: Digest, + Pub: PublicKey, { - fn from(key: RsaPublicKey) -> Self { + fn from(key: Pub) -> Self { Self::new(key) } } -impl From> for RsaPublicKey -where - D: Digest, -{ - fn from(key: VerifyingKey) -> Self { - key.inner - } -} - -impl Verifier for VerifyingKey +impl Verifier for VerifyingKey where D: Digest + FixedOutputReset, + Pub: PublicKey, { fn verify(&self, msg: &[u8], signature: &Signature) -> signature::Result<()> { verify_digest::<_, D>( @@ -1070,9 +1073,10 @@ where } } -impl DigestVerifier for VerifyingKey +impl DigestVerifier for VerifyingKey where D: Digest + FixedOutputReset, + Pub: PublicKey, { fn verify_digest(&self, digest: D, signature: &Signature) -> signature::Result<()> { verify_digest::<_, D>( @@ -1085,9 +1089,10 @@ where } } -impl PrehashVerifier for VerifyingKey +impl PrehashVerifier for VerifyingKey where D: Digest + FixedOutputReset, + Pub: PublicKey, { fn verify_prehash(&self, prehash: &[u8], signature: &Signature) -> signature::Result<()> { verify_digest::<_, D>(&self.inner, prehash, signature.as_ref(), self.salt_len) @@ -1095,18 +1100,20 @@ where } } -impl AsRef for VerifyingKey +impl AsRef for VerifyingKey where D: Digest, + Pub: PublicKey, { - fn as_ref(&self) -> &RsaPublicKey { + fn as_ref(&self) -> &Pub { &self.inner } } -impl EncodePublicKey for VerifyingKey +impl EncodePublicKey for VerifyingKey where D: Digest, + Pub: PublicKey + EncodePublicKey, { fn to_public_key_der(&self) -> pkcs8::spki::Result { self.inner.to_public_key_der() @@ -1116,7 +1123,7 @@ where #[cfg(test)] mod test { use crate::pss::{BlindedSigningKey, Pss, Signature, SigningKey, VerifyingKey}; - use crate::{PublicKey, RsaPrivateKey, RsaPublicKey}; + use crate::{PrivateKey, PublicKey, RsaPrivateKey, RsaPublicKey}; use hex_literal::hex; use num_bigint::BigUint; @@ -1208,7 +1215,7 @@ mod test { ), ]; let pub_key: RsaPublicKey = priv_key.into(); - let verifying_key: VerifyingKey = VerifyingKey::new(pub_key); + let verifying_key: VerifyingKey = VerifyingKey::new(pub_key); for (text, sig, expected) in &tests { let result = verifying_key.verify( @@ -1307,7 +1314,7 @@ mod test { let tests = ["test\n"]; let mut rng = ChaCha8Rng::from_seed([42; 32]); - let signing_key = SigningKey::::new(priv_key); + let signing_key = SigningKey::::new(priv_key); let verifying_key = signing_key.verifying_key(); for test in &tests { @@ -1324,7 +1331,7 @@ mod test { let tests = ["test\n"]; let mut rng = ChaCha8Rng::from_seed([42; 32]); - let signing_key = BlindedSigningKey::::new(priv_key); + let signing_key = BlindedSigningKey::::new(priv_key); let verifying_key = signing_key.verifying_key(); for test in &tests { @@ -1363,7 +1370,7 @@ mod test { let tests = ["test\n"]; let mut rng = ChaCha8Rng::from_seed([42; 32]); - let signing_key = BlindedSigningKey::::new(priv_key); + let signing_key = BlindedSigningKey::::new(priv_key); let verifying_key = signing_key.verifying_key(); for test in &tests { @@ -1402,7 +1409,7 @@ mod test { ), ]; let pub_key: RsaPublicKey = priv_key.into(); - let verifying_key = VerifyingKey::::new(pub_key); + let verifying_key = VerifyingKey::::new(pub_key); for (text, sig, expected) in &tests { let result = verifying_key @@ -1422,7 +1429,7 @@ mod test { let tests = [Sha1::digest("test\n")]; let mut rng = ChaCha8Rng::from_seed([42; 32]); - let signing_key = SigningKey::::new(priv_key); + let signing_key = SigningKey::::new(priv_key); let verifying_key = signing_key.verifying_key(); for test in &tests { @@ -1441,7 +1448,7 @@ mod test { let tests = [Sha1::digest("test\n")]; let mut rng = ChaCha8Rng::from_seed([42; 32]); - let signing_key = BlindedSigningKey::::new(priv_key); + let signing_key = BlindedSigningKey::::new(priv_key); let verifying_key = signing_key.verifying_key(); for test in &tests {