Skip to content

Commit

Permalink
feat: simplify public traits
Browse files Browse the repository at this point in the history
The crate contains several exported traits targeting
hardware-accelerated implementations (PublicKey, PrivateKey,
EncryptionPrimitive, DecriptionPrimitive). However these traits
overcomplicate internal structure of the crate. It is not clear, which
level of API can be implemented by the hardware accelerators.
The crate is already quite complicated, implementing both
PaddingScheme-based API and Signer/Verifier/Encryptor/Decryptor API.

Remove the complication for now. The proper level of indirection can be
introduced once support for actual hardware accelerators is implemented.

Signed-off-by: Dmitry Baryshkov <[email protected]>
  • Loading branch information
lumag committed Apr 18, 2023
1 parent abe9c38 commit 487f249
Show file tree
Hide file tree
Showing 8 changed files with 134 additions and 199 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ A portable RSA implementation in pure Rust.
## Example

```rust
use rsa::{Pkcs1v15Encrypt, PublicKey, RsaPrivateKey, RsaPublicKey};
use rsa::{Pkcs1v15Encrypt, RsaPrivateKey, RsaPublicKey};

let mut rng = rand::thread_rng();
let bits = 2048;
Expand Down
72 changes: 44 additions & 28 deletions src/key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@ use num_traits::{One, ToPrimitive};
use rand_core::CryptoRngCore;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use zeroize::Zeroize;
use zeroize::{Zeroize, Zeroizing};

use crate::algorithms::{generate_multi_prime_key, generate_multi_prime_key_with_exp};
use crate::dummy_rng::DummyRng;
use crate::errors::{Error, Result};
use crate::internals;

use crate::padding::{PaddingScheme, SignatureScheme};
use crate::raw::{DecryptionPrimitive, EncryptionPrimitive};

/// Components of an RSA public key.
pub trait PublicKeyParts {
Expand All @@ -31,8 +31,6 @@ pub trait PublicKeyParts {
}
}

pub trait PrivateKey: DecryptionPrimitive + PublicKeyParts {}

/// Represents the public part of an RSA key.
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
Expand Down Expand Up @@ -161,25 +159,6 @@ impl From<&RsaPrivateKey> for RsaPublicKey {
}
}

/// Generic trait for operations on a public key.
pub trait PublicKey: EncryptionPrimitive + PublicKeyParts {
/// Encrypt the given message.
fn encrypt<R: CryptoRngCore, P: PaddingScheme>(
&self,
rng: &mut R,
padding: P,
msg: &[u8],
) -> Result<Vec<u8>>;

/// Verify a signed message.
///
/// `hashed` must be the result of hashing the input using the hashing function
/// passed in through `hash`.
///
/// If the message is valid `Ok(())` is returned, otherwise an `Err` indicating failure.
fn verify<S: SignatureScheme>(&self, scheme: S, hashed: &[u8], sig: &[u8]) -> Result<()>;
}

impl PublicKeyParts for RsaPublicKey {
fn n(&self) -> &BigUint {
&self.n
Expand All @@ -190,8 +169,9 @@ impl PublicKeyParts for RsaPublicKey {
}
}

impl PublicKey for RsaPublicKey {
fn encrypt<R: CryptoRngCore, P: PaddingScheme>(
impl RsaPublicKey {
/// Encrypt the given message.
pub fn encrypt<R: CryptoRngCore, P: PaddingScheme>(
&self,
rng: &mut R,
padding: P,
Expand All @@ -200,7 +180,13 @@ impl PublicKey for RsaPublicKey {
padding.encrypt(rng, self, msg)
}

fn verify<S: SignatureScheme>(&self, scheme: S, hashed: &[u8], sig: &[u8]) -> Result<()> {
/// Verify a signed message.
///
/// `hashed` must be the result of hashing the input using the hashing function
/// passed in through `hash`.
///
/// If the message is valid `Ok(())` is returned, otherwise an `Err` indicating failure.
pub fn verify<S: SignatureScheme>(&self, scheme: S, hashed: &[u8], sig: &[u8]) -> Result<()> {
scheme.verify(self, hashed, sig)
}
}
Expand Down Expand Up @@ -239,6 +225,16 @@ impl RsaPublicKey {
pub fn new_unchecked(n: BigUint, e: BigUint) -> Self {
Self { n, e }
}

pub(crate) fn raw_int_encryption_primitive(
&self,
plaintext: &BigUint,
pad_size: usize,
) -> Result<Vec<u8>> {
let c = Zeroizing::new(internals::encrypt(self, plaintext));
let c_bytes = Zeroizing::new(c.to_bytes_be());
internals::left_pad(&c_bytes, pad_size)
}
}

impl PublicKeyParts for RsaPrivateKey {
Expand All @@ -251,8 +247,6 @@ impl PublicKeyParts for RsaPrivateKey {
}
}

impl PrivateKey for RsaPrivateKey {}

impl RsaPrivateKey {
/// Generate a new Rsa key pair of the given bit size using the passed in `rng`.
pub fn new<R: CryptoRngCore + ?Sized>(rng: &mut R, bit_size: usize) -> Result<RsaPrivateKey> {
Expand Down Expand Up @@ -461,6 +455,28 @@ impl RsaPrivateKey {
) -> Result<Vec<u8>> {
padding.sign(Some(rng), self, digest_in)
}

/// Do NOT use directly! Only for implementors.
pub(crate) fn raw_decryption_primitive<R: CryptoRngCore + ?Sized>(
&self,
rng: Option<&mut R>,
ciphertext: &[u8],
pad_size: usize,
) -> Result<Vec<u8>> {
let int = Zeroizing::new(BigUint::from_bytes_be(ciphertext));
self.raw_int_decryption_primitive(rng, &int, pad_size)
}

pub(crate) fn raw_int_decryption_primitive<R: CryptoRngCore + ?Sized>(
&self,
rng: Option<&mut R>,
ciphertext: &BigUint,
pad_size: usize,
) -> Result<Vec<u8>> {
let m = Zeroizing::new(internals::decrypt_and_check(rng, self, ciphertext)?);
let m_bytes = Zeroizing::new(m.to_bytes_be());
internals::left_pad(&m_bytes, pad_size)
}
}

/// Check that the public key is well formed and has an exponent within acceptable bounds.
Expand Down
7 changes: 3 additions & 4 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
//!
//! ## PKCS#1 v1.5 encryption
//! ```
//! use rsa::{PublicKey, RsaPrivateKey, RsaPublicKey, Pkcs1v15Encrypt};
//! use rsa::{RsaPrivateKey, RsaPublicKey, Pkcs1v15Encrypt};
//!
//! let mut rng = rand::thread_rng();
//!
Expand All @@ -34,7 +34,7 @@
//!
//! ## OAEP encryption
//! ```
//! use rsa::{PublicKey, RsaPrivateKey, RsaPublicKey, Oaep};
//! use rsa::{RsaPrivateKey, RsaPublicKey, Oaep};
//!
//! let mut rng = rand::thread_rng();
//!
Expand Down Expand Up @@ -233,15 +233,14 @@ mod dummy_rng;
mod encoding;
mod key;
mod padding;
mod raw;

