Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove padding using new encryption API #246

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions benches/key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ use num_bigint::BigUint;
use num_traits::{FromPrimitive, Num};
use rand_chacha::{rand_core::SeedableRng, ChaCha8Rng};
use rsa::signature::RandomizedSigner;
use rsa::{PaddingScheme, RsaPrivateKey};
use rsa::traits::Decryptor;
use rsa::RsaPrivateKey;
use sha2::{Digest, Sha256};
use test::Bencher;

Expand All @@ -29,12 +30,11 @@ fn get_key() -> RsaPrivateKey {
#[bench]
fn bench_rsa_2048_pkcsv1_decrypt(b: &mut Bencher) {
let priv_key = get_key();
let decryption_key = rsa::pkcs1v15::DecryptingKey::new(priv_key);
let x = Base64::decode_vec(DECRYPT_VAL).unwrap();

b.iter(|| {
let res = priv_key
.decrypt(PaddingScheme::new_pkcs1v15_encrypt(), &x)
.unwrap();
let res = decryption_key.decrypt(&x).unwrap();
test::black_box(res);
});
}
Expand Down
173 changes: 27 additions & 146 deletions src/key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,9 @@ use serde_crate::{Deserialize, Serialize};
use zeroize::Zeroize;

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::padding::PaddingScheme;
use crate::raw::{DecryptionPrimitive, EncryptionPrimitive};
use crate::{oaep, pkcs1v15};

/// Components of an RSA public key.
pub trait PublicKeyParts {
Expand Down Expand Up @@ -171,15 +168,7 @@ 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>(
&self,
rng: &mut R,
padding: PaddingScheme,
msg: &[u8],
) -> Result<Vec<u8>>;
}
pub trait PublicKey: EncryptionPrimitive + PublicKeyParts {}

impl PublicKeyParts for RsaPublicKey {
fn n(&self) -> &BigUint {
Expand All @@ -191,23 +180,7 @@ impl PublicKeyParts for RsaPublicKey {
}
}

impl PublicKey for RsaPublicKey {
fn encrypt<R: CryptoRngCore>(
&self,
rng: &mut R,
padding: 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),
}
}
}
impl PublicKey for RsaPublicKey {}

impl RsaPublicKey {
/// Minimum value of the public exponent `e`.
Expand Down Expand Up @@ -424,54 +397,6 @@ impl RsaPrivateKey {

Ok(())
}

/// 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,
),
}
}

/// Decrypt the given message.
///
/// Uses `rng` to blind the decryption process.
pub fn decrypt_blinded<R: CryptoRngCore>(
&self,
rng: &mut R,
padding: 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,
),
}
}
}

/// Check that the public key is well formed and has an exponent within acceptable bounds.
Expand Down Expand Up @@ -507,9 +432,11 @@ fn check_public_with_max_size(public_key: &impl PublicKeyParts, max_size: usize)
mod tests {
use super::*;
use crate::internals;
use crate::oaep::{DecryptingKey, EncryptingKey};
use crate::traits::{Decryptor, RandomizedDecryptor, RandomizedEncryptor};

use alloc::string::String;
use digest::{Digest, DynDigest};
use digest::{Digest, FixedOutputReset};
use hex_literal::hex;
use num_traits::{FromPrimitive, ToPrimitive};
use rand_chacha::{
Expand Down Expand Up @@ -862,55 +789,11 @@ mod tests {
}
}

fn do_test_encrypt_decrypt_oaep<D: 'static + Digest + DynDigest + Send + Sync>(
prk: &RsaPrivateKey,
) {
let mut rng = ChaCha8Rng::from_seed([42; 32]);

let k = prk.size();

for i in 1..8 {
let mut input = vec![0u8; i * 8];
rng.fill_bytes(&mut input);

if input.len() > k - 11 {
input = input[0..k - 11].to_vec();
}
let label = get_label(&mut rng);

let pub_key: RsaPublicKey = prk.into();

let ciphertext = if let Some(ref label) = label {
let padding = PaddingScheme::new_oaep_with_label::<D, _>(label);
pub_key.encrypt(&mut rng, padding, &input).unwrap()
} else {
let padding = PaddingScheme::new_oaep::<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)
} else {
PaddingScheme::new_oaep::<D>()
};

let plaintext = if blind {
prk.decrypt(padding, &ciphertext).unwrap()
} else {
prk.decrypt_blinded(&mut rng, padding, &ciphertext).unwrap()
};

assert_eq!(input, plaintext);
}
fn do_test_encrypt_decrypt_oaep<D: Digest + FixedOutputReset>(prk: &RsaPrivateKey) {
do_test_oaep_with_different_hashes::<D, D>(prk);
}

