Skip to content

Commit

Permalink
Refactor PaddingScheme into a trait
Browse files Browse the repository at this point in the history
Splits up the `PaddingScheme` enum into four structs, named after the
previous variants of the struct (adopting capitalization from the Rust
API guidelines):

- `oaep::Oaep`
- `pkcs1v15::{Pkcs1v15Encrypt, Pkcs1v15Sign}`
- `pss::Pss`

All of these are re-exported from the toplevel.

Each of these structs impls one or more of the following traits:

- `PaddingScheme`: used for encryption
- `SignatureScheme`: used for signing

The `PaddingScheme` constructors have been remapped as follows:

- `new_oaep` => `Oaep::new`
- `new_oaep_with_label` => `Oaep::new_with_label`
- `new_oaep_with_mgf_hash` => `Oaep::new_with_mgf_hash`
- `new_oaep_with_mgf_hash_with_label` => `Oaep::new_with_mgf_hash_and_label`
- `new_pkcs1v15_encrypt` => `Pkcs1v15Encrypt`
- `new_pkcs1v15_sign` => `Pkcs1v15Sign::new`
- `new_pkcs1v15_sign_raw` => `Pkcs1v15Sign::new_raw`
- `new_pss` => `Pss::{new, new_blinded}`
- `new_pss_with_salt` => `Pss::{new_with_salt new_blinded_with_salt}`
  • Loading branch information
