Introduce raw::{DecryptionPrimitive, EncryptionPrimitive}

This commit is contained in:
Jack Grigg 2020-01-02 21:51:43 -05:00 committed by dignifiedquire
parent d26bb6a057
commit 826ea30004
4 changed files with 96 additions and 54 deletions

View File

@ -12,6 +12,7 @@ use crate::errors::{Error, Result};
use crate::hash::Hash; use crate::hash::Hash;
use crate::padding::PaddingScheme; use crate::padding::PaddingScheme;
use crate::pkcs1v15; use crate::pkcs1v15;
use crate::raw::EncryptionPrimitive;
lazy_static! { lazy_static! {
static ref MIN_PUB_EXPONENT: BigUint = BigUint::from_u64(2).unwrap(); static ref MIN_PUB_EXPONENT: BigUint = BigUint::from_u64(2).unwrap();
@ -126,7 +127,7 @@ impl From<RSAPrivateKey> for RSAPublicKey {
} }
/// Generic trait for operations on a public key. /// Generic trait for operations on a public key.
pub trait PublicKey { pub trait PublicKey: EncryptionPrimitive {
/// Returns the modulus of the key. /// Returns the modulus of the key.
fn n(&self) -> &BigUint; fn n(&self) -> &BigUint;
/// Returns the public exponent of the key. /// Returns the public exponent of the key.

View File

@ -58,12 +58,13 @@ pub mod hash;
/// Supported padding schemes. /// Supported padding schemes.
pub mod padding; pub mod padding;
#[cfg(feature="pem")] #[cfg(feature = "pem")]
pub use pem; pub use pem;
mod key; mod key;
mod pkcs1v15;
mod parse; mod parse;
mod pkcs1v15;
mod raw;
pub use self::key::{PublicKey, RSAPrivateKey, RSAPublicKey}; pub use self::key::{PublicKey, RSAPrivateKey, RSAPublicKey};
pub use self::padding::PaddingScheme; pub use self::padding::PaddingScheme;

View File

@ -1,12 +1,10 @@
use num_bigint::BigUint;
use rand::Rng; use rand::Rng;
use subtle::{Choice, ConditionallySelectable, ConstantTimeEq}; use subtle::{Choice, ConditionallySelectable, ConstantTimeEq};
use zeroize::Zeroize;
use crate::errors::{Error, Result}; use crate::errors::{Error, Result};
use crate::hash::Hash; use crate::hash::Hash;
use crate::internals;
use crate::key::{self, PublicKey, RSAPrivateKey}; use crate::key::{self, PublicKey, RSAPrivateKey};
use crate::raw::DecryptionPrimitive;
// Encrypts the given message with RSA and the padding // Encrypts the given message with RSA and the padding
// scheme from PKCS#1 v1.5. The message must be no longer than the // scheme from PKCS#1 v1.5. The message must be no longer than the
@ -27,17 +25,7 @@ pub fn encrypt<R: Rng, K: PublicKey>(rng: &mut R, pub_key: &K, msg: &[u8]) -> Re
em[k - msg.len() - 1] = 0; em[k - msg.len() - 1] = 0;
em[k - msg.len()..].copy_from_slice(msg); em[k - msg.len()..].copy_from_slice(msg);
{ pub_key.raw_encryption_primitive(&em)
let mut m = BigUint::from_bytes_be(&em);
let mut c = internals::encrypt(pub_key, &m).to_bytes_be();
copy_with_left_pad(&mut em, &c);
// clear out tmp values
m.zeroize();
c.zeroize();
}
Ok(em)
} }
/// Decrypts a plaintext using RSA and the padding scheme from PKCS#1 v1.5. /// Decrypts a plaintext using RSA and the padding scheme from PKCS#1 v1.5.
@ -100,18 +88,7 @@ pub fn sign<R: Rng, H: Hash>(
em[k - t_len..k - hash_len].copy_from_slice(&prefix); em[k - t_len..k - hash_len].copy_from_slice(&prefix);
em[k - hash_len..k].copy_from_slice(hashed); em[k - hash_len..k].copy_from_slice(hashed);
{ priv_key.raw_decryption_primitive(rng, &em)
let mut m = BigUint::from_bytes_be(&em);
let mut c = internals::decrypt_and_check(rng, priv_key, &m)?.to_bytes_be();
copy_with_left_pad(&mut em, &c);
// clear tmp values
m.zeroize();
c.zeroize();
}
Ok(em)
} }
/// Verifies an RSA PKCS#1 v1.5 signature. /// Verifies an RSA PKCS#1 v1.5 signature.
@ -130,11 +107,7 @@ pub fn verify<H: Hash, K: PublicKey>(
return Err(Error::Verification); return Err(Error::Verification);
} }
let em = { let em = pub_key.raw_encryption_primitive(sig)?;
let c = BigUint::from_bytes_be(sig);
let m = internals::encrypt(pub_key, &c).to_bytes_be();
internals::left_pad(&m, k)
};
// EM = 0x00 || 0x01 || PS || 0x00 || T // EM = 0x00 || 0x01 || PS || 0x00 || T
let mut ok = em[0].ct_eq(&0u8); let mut ok = em[0].ct_eq(&0u8);
@ -170,16 +143,6 @@ fn hash_info<H: Hash>(hash: Option<&H>, digest_len: usize) -> Result<(usize, Vec
} }
} }
#[inline]
fn copy_with_left_pad(dest: &mut [u8], src: &[u8]) {
// left pad with zeros
let padding_bytes = dest.len() - src.len();
for el in dest.iter_mut().take(padding_bytes) {
*el = 0;
}
dest[padding_bytes..].copy_from_slice(src);
}
/// Decrypts ciphertext using `priv_key` and blinds the operation if /// Decrypts ciphertext using `priv_key` and blinds the operation if
/// `rng` is given. It returns one or zero in valid that indicates whether the /// `rng` is given. It returns one or zero in valid that indicates whether the
/// plaintext was correctly structured. In either case, the plaintext is /// plaintext was correctly structured. In either case, the plaintext is
@ -197,16 +160,7 @@ fn decrypt_inner<R: Rng>(
return Err(Error::Decryption); return Err(Error::Decryption);
} }
let em = { let em = priv_key.raw_decryption_primitive(rng, ciphertext)?;
let mut c = BigUint::from_bytes_be(ciphertext);
let mut m = internals::decrypt(rng, priv_key, &c)?;
let em = internals::left_pad(&m.to_bytes_be(), k);
c.zeroize();
m.zeroize();
em
};
let first_byte_is_zero = em[0].ct_eq(&0u8); let first_byte_is_zero = em[0].ct_eq(&0u8);
let second_byte_is_two = em[1].ct_eq(&2u8); let second_byte_is_two = em[1].ct_eq(&2u8);
@ -259,6 +213,7 @@ mod tests {
use super::*; use super::*;
use base64; use base64;
use hex; use hex;
use num_bigint::BigUint;
use num_traits::FromPrimitive; use num_traits::FromPrimitive;
use num_traits::Num; use num_traits::Num;
use rand::thread_rng; use rand::thread_rng;

85
src/raw.rs Normal file
View File

@ -0,0 +1,85 @@
use num_bigint::BigUint;
use rand::Rng;
use zeroize::Zeroize;
use crate::errors::Result;
use crate::internals;
use crate::key::{PublicKey, RSAPrivateKey, RSAPublicKey};
pub trait EncryptionPrimitive {
/// Do NOT use directly! Only for implementors.
fn raw_encryption_primitive(&self, plaintext: &[u8]) -> Result<Vec<u8>>;
}
pub trait DecryptionPrimitive {
/// Do NOT use directly! Only for implementors.
fn raw_decryption_primitive<R: Rng>(
&self,
rng: Option<&mut R>,
ciphertext: &[u8],
) -> Result<Vec<u8>>;
}
impl EncryptionPrimitive for RSAPublicKey {
fn raw_encryption_primitive(&self, plaintext: &[u8]) -> Result<Vec<u8>> {
let mut m = BigUint::from_bytes_be(plaintext);
let mut c = internals::encrypt(self, &m);
let mut c_bytes = c.to_bytes_be();
let ciphertext = internals::left_pad(&c_bytes, self.size());
// clear out tmp values
m.zeroize();
c.zeroize();
c_bytes.zeroize();
Ok(ciphertext)
}
}
impl<'a> EncryptionPrimitive for &'a RSAPublicKey {
fn raw_encryption_primitive(&self, plaintext: &[u8]) -> Result<Vec<u8>> {
(*self).raw_encryption_primitive(plaintext)
}
}
impl EncryptionPrimitive for RSAPrivateKey {
fn raw_encryption_primitive(&self, plaintext: &[u8]) -> Result<Vec<u8>> {
let mut m = BigUint::from_bytes_be(plaintext);
let mut c = internals::encrypt(self, &m);
let mut c_bytes = c.to_bytes_be();
let ciphertext = internals::left_pad(&c_bytes, self.size());
// clear out tmp values
m.zeroize();
c.zeroize();
c_bytes.zeroize();
Ok(ciphertext)
}
}
impl<'a> EncryptionPrimitive for &'a RSAPrivateKey {
fn raw_encryption_primitive(&self, plaintext: &[u8]) -> Result<Vec<u8>> {
(*self).raw_encryption_primitive(plaintext)
}
}
impl DecryptionPrimitive for RSAPrivateKey {
fn raw_decryption_primitive<R: Rng>(
&self,
rng: Option<&mut R>,
ciphertext: &[u8],
) -> Result<Vec<u8>> {
let mut c = BigUint::from_bytes_be(ciphertext);
let mut m = internals::decrypt_and_check(rng, self, &c)?;
let mut m_bytes = m.to_bytes_be();
let plaintext = internals::left_pad(&m_bytes, self.size());
// clear tmp values
c.zeroize();
m.zeroize();
m_bytes.zeroize();
Ok(plaintext)
}
}