fn do_test_oaep_with_different_hashes<
D: 'static + Digest + DynDigest + Send + Sync,
U: 'static + Digest + DynDigest + Send + Sync,
>(
fn do_test_oaep_with_different_hashes<D: Digest, MGD: Digest + FixedOutputReset>(
prk: &RsaPrivateKey,
) {
let mut rng = ChaCha8Rng::from_seed([42; 32]);
Expand All @@ -929,50 +812,48 @@ 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);
pub_key.encrypt(&mut rng, padding, &input).unwrap()
let encrypting_key =
EncryptingKey::<D, MGD>::new_with_label(pub_key, label.clone());
encrypting_key.encrypt_with_rng(&mut rng, &input).unwrap()
} else {
let padding = PaddingScheme::new_oaep_with_mgf_hash::<D, U>();
pub_key.encrypt(&mut rng, padding, &input).unwrap()
let encrypting_key = EncryptingKey::<D, MGD>::new(pub_key);
encrypting_key.encrypt_with_rng(&mut rng, &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)
let decrypting_key = if let Some(ref label) = label {
DecryptingKey::<D, MGD>::new_with_label(prk.clone(), label.clone())
} else {
PaddingScheme::new_oaep_with_mgf_hash::<D, U>()
DecryptingKey::<D, MGD>::new(prk.clone())
};

let plaintext = if blind {
prk.decrypt(padding, &ciphertext).unwrap()
decrypting_key.decrypt(&ciphertext).unwrap()
} else {
prk.decrypt_blinded(&mut rng, padding, &ciphertext).unwrap()
decrypting_key
.decrypt_with_rng(&mut rng, &ciphertext)
.unwrap()
};

assert_eq!(input, plaintext);
}
}

#[test]
fn test_decrypt_oaep_invalid_hash() {
let mut rng = ChaCha8Rng::from_seed([42; 32]);
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(),
)
let encrypting_key = EncryptingKey::<Sha1>::new(pub_key);
let decrypting_key = DecryptingKey::<Sha1>::new_with_label(priv_key, "label");
let ciphertext = encrypting_key
.encrypt_with_rng(&mut rng, "a_plain_text".as_bytes())
.unwrap();
assert!(
priv_key
.decrypt_blinded(
&mut rng,
PaddingScheme::new_oaep_with_label::<Sha1, _>("label"),
&ciphertext,
)
decrypting_key
.decrypt_with_rng(&mut rng, &ciphertext,)
.is_err(),
"decrypt should have failed on hash verification"
);
Expand Down
26 changes: 15 additions & 11 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@
//!
//! ## PKCS#1 v1.5 encryption
//! ```
//! use rsa::{PublicKey, RsaPrivateKey, RsaPublicKey, PaddingScheme};
//! use rsa::{RsaPrivateKey, RsaPublicKey};
//! use rsa::pkcs1v15::{DecryptingKey, EncryptingKey};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

EncryptingKey reads quite odd, I would have expected it to be called EncryptionKey

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ack

//! use rsa::traits::{RandomizedEncryptor, Decryptor};
//!
//! let mut rng = rand::thread_rng();
//!
Expand All @@ -23,35 +25,37 @@
//!
//! // 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 encrypting_key = EncryptingKey::new(public_key);
//! let enc_data = encrypting_key.encrypt_with_rng(&mut rng, &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 decrypting_key = DecryptingKey::new(private_key);
//! let dec_data = decrypting_key.decrypt(&enc_data).expect("failed to decrypt");
//! assert_eq!(&data[..], &dec_data[..]);
//! ```
//!
//! ## OAEP encryption
//! ```
//! use rsa::{PublicKey, RsaPrivateKey, RsaPublicKey, PaddingScheme};
//! use rsa::{PublicKey, RsaPrivateKey, RsaPublicKey};
//! use rsa::oaep::{DecryptingKey, EncryptingKey};
//! use rsa::traits::{RandomizedEncryptor, Decryptor};
//!
//! let mut rng = rand::thread_rng();
//!
//! let bits = 2048;
//! let private_key = RsaPrivateKey::new(&mut rng, bits).expect("failed to generate a key");
//! let public_key = RsaPublicKey::from(&private_key);
//! let encrypting_key = EncryptingKey::<sha2::Sha256>::new(public_key);
//! let decrypting_key = DecryptingKey::<sha2::Sha256>::new(private_key);
//!
//! // Encrypt
//! let data = b"hello world";
//! let padding = PaddingScheme::new_oaep::<sha2::Sha256>();
//! let enc_data = public_key.encrypt(&mut rng, padding, &data[..]).expect("failed to encrypt");
//! let enc_data = encrypting_key.encrypt_with_rng(&mut rng, &data[..]).expect("failed to encrypt");
//! assert_ne!(&data[..], &enc_data[..]);
//!
//! // Decrypt
//! let padding = PaddingScheme::new_oaep::<sha2::Sha256>();
//! let dec_data = private_key.decrypt(padding, &enc_data).expect("failed to decrypt");
//! let dec_data = decrypting_key.decrypt(&enc_data).expect("failed to decrypt");
//! assert_eq!(&data[..], &dec_data[..]);
//! ```
//!
Expand Down Expand Up @@ -214,14 +218,14 @@ pub use signature;

pub mod algorithms;
pub mod errors;
pub mod oaep;
pub mod pkcs1v15;
pub mod pss;
pub mod traits;

mod dummy_rng;
mod encoding;
mod key;
mod oaep;
mod padding;
mod raw;

Expand Down
Loading