pub use pkcs1;
pub use pkcs8;
#[cfg(feature = "sha2")]
pub use sha2;

pub use crate::{
key::{PublicKey, PublicKeyParts, RsaPrivateKey, RsaPublicKey},
key::{PublicKeyParts, RsaPrivateKey, RsaPublicKey},
oaep::Oaep,
padding::{PaddingScheme, SignatureScheme},
pkcs1v15::{Pkcs1v15Encrypt, Pkcs1v15Sign},
Expand Down
60 changes: 26 additions & 34 deletions src/oaep.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,14 @@ use core::marker::PhantomData;
use rand_core::CryptoRngCore;

use digest::{Digest, DynDigest, FixedOutputReset};
use num_bigint::BigUint;
use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};
use zeroize::Zeroizing;

use crate::algorithms::{mgf1_xor, mgf1_xor_digest};
use crate::dummy_rng::DummyRng;
use crate::errors::{Error, Result};
use crate::key::{self, PrivateKey, PublicKey, RsaPrivateKey, RsaPublicKey};
use crate::key::{self, PublicKeyParts, RsaPrivateKey, RsaPublicKey};
use crate::padding::PaddingScheme;
use crate::traits::{Decryptor, RandomizedDecryptor, RandomizedEncryptor};

Expand Down Expand Up @@ -55,7 +56,7 @@ impl Oaep {
/// ```
/// use sha1::Sha1;
/// use sha2::Sha256;
/// use rsa::{BigUint, RsaPublicKey, Oaep, PublicKey};
/// use rsa::{BigUint, RsaPublicKey, Oaep, };
/// use base64ct::{Base64, Encoding};
///
/// let n = Base64::decode_vec("ALHgDoZmBQIx+jTmgeeHW6KsPOrj11f6CvWsiRleJlQpW77AwSZhd21ZDmlTKfaIHBSUxRUsuYNh7E2SHx8rkFVCQA2/gXkZ5GK2IUbzSTio9qXA25MWHvVxjMfKSL8ZAxZyKbrG94FLLszFAFOaiLLY8ECs7g+dXOriYtBwLUJK+lppbd+El+8ZA/zH0bk7vbqph5pIoiWggxwdq3mEz4LnrUln7r6dagSQzYErKewY8GADVpXcq5mfHC1xF2DFBub7bFjMVM5fHq7RK+pG5xjNDiYITbhLYrbVv3X0z75OvN0dY49ITWjM7xyvMWJXVJS7sJlgmCCL6RwWgP8PhcE=").unwrap();
Expand Down Expand Up @@ -92,7 +93,7 @@ impl Oaep {
/// ```
/// use sha1::Sha1;
/// use sha2::Sha256;
/// use rsa::{BigUint, RsaPublicKey, Oaep, PublicKey};
/// use rsa::{BigUint, RsaPublicKey, Oaep, };
/// use base64ct::{Base64, Encoding};
///
/// let n = Base64::decode_vec("ALHgDoZmBQIx+jTmgeeHW6KsPOrj11f6CvWsiRleJlQpW77AwSZhd21ZDmlTKfaIHBSUxRUsuYNh7E2SHx8rkFVCQA2/gXkZ5GK2IUbzSTio9qXA25MWHvVxjMfKSL8ZAxZyKbrG94FLLszFAFOaiLLY8ECs7g+dXOriYtBwLUJK+lppbd+El+8ZA/zH0bk7vbqph5pIoiWggxwdq3mEz4LnrUln7r6dagSQzYErKewY8GADVpXcq5mfHC1xF2DFBub7bFjMVM5fHq7RK+pG5xjNDiYITbhLYrbVv3X0z75OvN0dY49ITWjM7xyvMWJXVJS7sJlgmCCL6RwWgP8PhcE=").unwrap();
Expand Down Expand Up @@ -131,10 +132,10 @@ impl Oaep {
}

impl PaddingScheme for Oaep {
fn decrypt<Rng: CryptoRngCore, Priv: PrivateKey>(
fn decrypt<Rng: CryptoRngCore>(
mut self,
rng: Option<&mut Rng>,
priv_key: &Priv,
priv_key: &RsaPrivateKey,
ciphertext: &[u8],
) -> Result<Vec<u8>> {
decrypt(
Expand All @@ -147,10 +148,10 @@ impl PaddingScheme for Oaep {
)
}

fn encrypt<Rng: CryptoRngCore, Pub: PublicKey>(
fn encrypt<Rng: CryptoRngCore>(
mut self,
rng: &mut Rng,
pub_key: &Pub,
pub_key: &RsaPublicKey,
msg: &[u8],
) -> Result<Vec<u8>> {
encrypt(
Expand All @@ -175,9 +176,9 @@ impl fmt::Debug for Oaep {
}

#[inline]
fn encrypt_internal<R: CryptoRngCore + ?Sized, K: PublicKey, MGF: FnMut(&mut [u8], &mut [u8])>(
fn encrypt_internal<R: CryptoRngCore + ?Sized, MGF: FnMut(&mut [u8], &mut [u8])>(
rng: &mut R,
pub_key: &K,
pub_key: &RsaPublicKey,
msg: &[u8],
p_hash: &[u8],
h_size: usize,
Expand Down Expand Up @@ -206,7 +207,8 @@ fn encrypt_internal<R: CryptoRngCore + ?Sized, K: PublicKey, MGF: FnMut(&mut [u8

mgf(seed, db);

pub_key.raw_encryption_primitive(&em, pub_key.size())
let int = Zeroizing::new(BigUint::from_bytes_be(&em));
pub_key.raw_int_encryption_primitive(&int, pub_key.size())
}

/// Encrypts the given message with RSA and the padding scheme from
Expand All @@ -217,9 +219,9 @@ fn encrypt_internal<R: CryptoRngCore + ?Sized, K: PublicKey, MGF: FnMut(&mut [u8
///
/// [PKCS#1 OAEP]: https://datatracker.ietf.org/doc/html/rfc8017#section-7.1
#[inline]
fn encrypt<R: CryptoRngCore + ?Sized, K: PublicKey>(
fn encrypt<R: CryptoRngCore + ?Sized>(
rng: &mut R,
pub_key: &K,
pub_key: &RsaPublicKey,
msg: &[u8],
digest: &mut dyn DynDigest,
mgf_digest: &mut dyn DynDigest,
Expand Down Expand Up @@ -249,14 +251,9 @@ fn encrypt<R: CryptoRngCore + ?Sized, K: PublicKey>(
///
/// [PKCS#1 OAEP]: https://datatracker.ietf.org/doc/html/rfc8017#section-7.1
#[inline]
fn encrypt_digest<
R: CryptoRngCore + ?Sized,
K: PublicKey,
D: Digest,
MGD: Digest + FixedOutputReset,
>(
fn encrypt_digest<R: CryptoRngCore + ?Sized, D: Digest, MGD: Digest + FixedOutputReset>(
rng: &mut R,
pub_key: &K,
pub_key: &RsaPublicKey,
msg: &[u8],
label: Option<String>,
) -> Result<Vec<u8>> {
Expand Down Expand Up @@ -289,9 +286,9 @@ fn encrypt_digest<
///
/// [PKCS#1 OAEP]: https://datatracker.ietf.org/doc/html/rfc8017#section-7.1
#[inline]
fn decrypt<R: CryptoRngCore + ?Sized, SK: PrivateKey>(
fn decrypt<R: CryptoRngCore + ?Sized>(
rng: Option<&mut R>,
priv_key: &SK,
priv_key: &RsaPrivateKey,
ciphertext: &[u8],
digest: &mut dyn DynDigest,
mgf_digest: &mut dyn DynDigest,
Expand Down Expand Up @@ -343,14 +340,9 @@ fn decrypt<R: CryptoRngCore + ?Sized, SK: PrivateKey>(
///
/// [PKCS#1 OAEP]: https://datatracker.ietf.org/doc/html/rfc8017#section-7.1
#[inline]
fn decrypt_digest<
R: CryptoRngCore + ?Sized,
SK: PrivateKey,
D: Digest,
MGD: Digest + FixedOutputReset,
>(
fn decrypt_digest<R: CryptoRngCore + ?Sized, D: Digest, MGD: Digest + FixedOutputReset>(
rng: Option<&mut R>,
priv_key: &SK,
priv_key: &RsaPrivateKey,
ciphertext: &[u8],
label: Option<String>,
) -> Result<Vec<u8>> {
Expand Down Expand Up @@ -390,9 +382,9 @@ fn decrypt_digest<
/// `rng` is given. It returns one or zero in valid that indicates whether the
/// plaintext was correctly structured.
#[inline]
fn decrypt_inner<R: CryptoRngCore + ?Sized, SK: PrivateKey, MGF: FnMut(&mut [u8], &mut [u8])>(
fn decrypt_inner<R: CryptoRngCore + ?Sized, MGF: FnMut(&mut [u8], &mut [u8])>(
rng: Option<&mut R>,
priv_key: &SK,
priv_key: &RsaPrivateKey,
ciphertext: &[u8],
h_size: usize,
expected_p_hash: &[u8],
Expand Down Expand Up @@ -491,7 +483,7 @@ where
rng: &mut R,
msg: &[u8],
) -> Result<Vec<u8>> {
encrypt_digest::<_, _, D, MGD>(rng, &self.inner, msg, self.label.as_ref().cloned())
encrypt_digest::<_, D, MGD>(rng, &self.inner, msg, self.label.as_ref().cloned())
}
}

Expand Down Expand Up @@ -542,7 +534,7 @@ where
MGD: Digest + FixedOutputReset,
{
fn decrypt(&self, ciphertext: &[u8]) -> Result<Vec<u8>> {
decrypt_digest::<DummyRng, _, D, MGD>(
decrypt_digest::<DummyRng, D, MGD>(
None,
&self.inner,
ciphertext,
Expand All @@ -561,7 +553,7 @@ where
rng: &mut R,
ciphertext: &[u8],
) -> Result<Vec<u8>> {
decrypt_digest::<_, _, D, MGD>(
decrypt_digest::<_, D, MGD>(
Some(rng),
&self.inner,
ciphertext,
Expand All @@ -572,7 +564,7 @@ where

#[cfg(test)]
mod tests {
use crate::key::{PublicKey, PublicKeyParts, RsaPrivateKey, RsaPublicKey};
use crate::key::{PublicKeyParts, RsaPrivateKey, RsaPublicKey};
use crate::oaep::{DecryptingKey, EncryptingKey, Oaep};
use crate::traits::{Decryptor, RandomizedDecryptor, RandomizedEncryptor};

Expand Down
Loading

0 comments on commit 487f249

Please sign in to comment.