tarcieri committed Jan 6, 2023
1 parent 6b5dcc8 commit ef9650b
Show file tree
Hide file tree
Showing 6 changed files with 438 additions and 373 deletions.
173 changes: 38 additions & 135 deletions src/key.rs
Expand Up @@ -13,9 +13,8 @@ use crate::algorithms::{generate_multi_prime_key, generate_multi_prime_key_with_
use crate::dummy_rng::DummyRng;
use crate::errors::{Error, Result};

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

/// Components of an RSA public key.
pub trait PublicKeyParts {
Expand Down Expand Up @@ -173,18 +172,20 @@ 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>(
fn encrypt(
&self,
rng: &mut R,
padding: PaddingScheme,
rng: &mut impl CryptoRngCore,
padding: impl PaddingScheme,
msg: &[u8],
) -> Result<Vec<u8>>;

/// Verify a signed message.
/// `hashed`must be the result of hashing the input using the hashing function
///
/// `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, otherwiese an `Err` indicating failure.
fn verify(&self, padding: PaddingScheme, hashed: &[u8], sig: &[u8]) -> Result<()>;
///
/// If the message is valid `Ok(())` is returned, otherwise an `Err` indicating failure.
fn verify(&self, padding: impl SignatureScheme, hashed: &[u8], sig: &[u8]) -> Result<()>;
}

impl PublicKeyParts for RsaPublicKey {
Expand All @@ -198,36 +199,17 @@ impl PublicKeyParts for RsaPublicKey {
}

impl PublicKey for RsaPublicKey {
fn encrypt<R: CryptoRngCore>(
fn encrypt(
&self,
rng: &mut R,
padding: PaddingScheme,
rng: &mut impl CryptoRngCore,
padding: impl PaddingScheme,
msg: &[u8],
) -> Result<Vec<u8>> {
match padding {
PaddingScheme::PKCS1v15Encrypt => pkcs1v15::encrypt(rng, self, msg),
PaddingScheme::OAEP {
mut digest,
mut mgf_digest,
label,
} => oaep::encrypt(rng, self, msg, &mut *digest, &mut *mgf_digest, label),
_ => Err(Error::InvalidPaddingScheme),
}
padding.encrypt(rng, self, msg)
}

fn verify(&self, padding: PaddingScheme, hashed: &[u8], sig: &[u8]) -> Result<()> {
match padding {
PaddingScheme::PKCS1v15Sign { hash_len, prefix } => {
if let Some(hash_len) = hash_len {
if hashed.len() != hash_len {
return Err(Error::InputNotHashed);
}
}
pkcs1v15::verify(self, prefix.as_ref(), hashed, sig)
}
PaddingScheme::PSS { mut digest, .. } => pss::verify(self, hashed, sig, &mut *digest),
_ => Err(Error::InvalidPaddingScheme),
}
fn verify(&self, padding: impl SignatureScheme, hashed: &[u8], sig: &[u8]) -> Result<()> {
padding.verify(self, hashed, sig)
}
}

Expand Down Expand Up @@ -448,113 +430,37 @@ impl RsaPrivateKey {
}

/// Decrypt the given message.
pub fn decrypt(&self, padding: PaddingScheme, ciphertext: &[u8]) -> Result<Vec<u8>> {
match padding {
// need to pass any Rng as the type arg, so the type checker is happy, it is not actually used for anything
PaddingScheme::PKCS1v15Encrypt => {
pkcs1v15::decrypt::<DummyRng, _>(None, self, ciphertext)
}
PaddingScheme::OAEP {
mut digest,
mut mgf_digest,
label,
} => oaep::decrypt::<DummyRng, _>(
None,
self,
ciphertext,
&mut *digest,
&mut *mgf_digest,
label,
),
_ => Err(Error::InvalidPaddingScheme),
}
pub fn decrypt(&self, padding: impl PaddingScheme, ciphertext: &[u8]) -> Result<Vec<u8>> {
padding.decrypt(Option::<&mut DummyRng>::None, self, ciphertext)
}

/// Decrypt the given message.
///
/// Uses `rng` to blind the decryption process.
pub fn decrypt_blinded<R: CryptoRngCore>(
pub fn decrypt_blinded(
&self,
rng: &mut R,
padding: PaddingScheme,
rng: &mut impl CryptoRngCore,
padding: impl PaddingScheme,
ciphertext: &[u8],
) -> Result<Vec<u8>> {
match padding {
PaddingScheme::PKCS1v15Encrypt => pkcs1v15::decrypt(Some(rng), self, ciphertext),
PaddingScheme::OAEP {
mut digest,
mut mgf_digest,
label,
} => oaep::decrypt(
Some(rng),
self,
ciphertext,
&mut *digest,
&mut *mgf_digest,
label,
),
_ => Err(Error::InvalidPaddingScheme),
}
padding.decrypt(Some(rng), self, ciphertext)
}

/// Sign the given digest.
pub fn sign(&self, padding: PaddingScheme, digest_in: &[u8]) -> Result<Vec<u8>> {
match padding {
// need to pass any Rng as the type arg, so the type checker is happy, it is not actually used for anything
PaddingScheme::PKCS1v15Sign { hash_len, prefix } => {
if let Some(hash_len) = hash_len {
if digest_in.len() != hash_len {
return Err(Error::InputNotHashed);
}
}
pkcs1v15::sign::<DummyRng, _>(None, self, prefix.as_ref(), digest_in)
}
_ => Err(Error::InvalidPaddingScheme),
}
pub fn sign(&self, padding: impl SignatureScheme, digest_in: &[u8]) -> Result<Vec<u8>> {
padding.sign(Option::<&mut DummyRng>::None, self, digest_in)
}

/// Sign the given digest using the provided rng
///
/// Use `rng` for signature process.
pub fn sign_with_rng<R: CryptoRngCore>(
&self,
rng: &mut R,
padding: PaddingScheme,
digest_in: &[u8],
) -> Result<Vec<u8>> {
match padding {
PaddingScheme::PSS {
mut digest,
salt_len,
} => pss::sign::<R, _>(rng, false, self, digest_in, salt_len, &mut *digest),
_ => Err(Error::InvalidPaddingScheme),
}
}

/// Sign the given digest.
///
/// Use `rng` for blinding.
pub fn sign_blinded<R: CryptoRngCore>(
pub fn sign_with_rng(
&self,
rng: &mut R,
padding: PaddingScheme,
rng: &mut impl CryptoRngCore,
padding: impl SignatureScheme,
digest_in: &[u8],
) -> Result<Vec<u8>> {
match padding {
PaddingScheme::PKCS1v15Sign { hash_len, prefix } => {
if let Some(hash_len) = hash_len {
if digest_in.len() != hash_len {
return Err(Error::InputNotHashed);
}
}
pkcs1v15::sign(Some(rng), self, prefix.as_ref(), digest_in)
}
PaddingScheme::PSS {
mut digest,
salt_len,
} => pss::sign::<R, _>(rng, true, self, digest_in, salt_len, &mut *digest),
_ => Err(Error::InvalidPaddingScheme),
}
padding.sign(Some(rng), self, digest_in)
}
}

Expand Down Expand Up @@ -591,6 +497,7 @@ fn check_public_with_max_size(public_key: &impl PublicKeyParts, max_size: usize)
mod tests {
use super::*;
use crate::internals;
use crate::oaep::Oaep;

use alloc::string::String;
use digest::{Digest, DynDigest};
Expand Down Expand Up @@ -965,20 +872,20 @@ mod tests {
let pub_key: RsaPublicKey = prk.into();

let ciphertext = if let Some(ref label) = label {
let padding = PaddingScheme::new_oaep_with_label::<D, _>(label);
let padding = Oaep::new_with_label::<D, _>(label);
pub_key.encrypt(&mut rng, padding, &input).unwrap()
} else {
let padding = PaddingScheme::new_oaep::<D>();
let padding = Oaep::new::<D>();
pub_key.encrypt(&mut rng, padding, &input).unwrap()
};

assert_ne!(input, ciphertext);
let blind: bool = rng.next_u32() < (1 << 31);

let padding = if let Some(ref label) = label {
PaddingScheme::new_oaep_with_label::<D, _>(label)
Oaep::new_with_label::<D, _>(label)
} else {
PaddingScheme::new_oaep::<D>()
Oaep::new::<D>()
};

let plaintext = if blind {
Expand Down Expand Up @@ -1013,20 +920,20 @@ mod tests {
let pub_key: RsaPublicKey = prk.into();

let ciphertext = if let Some(ref label) = label {
let padding = PaddingScheme::new_oaep_with_mgf_hash_with_label::<D, U, _>(label);
let padding = Oaep::new_with_mgf_hash_and_label::<D, U, _>(label);
pub_key.encrypt(&mut rng, padding, &input).unwrap()
} else {
let padding = PaddingScheme::new_oaep_with_mgf_hash::<D, U>();
let padding = Oaep::new_with_mgf_hash::<D, U>();
pub_key.encrypt(&mut rng, padding, &input).unwrap()
};

assert_ne!(input, ciphertext);
let blind: bool = rng.next_u32() < (1 << 31);

let padding = if let Some(ref label) = label {
PaddingScheme::new_oaep_with_mgf_hash_with_label::<D, U, _>(label)
Oaep::new_with_mgf_hash_and_label::<D, U, _>(label)
} else {
PaddingScheme::new_oaep_with_mgf_hash::<D, U>()
Oaep::new_with_mgf_hash::<D, U>()
};

let plaintext = if blind {
Expand All @@ -1044,17 +951,13 @@ mod tests {
let priv_key = get_private_key();
let pub_key: RsaPublicKey = (&priv_key).into();
let ciphertext = pub_key
.encrypt(
&mut rng,
PaddingScheme::new_oaep::<Sha1>(),
"a_plain_text".as_bytes(),
)
.encrypt(&mut rng, Oaep::new::<Sha1>(), "a_plain_text".as_bytes())
.unwrap();
assert!(
priv_key
.decrypt_blinded(
&mut rng,
PaddingScheme::new_oaep_with_label::<Sha1, _>("label"),
Oaep::new_with_label::<Sha1, _>("label"),
&ciphertext,
)
.is_err(),
Expand Down
23 changes: 13 additions & 10 deletions src/lib.rs
Expand Up @@ -13,7 +13,7 @@
//!
//! ## PKCS#1 v1.5 encryption
//! ```
//! use rsa::{PublicKey, RsaPrivateKey, RsaPublicKey, PaddingScheme};
//! use rsa::{PublicKey, RsaPrivateKey, RsaPublicKey, Pkcs1v15Encrypt};
//!
//! let mut rng = rand::thread_rng();
//!
Expand All @@ -23,19 +23,17 @@
//!
//! // Encrypt
//! let data = b"hello world";
//! let padding = PaddingScheme::new_pkcs1v15_encrypt();
//! let enc_data = public_key.encrypt(&mut rng, padding, &data[..]).expect("failed to encrypt");
//! let enc_data = public_key.encrypt(&mut rng, Pkcs1v15Encrypt, &data[..]).expect("failed to encrypt");
//! assert_ne!(&data[..], &enc_data[..]);
//!
//! // Decrypt
//! let padding = PaddingScheme::new_pkcs1v15_encrypt();
//! let dec_data = private_key.decrypt(padding, &enc_data).expect("failed to decrypt");
//! let dec_data = private_key.decrypt(Pkcs1v15Encrypt, &enc_data).expect("failed to decrypt");
//! assert_eq!(&data[..], &dec_data[..]);
//! ```
//!
//! ## OAEP encryption
//! ```
//! use rsa::{PublicKey, RsaPrivateKey, RsaPublicKey, PaddingScheme};
//! use rsa::{PublicKey, RsaPrivateKey, RsaPublicKey, Oaep};
//!
//! let mut rng = rand::thread_rng();
//!
Expand All @@ -45,12 +43,12 @@
//!
//! // Encrypt
//! let data = b"hello world";
//! let padding = PaddingScheme::new_oaep::<sha2::Sha256>();
//! let padding = Oaep::new::<sha2::Sha256>();
//! let enc_data = public_key.encrypt(&mut rng, padding, &data[..]).expect("failed to encrypt");
//! assert_ne!(&data[..], &enc_data[..]);
//!
//! // Decrypt
//! let padding = PaddingScheme::new_oaep::<sha2::Sha256>();
//! let padding = Oaep::new::<sha2::Sha256>();
//! let dec_data = private_key.decrypt(padding, &enc_data).expect("failed to decrypt");
//! assert_eq!(&data[..], &dec_data[..]);
//! ```
Expand Down Expand Up @@ -227,8 +225,13 @@ mod raw;
pub use pkcs1;
pub use pkcs8;

pub use self::key::{PublicKey, PublicKeyParts, RsaPrivateKey, RsaPublicKey};
pub use self::padding::PaddingScheme;
pub use crate::{
key::{PublicKey, PublicKeyParts, RsaPrivateKey, RsaPublicKey},
oaep::Oaep,
padding::{PaddingScheme, SignatureScheme},
pkcs1v15::{Pkcs1v15Encrypt, Pkcs1v15Sign},
pss::Pss,
};

/// Internal raw RSA functions.
#[cfg(not(feature = "expose-internals"))]
Expand Down

0 comments on commit ef9650b

Please sign in to comment.