Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
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
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